mirror of https://github.com/doitsujin/dxvk
Compare commits
69 Commits
Author | SHA1 | Date |
---|---|---|
Tiagoquix | 79eea564fb | |
Robin Kertels | 7df8017e46 | |
WinterSnowfall | c98152683f | |
Blisto91 | 890ad3f47f | |
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 |
|
@ -9,13 +9,13 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
id: checkout-code
|
id: checkout-code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup problem matcher
|
- name: Setup problem matcher
|
||||||
uses: Joshua-Ashton/gcc-problem-matcher@v2
|
uses: Joshua-Ashton/gcc-problem-matcher@v3
|
||||||
|
|
||||||
- name: Build release
|
- name: Build release
|
||||||
id: build-release
|
id: build-release
|
||||||
|
@ -28,9 +28,9 @@ jobs:
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
id: upload-artifacts
|
id: upload-artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dxvk-${{ env.VERSION_NAME }}
|
name: dxvk-win-${{ env.VERSION_NAME }}
|
||||||
path: build/dxvk-${{ env.VERSION_NAME }}
|
path: build/dxvk-${{ env.VERSION_NAME }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
@ -41,26 +41,43 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
id: checkout-code
|
id: checkout-code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup problem matcher
|
- name: Setup problem matcher
|
||||||
uses: Joshua-Ashton/gcc-problem-matcher@v2
|
uses: Joshua-Ashton/gcc-problem-matcher@v3
|
||||||
|
|
||||||
- name: Build release
|
- name: Build release
|
||||||
id: build-release
|
id: build-release
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}"
|
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
|
echo "VERSION_NAME=${VERSION_NAME}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
id: upload-artifacts
|
id: upload-artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dxvk-${{ env.VERSION_NAME }}
|
name: dxvk-native-${{ env.VERSION_NAME }}
|
||||||
path: build/dxvk-native-${{ env.VERSION_NAME }}
|
path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
merge-artifacts:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
needs: [artifacts-mingw-w64, artifacts-steamrt-sniper]
|
||||||
|
steps:
|
||||||
|
- name: Get version
|
||||||
|
id: get-version
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "VERSION_NAME=${GITHUB_REF##*/}-${GITHUB_SHA##*/}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Merge Artifacts
|
||||||
|
uses: actions/upload-artifact/merge@v4
|
||||||
|
with:
|
||||||
|
name: dxvk-${{ env.VERSION_NAME }}
|
||||||
|
pattern: dxvk*
|
||||||
|
delete-merged: true
|
||||||
|
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
id: checkout-code
|
id: checkout-code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
|
|
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
|
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
|
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.
|
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.
|
||||||
|
|
31
dxvk.conf
31
dxvk.conf
|
@ -312,6 +312,20 @@
|
||||||
# d3d11.exposeDriverCommandLists = True
|
# 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.
|
# Sets number of pipeline compiler threads.
|
||||||
#
|
#
|
||||||
# If the graphics pipeline library feature is enabled, the given
|
# If the graphics pipeline library feature is enabled, the given
|
||||||
|
@ -499,6 +513,7 @@
|
||||||
# Supported values:
|
# Supported values:
|
||||||
# - True/False
|
# - True/False
|
||||||
|
|
||||||
|
# d3d11.longMad = False
|
||||||
# d3d9.longMad = False
|
# d3d9.longMad = False
|
||||||
|
|
||||||
# Device Local Constant Buffers
|
# Device Local Constant Buffers
|
||||||
|
@ -514,7 +529,9 @@
|
||||||
|
|
||||||
# Support DF formats
|
# 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:
|
# Supported values:
|
||||||
# - True/False
|
# - True/False
|
||||||
|
@ -644,18 +661,6 @@
|
||||||
|
|
||||||
# d3d9.textureMemory = 100
|
# d3d9.textureMemory = 100
|
||||||
|
|
||||||
# Always enumerate all monitors on each dxgi output
|
|
||||||
#
|
|
||||||
# Used to avoid performance degradation in some games
|
|
||||||
# (will be deprecated once QueryDisplayConfig optimization
|
|
||||||
# is in Proton Wine).
|
|
||||||
#
|
|
||||||
# Supported values:
|
|
||||||
# - True/False
|
|
||||||
|
|
||||||
# dxgi.useMonitorFallback = False
|
|
||||||
|
|
||||||
|
|
||||||
# Hide integrated graphics from applications
|
# Hide integrated graphics from applications
|
||||||
#
|
#
|
||||||
# Only has an effect when dedicated GPUs are present on the system. It is
|
# Only has an effect when dedicated GPUs are present on the system. It is
|
||||||
|
|
|
@ -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',
|
||||||
|
)
|
|
@ -1,6 +1,6 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
@ -22,4 +22,4 @@ namespace dxvk::wsi {
|
||||||
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
32
meson.build
32
meson.build
|
@ -1,5 +1,6 @@
|
||||||
project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
|
project('dxvk', ['c', 'cpp'], version : '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()
|
cpu_family = target_machine.cpu_family()
|
||||||
platform = target_machine.system()
|
platform = target_machine.system()
|
||||||
fs = import('fs')
|
fs = import('fs')
|
||||||
|
@ -54,6 +55,8 @@ dep_displayinfo = dependency(
|
||||||
)
|
)
|
||||||
|
|
||||||
if platform == 'windows'
|
if platform == 'windows'
|
||||||
|
dxvk_so_version = {'name_prefix': ''}
|
||||||
|
|
||||||
compiler_args += [
|
compiler_args += [
|
||||||
'-DNOMINMAX',
|
'-DNOMINMAX',
|
||||||
'-D_WIN32_WINNT=0xa00',
|
'-D_WIN32_WINNT=0xa00',
|
||||||
|
@ -115,10 +118,13 @@ if platform == 'windows'
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
dxvk_wsi = 'win32'
|
|
||||||
dxvk_name_prefix = ''
|
dxvk_name_prefix = ''
|
||||||
compiler_args += ['-DDXVK_WSI_WIN32']
|
compiler_args += ['-DDXVK_WSI_WIN32']
|
||||||
else
|
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 = find_program('touch')
|
||||||
wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] )
|
wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] )
|
||||||
|
|
||||||
|
@ -128,17 +134,20 @@ else
|
||||||
'./include/native/directx'
|
'./include/native/directx'
|
||||||
]
|
]
|
||||||
|
|
||||||
dxvk_wsi = get_option('dxvk_native_wsi')
|
lib_sdl2 = dependency('SDL2', required: false)
|
||||||
|
lib_glfw = dependency('glfw', required: false)
|
||||||
if dxvk_wsi == 'sdl2'
|
if lib_sdl2.found()
|
||||||
lib_sdl2 = cpp.find_library('SDL2')
|
|
||||||
compiler_args += ['-DDXVK_WSI_SDL2']
|
compiler_args += ['-DDXVK_WSI_SDL2']
|
||||||
elif dxvk_wsi == 'glfw'
|
endif
|
||||||
lib_glfw = cpp.find_library('glfw')
|
if lib_glfw.found()
|
||||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||||
endif
|
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 += [
|
link_args += [
|
||||||
'-static-libgcc',
|
'-static-libgcc',
|
||||||
|
@ -154,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')
|
add_project_link_arguments(cc.get_supported_link_arguments(link_args), language: 'c')
|
||||||
|
|
||||||
exe_ext = ''
|
exe_ext = ''
|
||||||
dll_ext = ''
|
|
||||||
def_spec_ext = '.def'
|
def_spec_ext = '.def'
|
||||||
|
|
||||||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||||
glsl_args = [
|
glsl_args = [
|
||||||
'--quiet',
|
'--quiet',
|
||||||
'--target-env', 'vulkan1.2',
|
'--target-env', 'vulkan1.3',
|
||||||
'--vn', '@BASENAME@',
|
'--vn', '@BASENAME@',
|
||||||
'--depfile', '@DEPFILE@',
|
'--depfile', '@DEPFILE@',
|
||||||
'@INPUT@',
|
'@INPUT@',
|
||||||
|
@ -179,4 +187,8 @@ dxvk_version = vcs_tag(
|
||||||
output: 'version.h',
|
output: 'version.h',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if platform != 'windows'
|
||||||
|
subdir('include/native')
|
||||||
|
endif
|
||||||
|
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
|
|
@ -15,16 +15,23 @@ else
|
||||||
d3d10_d3d11_dep = d3d11_dep
|
d3d10_d3d11_dep = d3d11_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_res,
|
d3d10_core_dll = shared_library(dxvk_name_prefix+'d3d10core', d3d10_core_src, d3d10_core_res,
|
||||||
name_prefix : dxvk_name_prefix,
|
|
||||||
dependencies : [ d3d10_d3d11_dep ],
|
dependencies : [ d3d10_d3d11_dep ],
|
||||||
include_directories : dxvk_include_path,
|
include_directories : dxvk_include_path,
|
||||||
install : true,
|
install : true,
|
||||||
vs_module_defs : 'd3d10core'+def_spec_ext,
|
vs_module_defs : 'd3d10core'+def_spec_ext,
|
||||||
link_args : d3d10_core_ld_args,
|
link_args : d3d10_core_ld_args,
|
||||||
link_depends : [ d3d10_core_link_depends ],
|
link_depends : [ d3d10_core_link_depends ],
|
||||||
|
kwargs : dxvk_so_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
d3d10_core_dep = declare_dependency(
|
d3d10_core_dep = declare_dependency(
|
||||||
link_with : [ d3d10_core_dll ],
|
link_with : [ d3d10_core_dll ],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if platform != 'windows'
|
||||||
|
pkg.generate(d3d10_core_dll,
|
||||||
|
filebase: dxvk_pkg_prefix + 'd3d10core',
|
||||||
|
subdirs: 'dxvk',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace dxvk {
|
||||||
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
|
m_csThread(Device, Device->createContext(DxvkContextType::Primary)),
|
||||||
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
m_maxImplicitDiscardSize(pParent->GetOptions()->maxImplicitDiscardSize),
|
||||||
m_submissionFence(new sync::CallbackFence()),
|
m_submissionFence(new sync::CallbackFence()),
|
||||||
|
m_flushTracker(pParent->GetOptions()->reproducibleCommandStream),
|
||||||
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
m_multithread(this, false, pParent->GetOptions()->enableContextLock),
|
||||||
m_videoContext(this, Device) {
|
m_videoContext(this, Device) {
|
||||||
EmitCs([
|
EmitCs([
|
||||||
|
|
|
@ -32,6 +32,8 @@ namespace dxvk {
|
||||||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||||
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
||||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
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
|
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||||
|
|
|
@ -120,6 +120,14 @@ namespace dxvk {
|
||||||
|
|
||||||
/// Shader dump path
|
/// Shader dump path
|
||||||
std::string shaderDumpPath;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -58,9 +58,6 @@ namespace dxvk {
|
||||||
"\n MiscFlags: ", m_desc.MiscFlags,
|
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
"\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.shared = true;
|
||||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||||
|
|
|
@ -1262,12 +1262,28 @@ namespace dxvk {
|
||||||
viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
|
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 uboData = { };
|
||||||
uboData.colorMatrix[0][0] = 1.0f;
|
uboData.colorMatrix[0][0] = 1.0f;
|
||||||
uboData.colorMatrix[1][1] = 1.0f;
|
uboData.colorMatrix[1][1] = 1.0f;
|
||||||
uboData.colorMatrix[2][2] = 1.0f;
|
uboData.colorMatrix[2][2] = 1.0f;
|
||||||
uboData.coordMatrix[0][0] = 1.0f;
|
uboData.coordMatrix[0][0] = float(srcRect.extent.width) / float(viewExtent.width);
|
||||||
uboData.coordMatrix[1][1] = 1.0f;
|
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.yMin = 0.0f;
|
||||||
uboData.yMax = 1.0f;
|
uboData.yMax = 1.0f;
|
||||||
uboData.isPlanar = cViews[1] != nullptr;
|
uboData.isPlanar = cViews[1] != nullptr;
|
||||||
|
@ -1290,17 +1306,14 @@ namespace dxvk {
|
||||||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
||||||
|
|
||||||
ctx->bindUniformBuffer(VK_SHADER_STAGE_FRAGMENT_BIT, 0, DxvkBufferSlice(m_ubo));
|
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++)
|
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->draw(3, 1, 0, 0);
|
||||||
|
|
||||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
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() {
|
void D3D11VideoContext::CreateShaders() {
|
||||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
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_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, 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;
|
DxvkShaderCreateInfo vsInfo;
|
||||||
|
@ -1368,7 +1357,6 @@ namespace dxvk {
|
||||||
if (std::exchange(m_resourcesCreated, true))
|
if (std::exchange(m_resourcesCreated, true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CreateSampler();
|
|
||||||
CreateUniformBuffer();
|
CreateUniformBuffer();
|
||||||
CreateShaders();
|
CreateShaders();
|
||||||
}
|
}
|
||||||
|
|
|
@ -584,6 +584,7 @@ namespace dxvk {
|
||||||
struct alignas(16) UboData {
|
struct alignas(16) UboData {
|
||||||
float colorMatrix[3][4];
|
float colorMatrix[3][4];
|
||||||
float coordMatrix[3][2];
|
float coordMatrix[3][2];
|
||||||
|
VkRect2D srcRect;
|
||||||
float yMin, yMax;
|
float yMin, yMax;
|
||||||
VkBool32 isPlanar;
|
VkBool32 isPlanar;
|
||||||
};
|
};
|
||||||
|
@ -593,7 +594,6 @@ namespace dxvk {
|
||||||
Rc<DxvkDevice> m_device;
|
Rc<DxvkDevice> m_device;
|
||||||
Rc<DxvkShader> m_vs;
|
Rc<DxvkShader> m_vs;
|
||||||
Rc<DxvkShader> m_fs;
|
Rc<DxvkShader> m_fs;
|
||||||
Rc<DxvkSampler> m_sampler;
|
|
||||||
Rc<DxvkBuffer> m_ubo;
|
Rc<DxvkBuffer> m_ubo;
|
||||||
|
|
||||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||||
|
@ -613,8 +613,6 @@ namespace dxvk {
|
||||||
|
|
||||||
void CreateUniformBuffer();
|
void CreateUniformBuffer();
|
||||||
|
|
||||||
void CreateSampler();
|
|
||||||
|
|
||||||
void CreateShaders();
|
void CreateShaders();
|
||||||
|
|
||||||
void CreateResources();
|
void CreateResources();
|
||||||
|
|
|
@ -77,18 +77,25 @@ else
|
||||||
d3d11_dxgi_dep = dxgi_dep
|
d3d11_dxgi_dep = dxgi_dep
|
||||||
endif
|
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,
|
glsl_generator.process(d3d11_shaders), d3d11_res,
|
||||||
name_prefix : dxvk_name_prefix,
|
|
||||||
dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ],
|
dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ],
|
||||||
include_directories : dxvk_include_path,
|
include_directories : dxvk_include_path,
|
||||||
install : true,
|
install : true,
|
||||||
vs_module_defs : 'd3d11'+def_spec_ext,
|
vs_module_defs : 'd3d11'+def_spec_ext,
|
||||||
link_args : d3d11_ld_args,
|
link_args : d3d11_ld_args,
|
||||||
link_depends : [ d3d11_link_depends ],
|
link_depends : [ d3d11_link_depends ],
|
||||||
|
kwargs : dxvk_so_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
d3d11_dep = declare_dependency(
|
d3d11_dep = declare_dependency(
|
||||||
link_with : [ d3d11_dll ],
|
link_with : [ d3d11_dll ],
|
||||||
include_directories : [ dxvk_include_path ],
|
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
|
#version 450
|
||||||
|
|
||||||
|
#extension GL_EXT_samplerless_texture_functions : require
|
||||||
|
|
||||||
// Can't use matrix types here since even a two-row
|
// Can't use matrix types here since even a two-row
|
||||||
// matrix will be padded to 16 bytes per column for
|
// matrix will be padded to 16 bytes per column for
|
||||||
// absolutely no reason
|
// absolutely no reason
|
||||||
|
@ -11,6 +13,8 @@ uniform ubo_t {
|
||||||
vec2 coord_matrix_c1;
|
vec2 coord_matrix_c1;
|
||||||
vec2 coord_matrix_c2;
|
vec2 coord_matrix_c2;
|
||||||
vec2 coord_matrix_c3;
|
vec2 coord_matrix_c3;
|
||||||
|
uvec2 src_offset;
|
||||||
|
uvec2 src_extent;
|
||||||
float y_min;
|
float y_min;
|
||||||
float y_max;
|
float y_max;
|
||||||
bool is_planar;
|
bool is_planar;
|
||||||
|
@ -19,9 +23,8 @@ uniform ubo_t {
|
||||||
layout(location = 0) in vec2 i_texcoord;
|
layout(location = 0) in vec2 i_texcoord;
|
||||||
layout(location = 0) out vec4 o_color;
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
layout(set = 0, binding = 1) uniform sampler s_sampler;
|
layout(set = 0, binding = 1) uniform texture2D s_inputY;
|
||||||
layout(set = 0, binding = 2) uniform texture2D s_inputY;
|
layout(set = 0, binding = 2) uniform texture2D s_inputCbCr;
|
||||||
layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Transform input texture coordinates to
|
// Transform input texture coordinates to
|
||||||
|
@ -31,25 +34,61 @@ void main() {
|
||||||
coord_matrix_c2,
|
coord_matrix_c2,
|
||||||
coord_matrix_c3);
|
coord_matrix_c3);
|
||||||
|
|
||||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
// Load color space transform
|
||||||
|
|
||||||
// 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
|
|
||||||
mat3x4 color_matrix = mat3x4(
|
mat3x4 color_matrix = mat3x4(
|
||||||
color_matrix_r1,
|
color_matrix_r1,
|
||||||
color_matrix_r2,
|
color_matrix_r2,
|
||||||
color_matrix_r3);
|
color_matrix_r3);
|
||||||
|
|
||||||
o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
// Compute actual pixel coordinates to sample. We filter
|
||||||
o_color.a = color.a;
|
// 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)
|
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
|
||||||
return D3DERR_NOTAVAILABLE;
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
|
if (RType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
|
@ -224,11 +227,15 @@ namespace dxvk {
|
||||||
if (!IsDepthFormat(DepthStencilFormat))
|
if (!IsDepthFormat(DepthStencilFormat))
|
||||||
return D3DERR_NOTAVAILABLE;
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
|
auto dsfMapping = ConvertFormatUnfixed(DepthStencilFormat);
|
||||||
|
if (dsfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||||
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
|
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
|
auto rtfMapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
if (rtfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||||
return D3DERR_NOTAVAILABLE;
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
|
@ -118,6 +118,7 @@ namespace dxvk {
|
||||||
|
|
||||||
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
||||||
D3D9DeviceEx* pDevice,
|
D3D9DeviceEx* pDevice,
|
||||||
|
D3DRESOURCETYPE ResourceType,
|
||||||
D3D9_COMMON_TEXTURE_DESC* pDesc) {
|
D3D9_COMMON_TEXTURE_DESC* pDesc) {
|
||||||
auto* options = pDevice->GetOptions();
|
auto* options = pDevice->GetOptions();
|
||||||
|
|
||||||
|
@ -131,6 +132,11 @@ namespace dxvk {
|
||||||
options->disableA8RT)
|
options->disableA8RT)
|
||||||
return D3DERR_INVALIDCALL;
|
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
|
// If the mapping is invalid then lets return invalid
|
||||||
// Some edge cases:
|
// Some edge cases:
|
||||||
// NULL format does not map to anything, but should succeed
|
// NULL format does not map to anything, but should succeed
|
||||||
|
|
|
@ -179,11 +179,14 @@ namespace dxvk {
|
||||||
* Fills in undefined values and validates the texture
|
* Fills in undefined values and validates the texture
|
||||||
* parameters. Any error returned by this method should
|
* parameters. Any error returned by this method should
|
||||||
* be forwarded to the application.
|
* be forwarded to the application.
|
||||||
|
* \param [in] pDevice D3D9 device
|
||||||
|
* \param [in] ResourceType Resource type
|
||||||
* \param [in,out] pDesc Texture description
|
* \param [in,out] pDesc Texture description
|
||||||
* \returns \c S_OK if the parameters are valid
|
* \returns \c S_OK if the parameters are valid
|
||||||
*/
|
*/
|
||||||
static HRESULT NormalizeTextureProperties(
|
static HRESULT NormalizeTextureProperties(
|
||||||
D3D9DeviceEx* pDevice,
|
D3D9DeviceEx* pDevice,
|
||||||
|
D3DRESOURCETYPE ResourceType,
|
||||||
D3D9_COMMON_TEXTURE_DESC* pDesc);
|
D3D9_COMMON_TEXTURE_DESC* pDesc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace dxvk {
|
||||||
DxsoProgramType ShaderStage,
|
DxsoProgramType ShaderStage,
|
||||||
DxsoConstantBuffers BufferType,
|
DxsoConstantBuffers BufferType,
|
||||||
VkDeviceSize Size)
|
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),
|
computeResourceSlotId(ShaderStage, DxsoBindingType::ConstantBuffer, BufferType),
|
||||||
Size) {
|
Size) {
|
||||||
|
|
||||||
|
@ -135,21 +135,4 @@ namespace dxvk {
|
||||||
device->properties().extRobustness2.robustUniformBufferAccessSizeAlignment);
|
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;
|
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_csThread ( dxvkDevice, dxvkDevice->createContext(DxvkContextType::Primary) )
|
||||||
, m_csChunk ( AllocCsChunk() )
|
, m_csChunk ( AllocCsChunk() )
|
||||||
, m_submissionFence (new sync::Fence())
|
, m_submissionFence (new sync::Fence())
|
||||||
|
, m_flushTracker (m_d3d9Options.reproducibleCommandStream)
|
||||||
, m_d3d9Interop ( this )
|
, m_d3d9Interop ( this )
|
||||||
, m_d3d9On12 ( this )
|
, m_d3d9On12 ( this )
|
||||||
, m_d3d8Bridge ( this ) {
|
, m_d3d8Bridge ( this ) {
|
||||||
|
@ -594,7 +595,7 @@ namespace dxvk {
|
||||||
|| (Usage & D3DUSAGE_DYNAMIC)
|
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||||
|| IsVendorFormat(EnumerateFormat(Format));
|
|| IsVendorFormat(EnumerateFormat(Format));
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -664,7 +665,7 @@ namespace dxvk {
|
||||||
|| (Usage & D3DUSAGE_DYNAMIC)
|
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||||
|| IsVendorFormat(EnumerateFormat(Format));
|
|| IsVendorFormat(EnumerateFormat(Format));
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_VOLUMETEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -721,7 +722,7 @@ namespace dxvk {
|
||||||
|| (Usage & D3DUSAGE_DYNAMIC)
|
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||||
|| IsVendorFormat(EnumerateFormat(Format));
|
|| IsVendorFormat(EnumerateFormat(Format));
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_CUBETEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -3798,7 +3799,7 @@ namespace dxvk {
|
||||||
desc.IsAttachmentOnly = TRUE;
|
desc.IsAttachmentOnly = TRUE;
|
||||||
desc.IsLockable = Lockable;
|
desc.IsLockable = Lockable;
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -3846,7 +3847,7 @@ namespace dxvk {
|
||||||
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
|
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
|
||||||
desc.IsLockable = TRUE;
|
desc.IsLockable = TRUE;
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
||||||
|
@ -3901,7 +3902,7 @@ namespace dxvk {
|
||||||
// Docs don't say anything, so just assume it's lockable.
|
// Docs don't say anything, so just assume it's lockable.
|
||||||
desc.IsLockable = TRUE;
|
desc.IsLockable = TRUE;
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -5158,7 +5159,7 @@ namespace dxvk {
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void D3D9DeviceEx::UploadDynamicSysmemBuffers(
|
void D3D9DeviceEx::UploadDynamicSysmemBuffers(
|
||||||
UINT& FirstVertexIndex,
|
UINT& FirstVertexIndex,
|
||||||
|
@ -5190,25 +5191,58 @@ namespace dxvk {
|
||||||
// First we calculate the size of that UP buffer slice
|
// First we calculate the size of that UP buffer slice
|
||||||
// and store all sizes and offsets into it.
|
// and store all sizes and offsets into it.
|
||||||
|
|
||||||
uint32_t upBufferSize = 0;
|
struct VBOCopy {
|
||||||
std::array<uint32_t, caps::MaxStreams> vboUPBufferOffsets = {};
|
uint32_t srcOffset;
|
||||||
std::array<uint32_t, caps::MaxStreams> vboUPBufferSizes = {};
|
uint32_t dstOffset;
|
||||||
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
|
uint32_t copyBufferLength;
|
||||||
vboUPBufferOffsets[i] = upBufferSize;
|
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);
|
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||||
if (likely(vbo == nullptr)) {
|
if (likely(vbo == nullptr)) {
|
||||||
vboUPBufferSizes[i] = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
|
const uint32_t vertexSize = m_state.vertexDecl->GetSize(i);
|
||||||
uint32_t offset = (FirstVertexIndex + BaseVertexIndex) * vertexStride;
|
const uint32_t vertexStride = m_state.vertexBuffers[i].stride;
|
||||||
const uint32_t vertexBufferSize = vbo->Desc()->Size;
|
const uint32_t srcStride = vertexStride;
|
||||||
if (offset < vertexBufferSize) {
|
const uint32_t dstStride = std::min(vertexStride, vertexSize);
|
||||||
const uint32_t vertexDataSize = std::min(NumVertices * vertexStride, vertexBufferSize - offset);
|
|
||||||
vboUPBufferSizes[i] = vertexDataSize;
|
uint32_t elementCount = NumVertices;
|
||||||
upBufferSize += vertexDataSize;
|
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 iboUPBufferSize = 0;
|
||||||
|
@ -5221,13 +5255,13 @@ namespace dxvk {
|
||||||
uint32_t indexBufferSize = ibo->Desc()->Size;
|
uint32_t indexBufferSize = ibo->Desc()->Size;
|
||||||
if (offset < indexBufferSize) {
|
if (offset < indexBufferSize) {
|
||||||
iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset);
|
iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset);
|
||||||
iboUPBufferOffset = upBufferSize;
|
iboUPBufferOffset = totalUpBufferSize;
|
||||||
upBufferSize += iboUPBufferSize;
|
totalUpBufferSize += iboUPBufferSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(upBufferSize == 0)) {
|
if (unlikely(totalUpBufferSize == 0)) {
|
||||||
*pDynamicVBOs = false;
|
*pDynamicVBOs = false;
|
||||||
if (pDynamicIBO)
|
if (pDynamicIBO)
|
||||||
*pDynamicIBO = false;
|
*pDynamicIBO = false;
|
||||||
|
@ -5235,47 +5269,49 @@ namespace dxvk {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto upSlice = AllocUPBuffer(upBufferSize);
|
auto upSlice = AllocUPBuffer(totalUpBufferSize);
|
||||||
|
|
||||||
// Now copy the actual data and bind it.
|
// Now copy the actual data and bind it.
|
||||||
if (dynamicSysmemVBOs) {
|
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
|
||||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
const VBOCopy& copy = vboCopies[i];
|
||||||
if (unlikely(vboUPBufferSizes[i] == 0)) {
|
|
||||||
EmitCs([
|
if (likely(copy.copyBufferLength != 0)) {
|
||||||
cStream = i
|
const auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
||||||
](DxvkContext* ctx) {
|
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + copy.dstOffset;
|
||||||
ctx->bindVertexBuffer(cStream, DxvkBufferSlice(), 0);
|
const uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + copy.srcOffset;
|
||||||
});
|
|
||||||
m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers);
|
if (likely(copy.copyElementStride == copy.copyElementSize)) {
|
||||||
continue;
|
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* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
|
|
||||||
|
|
||||||
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
|
|
||||||
uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vertexStride + m_state.vertexBuffers[i].offset;
|
|
||||||
|
|
||||||
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + vboUPBufferOffsets[i];
|
|
||||||
uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + offset;
|
|
||||||
std::memcpy(data, src, vboUPBufferSizes[i]);
|
|
||||||
|
|
||||||
auto vboSlice = upSlice.slice.subSlice(vboUPBufferOffsets[i], vboUPBufferSizes[i]);
|
|
||||||
EmitCs([
|
|
||||||
cStream = i,
|
|
||||||
cBufferSlice = std::move(vboSlice),
|
|
||||||
cStride = vertexStride
|
|
||||||
](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
|
auto vboSlice = upSlice.slice.subSlice(copy.dstOffset, copy.copyBufferLength);
|
||||||
if (NumIndices != 0) {
|
EmitCs([
|
||||||
BaseVertexIndex = -FirstVertexIndex;
|
cStream = i,
|
||||||
} else {
|
cBufferSlice = std::move(vboSlice),
|
||||||
FirstVertexIndex = 0;
|
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 (dynamicSysmemIBO) {
|
||||||
|
@ -5292,7 +5328,7 @@ namespace dxvk {
|
||||||
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + iboUPBufferOffset;
|
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + iboUPBufferOffset;
|
||||||
uint8_t* src = reinterpret_cast<uint8_t*>(ibo->GetMappedSlice().mapPtr) + offset;
|
uint8_t* src = reinterpret_cast<uint8_t*>(ibo->GetMappedSlice().mapPtr) + offset;
|
||||||
std::memcpy(data, src, iboUPBufferSize);
|
std::memcpy(data, src, iboUPBufferSize);
|
||||||
|
|
||||||
auto iboSlice = upSlice.slice.subSlice(iboUPBufferOffset, iboUPBufferSize);
|
auto iboSlice = upSlice.slice.subSlice(iboUPBufferOffset, iboUPBufferSize);
|
||||||
EmitCs([
|
EmitCs([
|
||||||
cBufferSlice = std::move(iboSlice),
|
cBufferSlice = std::move(iboSlice),
|
||||||
|
@ -7891,7 +7927,7 @@ namespace dxvk {
|
||||||
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
|
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
|
||||||
desc.IsLockable = TRUE;
|
desc.IsLockable = TRUE;
|
||||||
|
|
||||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||||
return D3DERR_NOTAVAILABLE;
|
return D3DERR_NOTAVAILABLE;
|
||||||
|
|
||||||
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);
|
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);
|
||||||
|
|
|
@ -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 floatType = spvModule.defFloatType(32);
|
||||||
uint32_t uintType = spvModule.defIntType(32, 0);
|
uint32_t uintType = spvModule.defIntType(32, 0);
|
||||||
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
||||||
|
@ -357,7 +357,7 @@ namespace dxvk {
|
||||||
floatType,
|
floatType,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data());
|
uint32_t rsStruct = spvModule.defStructTypeUnique(rsMembers.size(), rsMembers.data());
|
||||||
uint32_t rsBlock = spvModule.newVar(
|
uint32_t rsBlock = spvModule.newVar(
|
||||||
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
|
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
|
||||||
spv::StorageClassPushConstant);
|
spv::StorageClassPushConstant);
|
||||||
|
@ -369,9 +369,6 @@ namespace dxvk {
|
||||||
|
|
||||||
uint32_t memberIdx = 0;
|
uint32_t memberIdx = 0;
|
||||||
auto SetMemberName = [&](const char* name, uint32_t offset) {
|
auto SetMemberName = [&](const char* name, uint32_t offset) {
|
||||||
if (memberIdx >= count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
spvModule.setDebugMemberName (rsStruct, memberIdx, name);
|
spvModule.setDebugMemberName (rsStruct, memberIdx, name);
|
||||||
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
|
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
|
||||||
memberIdx++;
|
memberIdx++;
|
||||||
|
@ -781,8 +778,6 @@ namespace dxvk {
|
||||||
uint32_t m_inputMask = 0u;
|
uint32_t m_inputMask = 0u;
|
||||||
uint32_t m_outputMask = 0u;
|
uint32_t m_outputMask = 0u;
|
||||||
uint32_t m_flatShadingMask = 0u;
|
uint32_t m_flatShadingMask = 0u;
|
||||||
uint32_t m_pushConstOffset = 0u;
|
|
||||||
uint32_t m_pushConstSize = 0u;
|
|
||||||
|
|
||||||
DxsoProgramType m_programType;
|
DxsoProgramType m_programType;
|
||||||
D3D9FFShaderKeyVS m_vsKey;
|
D3D9FFShaderKeyVS m_vsKey;
|
||||||
|
@ -892,8 +887,8 @@ namespace dxvk {
|
||||||
info.inputMask = m_inputMask;
|
info.inputMask = m_inputMask;
|
||||||
info.outputMask = m_outputMask;
|
info.outputMask = m_outputMask;
|
||||||
info.flatShadingInputs = m_flatShadingMask;
|
info.flatShadingInputs = m_flatShadingMask;
|
||||||
info.pushConstOffset = m_pushConstOffset;
|
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
info.pushConstSize = m_pushConstSize;
|
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||||
|
|
||||||
return new DxvkShader(info, m_module.compile());
|
return new DxvkShader(info, m_module.compile());
|
||||||
}
|
}
|
||||||
|
@ -1111,6 +1106,17 @@ namespace dxvk {
|
||||||
const uint32_t wIndex = 3;
|
const uint32_t wIndex = 3;
|
||||||
|
|
||||||
uint32_t flags = (m_vsKey.Data.Contents.TransformFlags >> (i * 3)) & 0b111;
|
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;
|
uint32_t count;
|
||||||
switch (inputFlags) {
|
switch (inputFlags) {
|
||||||
default:
|
default:
|
||||||
|
@ -1121,27 +1127,30 @@ namespace dxvk {
|
||||||
count = flags;
|
count = flags;
|
||||||
if (texcoordCount) {
|
if (texcoordCount) {
|
||||||
// Clamp by the number of elements in the texcoord input.
|
// Clamp by the number of elements in the texcoord input.
|
||||||
if (!count || count > texcoordCount)
|
if (!count || count > texcoordCount) {
|
||||||
count = texcoordCount;
|
count = texcoordCount;
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
|
count = 0;
|
||||||
flags = D3DTTFF_DISABLE;
|
flags = D3DTTFF_DISABLE;
|
||||||
|
applyTransform = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset):
|
case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset):
|
||||||
transformed = outNrm;
|
transformed = outNrm;
|
||||||
count = 4;
|
count = std::min(flags, 4u);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DXVK_TSS_TCI_CAMERASPACEPOSITION >> TCIOffset):
|
case (DXVK_TSS_TCI_CAMERASPACEPOSITION >> TCIOffset):
|
||||||
transformed = m_module.opCompositeInsert(m_vec4Type, m_module.constf32(1.0f), vtx, 1, &wIndex);
|
transformed = m_module.opCompositeInsert(m_vec4Type, m_module.constf32(1.0f), vtx, 1, &wIndex);
|
||||||
count = 4;
|
count = std::min(flags, 4u);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): {
|
case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): {
|
||||||
uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
|
uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data());
|
||||||
vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
|
vtx3 = m_module.opNormalize(m_vec3Type, vtx3);
|
||||||
|
|
||||||
uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
|
uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal);
|
||||||
|
|
||||||
std::array<uint32_t, 4> transformIndices;
|
std::array<uint32_t, 4> transformIndices;
|
||||||
|
@ -1150,7 +1159,7 @@ namespace dxvk {
|
||||||
transformIndices[3] = m_module.constf32(1.0f);
|
transformIndices[3] = m_module.constf32(1.0f);
|
||||||
|
|
||||||
transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
|
transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
|
||||||
count = 4;
|
count = std::min(flags, 4u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,37 +1183,43 @@ namespace dxvk {
|
||||||
transformIndices[3] = m_module.constf32(1.0f);
|
transformIndices[3] = m_module.constf32(1.0f);
|
||||||
|
|
||||||
transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
|
transformed = m_module.opCompositeConstruct(m_vec4Type, transformIndices.size(), transformIndices.data());
|
||||||
count = 4;
|
count = std::min(flags, 4u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t type = flags;
|
if (applyTransform && !m_vsKey.Data.Contents.HasPositionT) {
|
||||||
if (type != D3DTTFF_DISABLE) {
|
for (uint32_t j = count; j < 4; j++) {
|
||||||
if (!m_vsKey.Data.Contents.HasPositionT) {
|
// If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes.
|
||||||
for (uint32_t j = count; j < 4; j++) {
|
// Otherwise, pad with ones.
|
||||||
// If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes.
|
|
||||||
// Otherwise, pad with ones.
|
|
||||||
|
|
||||||
// Very weird quirk in order to get texcoord transforms to work like they do in native.
|
// Very weird quirk in order to get texcoord transforms to work like they do in native.
|
||||||
// In future, maybe we could sort this out properly by chopping matrices of different sizes, but thats
|
// In future, maybe we could sort this out properly by chopping matrices of different sizes, but thats
|
||||||
// a project for another day.
|
// a project for another day.
|
||||||
uint32_t texcoordCount = (m_vsKey.Data.Contents.TexcoordDeclMask >> (3 * inputIndex)) & 0x7;
|
uint32_t texcoordCount = (m_vsKey.Data.Contents.TexcoordDeclMask >> (3 * inputIndex)) & 0x7;
|
||||||
uint32_t value = j > texcoordCount ? m_module.constf32(0) : m_module.constf32(1);
|
uint32_t value = j > texcoordCount ? m_module.constf32(0) : m_module.constf32(1);
|
||||||
transformed = m_module.opCompositeInsert(m_vec4Type, value, transformed, 1, &j);
|
transformed = m_module.opCompositeInsert(m_vec4Type, value, transformed, 1, &j);
|
||||||
}
|
|
||||||
|
|
||||||
transformed = m_module.opVectorTimesMatrix(m_vec4Type, transformed, m_vs.constants.texcoord[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad the unused section of it with the value for projection.
|
transformed = m_module.opVectorTimesMatrix(m_vec4Type, transformed, m_vs.constants.texcoord[i]);
|
||||||
uint32_t lastIdx = count - 1;
|
|
||||||
uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &lastIdx);
|
|
||||||
|
|
||||||
for (uint32_t j = count; j < 4; j++)
|
|
||||||
transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &j);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The projection idx is always based on the flags, even when the input mode is not DXVK_TSS_TCI_PASSTHRU.
|
||||||
|
uint32_t projValue;
|
||||||
|
if (count < 3) {
|
||||||
|
// Not enough components to do projection.
|
||||||
|
// Native drivers render normally or garbage with D3DFVF_TEXCOORDSIZE2 or D3DTTFF_COUNT <3
|
||||||
|
projValue = m_module.constf32(1.0f);
|
||||||
|
} else {
|
||||||
|
uint32_t projIdx = count - 1;
|
||||||
|
projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &projIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The w component is only used for projection or unused, so always insert the component that's supposed to be divided by there.
|
||||||
|
// The fragment shader will then decide whether to project or not.
|
||||||
|
uint32_t wIdx = 3;
|
||||||
|
transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &wIdx);
|
||||||
|
|
||||||
m_module.opStore(m_vs.out.TEXCOORD[i], transformed);
|
m_module.opStore(m_vs.out.TEXCOORD[i], transformed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1384,20 +1399,7 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
void D3D9FFShaderCompiler::setupRenderStateInfo() {
|
void D3D9FFShaderCompiler::setupRenderStateInfo() {
|
||||||
uint32_t count;
|
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1808,22 +1810,17 @@ namespace dxvk {
|
||||||
texcoord = m_module.opVectorShuffle(texcoord_t,
|
texcoord = m_module.opVectorShuffle(texcoord_t,
|
||||||
texcoord, texcoord, texcoordCnt, indices.data());
|
texcoord, texcoord, texcoordCnt, indices.data());
|
||||||
|
|
||||||
uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount;
|
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
|
||||||
if (projIdx == 0 || projIdx > texcoordCnt) {
|
|
||||||
projIdx = 4; // Always use w if ProjectedCount is 0.
|
|
||||||
}
|
|
||||||
--projIdx;
|
|
||||||
|
|
||||||
uint32_t projValue = 0;
|
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);
|
projValue = m_module.opCompositeExtract(m_floatType, m_ps.in.TEXCOORD[i], 1, &projIdx);
|
||||||
uint32_t insertIdx = texcoordCnt - 1;
|
uint32_t insertIdx = texcoordCnt - 1;
|
||||||
texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx);
|
texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldProject = m_fsKey.Stages[i].Contents.Projected;
|
|
||||||
|
|
||||||
if (i != 0 && (
|
if (i != 0 && (
|
||||||
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP ||
|
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP ||
|
||||||
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {
|
m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace dxvk {
|
||||||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
||||||
|
|
||||||
// Returns a render state block
|
// Returns a render state block
|
||||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
|
uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
|
||||||
|
|
||||||
struct D3D9PointSizeInfoVS {
|
struct D3D9PointSizeInfoVS {
|
||||||
uint32_t defaultValue;
|
uint32_t defaultValue;
|
||||||
|
|
|
@ -134,7 +134,7 @@ namespace dxvk {
|
||||||
info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
info.bindingCount = bindings.size();
|
info.bindingCount = bindings.size();
|
||||||
info.bindings = bindings.data();
|
info.bindings = bindings.data();
|
||||||
info.pushConstOffset = 0;
|
info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
info.pushConstSize = sizeof(VkExtent2D);
|
info.pushConstSize = sizeof(VkExtent2D);
|
||||||
|
|
||||||
return new DxvkShader(info, std::move(code));
|
return new DxvkShader(info, std::move(code));
|
||||||
|
|
|
@ -37,8 +37,8 @@ namespace dxvk {
|
||||||
this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
|
this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
|
||||||
this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
|
this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
|
||||||
|
|
||||||
const int32_t vendorId = this->customDeviceId != -1
|
const uint32_t vendorId = this->customVendorId != -1
|
||||||
? this->customDeviceId
|
? this->customVendorId
|
||||||
: (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
|
: (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
|
||||||
|
|
||||||
this->maxFrameLatency = config.getOption<int32_t> ("d3d9.maxFrameLatency", 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->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
|
||||||
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
|
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
|
||||||
this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
|
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->supportX4R4G4B4 = config.getOption<bool> ("d3d9.supportX4R4G4B4", true);
|
||||||
this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
|
this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
|
||||||
this->useD32forD24 = config.getOption<bool> ("d3d9.useD32forD24", false);
|
this->useD32forD24 = config.getOption<bool> ("d3d9.useD32forD24", false);
|
||||||
this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
|
this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
|
||||||
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", true);
|
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", true);
|
||||||
this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
|
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->enableDialogMode = config.getOption<bool> ("d3d9.enableDialogMode", false);
|
||||||
this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
|
this->forceSamplerTypeSpecConstants = config.getOption<bool> ("d3d9.forceSamplerTypeSpecConstants", false);
|
||||||
this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
|
this->forceSwapchainMSAA = config.getOption<int32_t> ("d3d9.forceSwapchainMSAA", -1);
|
||||||
|
@ -77,6 +77,7 @@ namespace dxvk {
|
||||||
this->samplerLodBias = config.getOption<float> ("d3d9.samplerLodBias", 0.0f);
|
this->samplerLodBias = config.getOption<float> ("d3d9.samplerLodBias", 0.0f);
|
||||||
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
this->clampNegativeLodBias = config.getOption<bool> ("d3d9.clampNegativeLodBias", false);
|
||||||
this->countLosableResources = config.getOption<bool> ("d3d9.countLosableResources", true);
|
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
|
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||||
|
@ -90,8 +91,8 @@ namespace dxvk {
|
||||||
d3d9FloatEmulation = D3D9FloatEmulation::Enabled;
|
d3d9FloatEmulation = D3D9FloatEmulation::Enabled;
|
||||||
} else {
|
} else {
|
||||||
bool hasMulz = adapter != nullptr
|
bool hasMulz = adapter != nullptr
|
||||||
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV, 0, 0)
|
&& (adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV)
|
||||||
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK, 0, 0));
|
|| adapter->matchesDriver(VK_DRIVER_ID_MESA_NVK));
|
||||||
d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
|
d3d9FloatEmulation = hasMulz ? D3D9FloatEmulation::Strict : D3D9FloatEmulation::Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,11 @@ namespace dxvk {
|
||||||
|
|
||||||
/// Disable counting losable resources and rejecting calls to Reset() if any are still alive
|
/// Disable counting losable resources and rejecting calls to Reset() if any are still alive
|
||||||
bool countLosableResources;
|
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:
|
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3DQUERYTYPE_VERTEXSTATS:
|
|
||||||
m_query[0] = dxvkDevice->createGpuQuery(
|
|
||||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
||||||
}
|
}
|
||||||
|
@ -222,12 +217,10 @@ namespace dxvk {
|
||||||
|
|
||||||
switch (m_queryType) {
|
switch (m_queryType) {
|
||||||
case D3DQUERYTYPE_VCACHE:
|
case D3DQUERYTYPE_VCACHE:
|
||||||
// Don't know what the hell any of this means.
|
m_dataCache.VCache.Pattern = MAKEFOURCC('C', 'A', 'C', 'H');
|
||||||
// Nor do I care. This just makes games work.
|
|
||||||
m_dataCache.VCache.Pattern = MAKEFOURCC('H', 'C', 'A', 'C');
|
|
||||||
m_dataCache.VCache.OptMethod = 1;
|
m_dataCache.VCache.OptMethod = 1;
|
||||||
m_dataCache.VCache.CacheSize = 24;
|
m_dataCache.VCache.CacheSize = 16;
|
||||||
m_dataCache.VCache.MagicNumber = 20;
|
m_dataCache.VCache.MagicNumber = 7;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3DQUERYTYPE_OCCLUSION:
|
case D3DQUERYTYPE_OCCLUSION:
|
||||||
|
@ -246,11 +239,6 @@ namespace dxvk {
|
||||||
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
|
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3DQUERYTYPE_VERTEXSTATS:
|
|
||||||
m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
|
|
||||||
m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +264,6 @@ namespace dxvk {
|
||||||
void D3D9Query::Begin(DxvkContext* ctx) {
|
void D3D9Query::Begin(DxvkContext* ctx) {
|
||||||
switch (m_queryType) {
|
switch (m_queryType) {
|
||||||
case D3DQUERYTYPE_OCCLUSION:
|
case D3DQUERYTYPE_OCCLUSION:
|
||||||
case D3DQUERYTYPE_VERTEXSTATS:
|
|
||||||
ctx->beginQuery(m_query[0]);
|
ctx->beginQuery(m_query[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -296,7 +283,6 @@ namespace dxvk {
|
||||||
ctx->writeTimestamp(m_query[0]);
|
ctx->writeTimestamp(m_query[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3DQUERYTYPE_VERTEXSTATS:
|
|
||||||
case D3DQUERYTYPE_OCCLUSION:
|
case D3DQUERYTYPE_OCCLUSION:
|
||||||
ctx->endQuery(m_query[0]);
|
ctx->endQuery(m_query[0]);
|
||||||
break;
|
break;
|
||||||
|
@ -314,7 +300,6 @@ namespace dxvk {
|
||||||
|
|
||||||
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
||||||
return QueryType == D3DQUERYTYPE_OCCLUSION
|
return QueryType == D3DQUERYTYPE_OCCLUSION
|
||||||
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|
|
||||||
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +323,6 @@ namespace dxvk {
|
||||||
case D3DQUERYTYPE_TIMESTAMP:
|
case D3DQUERYTYPE_TIMESTAMP:
|
||||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||||
case D3DQUERYTYPE_VERTEXSTATS:
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -57,17 +57,24 @@ if platform != 'windows'
|
||||||
d3d9_link_depends += files('d3d9.sym')
|
d3d9_link_depends += files('d3d9.sym')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
|
d3d9_dll = shared_library(dxvk_name_prefix+'d3d9', d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
|
||||||
name_prefix : dxvk_name_prefix,
|
|
||||||
dependencies : [ dxso_dep, dxvk_dep ],
|
dependencies : [ dxso_dep, dxvk_dep ],
|
||||||
include_directories : dxvk_include_path,
|
include_directories : dxvk_include_path,
|
||||||
install : true,
|
install : true,
|
||||||
vs_module_defs : 'd3d9'+def_spec_ext,
|
vs_module_defs : 'd3d9'+def_spec_ext,
|
||||||
link_args : d3d9_ld_args,
|
link_args : d3d9_ld_args,
|
||||||
link_depends : [ d3d9_link_depends ],
|
link_depends : [ d3d9_link_depends ],
|
||||||
|
kwargs : dxvk_so_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
d3d9_dep = declare_dependency(
|
d3d9_dep = declare_dependency(
|
||||||
link_with : [ d3d9_dll ],
|
link_with : [ d3d9_dll ],
|
||||||
include_directories : [ dxvk_include_path ],
|
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++) {
|
for (uint32_t i = 0; i < ins.dstCount; i++) {
|
||||||
if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
|
if (ins.dst[i].type == DxbcOperandType::IndexableTemp) {
|
||||||
uint32_t index = ins.dst[0].idx[0].offset;
|
uint32_t index = ins.dst[i].idx[0].offset;
|
||||||
m_analysis->xRegMasks[index] |= ins.dst[0].mask;
|
m_analysis->xRegMasks[index] |= ins.dst[i].mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,11 @@ namespace dxvk {
|
||||||
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
|
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
|
||||||
entry.componentType = componentTypes.at(reader.readu32());
|
entry.componentType = componentTypes.at(reader.readu32());
|
||||||
entry.registerId = 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)
|
if (hasPrecision)
|
||||||
reader.readu32();
|
reader.readu32();
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace dxvk {
|
||||||
uint32_t semanticIndex;
|
uint32_t semanticIndex;
|
||||||
uint32_t registerId;
|
uint32_t registerId;
|
||||||
DxbcRegMask componentMask;
|
DxbcRegMask componentMask;
|
||||||
|
DxbcRegMask componentUsed;
|
||||||
DxbcScalarType componentType;
|
DxbcScalarType componentType;
|
||||||
DxbcSystemValue systemValue;
|
DxbcSystemValue systemValue;
|
||||||
uint32_t streamId;
|
uint32_t streamId;
|
||||||
|
|
|
@ -257,14 +257,13 @@ namespace dxvk {
|
||||||
info.outputMask = m_outputMask;
|
info.outputMask = m_outputMask;
|
||||||
info.uniformSize = m_immConstData.size();
|
info.uniformSize = m_immConstData.size();
|
||||||
info.uniformData = m_immConstData.data();
|
info.uniformData = m_immConstData.data();
|
||||||
|
info.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
info.pushConstSize = sizeof(DxbcPushConstants);
|
||||||
info.outputTopology = m_outputTopology;
|
info.outputTopology = m_outputTopology;
|
||||||
|
|
||||||
if (m_programInfo.type() == DxbcProgramType::HullShader)
|
if (m_programInfo.type() == DxbcProgramType::HullShader)
|
||||||
info.patchVertexCount = m_hs.vertexCountIn;
|
info.patchVertexCount = m_hs.vertexCountIn;
|
||||||
|
|
||||||
if (m_programInfo.type() == DxbcProgramType::PixelShader && m_ps.pushConstantId)
|
|
||||||
info.pushConstSize = sizeof(DxbcPushConstants);
|
|
||||||
|
|
||||||
if (m_moduleInfo.xfb) {
|
if (m_moduleInfo.xfb) {
|
||||||
info.xfbRasterizedStream = m_moduleInfo.xfb->rasterizedStream;
|
info.xfbRasterizedStream = m_moduleInfo.xfb->rasterizedStream;
|
||||||
|
|
||||||
|
@ -1624,8 +1623,13 @@ namespace dxvk {
|
||||||
|
|
||||||
case DxbcOpcode::Mad:
|
case DxbcOpcode::Mad:
|
||||||
case DxbcOpcode::DFma:
|
case DxbcOpcode::DFma:
|
||||||
dst.id = m_module.opFFma(typeId,
|
if (likely(!m_moduleInfo.options.longMad)) {
|
||||||
src.at(0).id, src.at(1).id, src.at(2).id);
|
dst.id = m_module.opFFma(typeId,
|
||||||
|
src.at(0).id, src.at(1).id, src.at(2).id);
|
||||||
|
} else {
|
||||||
|
dst.id = m_module.opFMul(typeId, src.at(0).id, src.at(1).id);
|
||||||
|
dst.id = m_module.opFAdd(typeId, dst.id, src.at(2).id);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DxbcOpcode::Max:
|
case DxbcOpcode::Max:
|
||||||
|
@ -2464,58 +2468,6 @@ namespace dxvk {
|
||||||
if (m_uavs.at(registerId).ctrId == 0)
|
if (m_uavs.at(registerId).ctrId == 0)
|
||||||
m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
|
m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
|
||||||
|
|
||||||
// Only use subgroup ops on compute to avoid having to
|
|
||||||
// deal with helper invocations or hardware limitations
|
|
||||||
bool useSubgroupOps = m_moduleInfo.options.useSubgroupOpsForAtomicCounters
|
|
||||||
&& m_programInfo.type() == DxbcProgramType::ComputeShader;
|
|
||||||
|
|
||||||
// Current block ID used in a phi later on
|
|
||||||
uint32_t baseBlockId = m_module.getBlockId();
|
|
||||||
|
|
||||||
// In case we have subgroup ops enabled, we need to
|
|
||||||
// count the number of active lanes, the lane index,
|
|
||||||
// and we need to perform the atomic op conditionally
|
|
||||||
uint32_t laneCount = 0;
|
|
||||||
uint32_t laneIndex = 0;
|
|
||||||
|
|
||||||
DxbcConditional elect;
|
|
||||||
|
|
||||||
if (useSubgroupOps) {
|
|
||||||
m_module.enableCapability(spv::CapabilityGroupNonUniform);
|
|
||||||
m_module.enableCapability(spv::CapabilityGroupNonUniformBallot);
|
|
||||||
|
|
||||||
uint32_t ballot = m_module.opGroupNonUniformBallot(
|
|
||||||
getVectorTypeId({ DxbcScalarType::Uint32, 4 }),
|
|
||||||
m_module.constu32(spv::ScopeSubgroup),
|
|
||||||
m_module.constBool(true));
|
|
||||||
|
|
||||||
laneCount = m_module.opGroupNonUniformBallotBitCount(
|
|
||||||
getScalarTypeId(DxbcScalarType::Uint32),
|
|
||||||
m_module.constu32(spv::ScopeSubgroup),
|
|
||||||
spv::GroupOperationReduce, ballot);
|
|
||||||
|
|
||||||
laneIndex = m_module.opGroupNonUniformBallotBitCount(
|
|
||||||
getScalarTypeId(DxbcScalarType::Uint32),
|
|
||||||
m_module.constu32(spv::ScopeSubgroup),
|
|
||||||
spv::GroupOperationExclusiveScan, ballot);
|
|
||||||
|
|
||||||
// Elect one lane to perform the atomic op
|
|
||||||
uint32_t election = m_module.opGroupNonUniformElect(
|
|
||||||
m_module.defBoolType(),
|
|
||||||
m_module.constu32(spv::ScopeSubgroup));
|
|
||||||
|
|
||||||
elect.labelIf = m_module.allocateId();
|
|
||||||
elect.labelEnd = m_module.allocateId();
|
|
||||||
|
|
||||||
m_module.opSelectionMerge(elect.labelEnd, spv::SelectionControlMaskNone);
|
|
||||||
m_module.opBranchConditional(election, elect.labelIf, elect.labelEnd);
|
|
||||||
|
|
||||||
m_module.opLabel(elect.labelIf);
|
|
||||||
} else {
|
|
||||||
// We're going to use this for the increment
|
|
||||||
laneCount = m_module.constu32(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a pointer to the atomic counter in question
|
// Get a pointer to the atomic counter in question
|
||||||
DxbcRegisterInfo ptrType;
|
DxbcRegisterInfo ptrType;
|
||||||
ptrType.type.ctype = DxbcScalarType::Uint32;
|
ptrType.type.ctype = DxbcScalarType::Uint32;
|
||||||
|
@ -2547,13 +2499,14 @@ namespace dxvk {
|
||||||
switch (ins.op) {
|
switch (ins.op) {
|
||||||
case DxbcOpcode::ImmAtomicAlloc:
|
case DxbcOpcode::ImmAtomicAlloc:
|
||||||
value.id = m_module.opAtomicIAdd(typeId, ptrId,
|
value.id = m_module.opAtomicIAdd(typeId, ptrId,
|
||||||
scopeId, semanticsId, laneCount);
|
scopeId, semanticsId, m_module.constu32(1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DxbcOpcode::ImmAtomicConsume:
|
case DxbcOpcode::ImmAtomicConsume:
|
||||||
value.id = m_module.opAtomicISub(typeId, ptrId,
|
value.id = m_module.opAtomicISub(typeId, ptrId,
|
||||||
scopeId, semanticsId, laneCount);
|
scopeId, semanticsId, m_module.constu32(1));
|
||||||
value.id = m_module.opISub(typeId, value.id, laneCount);
|
value.id = m_module.opISub(typeId, value.id,
|
||||||
|
m_module.constu32(1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2563,26 +2516,6 @@ namespace dxvk {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're using subgroup ops, we have to broadcast
|
|
||||||
// the result of the atomic op and compute the index
|
|
||||||
if (useSubgroupOps) {
|
|
||||||
m_module.opBranch(elect.labelEnd);
|
|
||||||
m_module.opLabel (elect.labelEnd);
|
|
||||||
|
|
||||||
uint32_t undef = m_module.constUndef(typeId);
|
|
||||||
|
|
||||||
std::array<SpirvPhiLabel, 2> phiLabels = {{
|
|
||||||
{ value.id, elect.labelIf },
|
|
||||||
{ undef, baseBlockId },
|
|
||||||
}};
|
|
||||||
|
|
||||||
value.id = m_module.opPhi(typeId,
|
|
||||||
phiLabels.size(), phiLabels.data());
|
|
||||||
value.id = m_module.opGroupNonUniformBroadcastFirst(typeId,
|
|
||||||
m_module.constu32(spv::ScopeSubgroup), value.id);
|
|
||||||
value.id = m_module.opIAdd(typeId, value.id, laneIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the result
|
// Store the result
|
||||||
emitRegisterStore(ins.dst[0], value);
|
emitRegisterStore(ins.dst[0], value);
|
||||||
}
|
}
|
||||||
|
@ -5584,12 +5517,12 @@ namespace dxvk {
|
||||||
result.type.ctype = DxbcScalarType::Uint32;
|
result.type.ctype = DxbcScalarType::Uint32;
|
||||||
result.type.ccount = 1;
|
result.type.ccount = 1;
|
||||||
|
|
||||||
if (info.image.sampled == 1) {
|
if (info.image.ms == 0 && info.image.sampled == 1) {
|
||||||
result.id = m_module.opImageQueryLevels(
|
result.id = m_module.opImageQueryLevels(
|
||||||
getVectorTypeId(result.type),
|
getVectorTypeId(result.type),
|
||||||
m_module.opLoad(info.typeId, info.varId));
|
m_module.opLoad(info.typeId, info.varId));
|
||||||
} else {
|
} else {
|
||||||
// Report one LOD in case of UAVs
|
// Report one LOD in case of UAVs or multisampled images
|
||||||
result.id = m_module.constu32(1);
|
result.id = m_module.constu32(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7799,6 +7732,21 @@ namespace dxvk {
|
||||||
return DxbcRegMask::firstN(getTexCoordDim(imageType));
|
return DxbcRegMask::firstN(getTexCoordDim(imageType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxbcCompiler::ignoreInputSystemValue(DxbcSystemValue sv) const {
|
||||||
|
switch (sv) {
|
||||||
|
case DxbcSystemValue::Position:
|
||||||
|
case DxbcSystemValue::IsFrontFace:
|
||||||
|
case DxbcSystemValue::SampleIndex:
|
||||||
|
case DxbcSystemValue::PrimitiveId:
|
||||||
|
case DxbcSystemValue::Coverage:
|
||||||
|
return m_programInfo.type() == DxbcProgramType::PixelShader;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DxbcVectorType DxbcCompiler::getInputRegType(uint32_t regIdx) const {
|
DxbcVectorType DxbcCompiler::getInputRegType(uint32_t regIdx) const {
|
||||||
switch (m_programInfo.type()) {
|
switch (m_programInfo.type()) {
|
||||||
|
@ -7829,8 +7777,25 @@ namespace dxvk {
|
||||||
result.ctype = DxbcScalarType::Float32;
|
result.ctype = DxbcScalarType::Float32;
|
||||||
result.ccount = 4;
|
result.ccount = 4;
|
||||||
|
|
||||||
if (m_isgn->findByRegister(regIdx))
|
if (m_isgn == nullptr || !m_isgn->findByRegister(regIdx))
|
||||||
result.ccount = m_isgn->regMask(regIdx).minComponents();
|
return result;
|
||||||
|
|
||||||
|
DxbcRegMask mask(0u);
|
||||||
|
DxbcRegMask used(0u);
|
||||||
|
|
||||||
|
for (const auto& e : *m_isgn) {
|
||||||
|
if (e.registerId == regIdx && !ignoreInputSystemValue(e.systemValue)) {
|
||||||
|
mask |= e.componentMask;
|
||||||
|
used |= e.componentUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_programInfo.type() == DxbcProgramType::PixelShader) {
|
||||||
|
if ((used.raw() & mask.raw()) == used.raw())
|
||||||
|
mask = used;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ccount = mask.minComponents();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1221,6 +1221,9 @@ namespace dxvk {
|
||||||
uint32_t getUavCoherence(
|
uint32_t getUavCoherence(
|
||||||
uint32_t registerId,
|
uint32_t registerId,
|
||||||
DxbcUavFlags flags);
|
DxbcUavFlags flags);
|
||||||
|
|
||||||
|
bool ignoreInputSystemValue(
|
||||||
|
DxbcSystemValue sv) const;
|
||||||
|
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
// Type definition methods
|
// Type definition methods
|
||||||
|
|
|
@ -17,9 +17,6 @@ namespace dxvk {
|
||||||
|
|
||||||
useDepthClipWorkaround
|
useDepthClipWorkaround
|
||||||
= !devFeatures.extDepthClipEnable.depthClipEnable;
|
= !devFeatures.extDepthClipEnable.depthClipEnable;
|
||||||
useSubgroupOpsForAtomicCounters
|
|
||||||
= (devInfo.vk11.subgroupSupportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
|
|
||||||
&& (devInfo.vk11.subgroupSupportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
|
|
||||||
|
|
||||||
VkFormatFeatureFlags2 r32Features
|
VkFormatFeatureFlags2 r32Features
|
||||||
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
|
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
|
||||||
|
@ -41,6 +38,7 @@ namespace dxvk {
|
||||||
disableMsaa = options.disableMsaa;
|
disableMsaa = options.disableMsaa;
|
||||||
forceSampleRateShading = options.forceSampleRateShading;
|
forceSampleRateShading = options.forceSampleRateShading;
|
||||||
enableSampleShadingInterlock = device->features().extFragmentShaderInterlock.fragmentShaderSampleInterlock;
|
enableSampleShadingInterlock = device->features().extFragmentShaderInterlock.fragmentShaderSampleInterlock;
|
||||||
|
longMad = options.longMad;
|
||||||
|
|
||||||
// Figure out float control flags to match D3D11 rules
|
// Figure out float control flags to match D3D11 rules
|
||||||
if (options.floatControls) {
|
if (options.floatControls) {
|
||||||
|
|
|
@ -30,10 +30,6 @@ namespace dxvk {
|
||||||
/// Determines whether raw access chains are supported
|
/// Determines whether raw access chains are supported
|
||||||
bool supportsRawAccessChains = false;
|
bool supportsRawAccessChains = false;
|
||||||
|
|
||||||
/// Use subgroup operations to reduce the number of
|
|
||||||
/// atomic operations for append/consume buffers.
|
|
||||||
bool useSubgroupOpsForAtomicCounters = false;
|
|
||||||
|
|
||||||
/// Clear thread-group shared memory to zero
|
/// Clear thread-group shared memory to zero
|
||||||
bool zeroInitWorkgroupMemory = false;
|
bool zeroInitWorkgroupMemory = false;
|
||||||
|
|
||||||
|
@ -58,6 +54,9 @@ namespace dxvk {
|
||||||
|
|
||||||
/// Minimum storage buffer alignment
|
/// Minimum storage buffer alignment
|
||||||
VkDeviceSize minSsboAlignment = 0;
|
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
|
// We can't really reconstruct the version numbers
|
||||||
// returned by Windows drivers from Vulkan data
|
// returned by Windows drivers from Vulkan data
|
||||||
if (SUCCEEDED(hr) && pUMDVersion)
|
if (SUCCEEDED(hr) && pUMDVersion)
|
||||||
pUMDVersion->QuadPart = ~0ull;
|
pUMDVersion->QuadPart = INT64_MAX;
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
|
Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
|
||||||
|
|
|
@ -124,13 +124,10 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If any monitors are left on the list, enable the
|
// If any monitors are left on the list, enable the
|
||||||
// fallback to always enumerate all monitors.
|
// fallback to always enumerate all monitors.
|
||||||
if ((m_monitorFallback = !monitors.empty()))
|
if ((m_monitorFallback = !monitors.empty()))
|
||||||
Logger::warn("DXGI: Found monitors not associated with any adapter, using fallback");
|
Logger::warn("DXGI: Found monitors not associated with any adapter, using fallback");
|
||||||
else
|
|
||||||
m_monitorFallback = m_options.useMonitorFallback;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,7 +230,7 @@ namespace dxvk {
|
||||||
descFs.Windowed = pDesc->Windowed;
|
descFs.Windowed = pDesc->Windowed;
|
||||||
|
|
||||||
IDXGISwapChain1* swapChain = nullptr;
|
IDXGISwapChain1* swapChain = nullptr;
|
||||||
HRESULT hr = CreateSwapChainForHwnd(
|
HRESULT hr = CreateSwapChainForHwndBase(
|
||||||
pDevice, pDesc->OutputWindow,
|
pDevice, pDesc->OutputWindow,
|
||||||
&desc, &descFs, nullptr,
|
&desc, &descFs, nullptr,
|
||||||
&swapChain);
|
&swapChain);
|
||||||
|
@ -247,6 +244,19 @@ namespace dxvk {
|
||||||
IUnknown* pDevice,
|
IUnknown* pDevice,
|
||||||
HWND hWnd,
|
HWND hWnd,
|
||||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
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,
|
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||||
IDXGIOutput* pRestrictToOutput,
|
IDXGIOutput* pRestrictToOutput,
|
||||||
IDXGISwapChain1** ppSwapChain) {
|
IDXGISwapChain1** ppSwapChain) {
|
||||||
|
|
|
@ -200,6 +200,14 @@ namespace dxvk {
|
||||||
UINT m_flags;
|
UINT m_flags;
|
||||||
BOOL m_monitorFallback;
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,21 @@ namespace dxvk {
|
||||||
return id;
|
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() {
|
static bool isNvapiEnabled() {
|
||||||
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
|
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
|
||||||
|
@ -95,15 +110,17 @@ namespace dxvk {
|
||||||
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
|
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
|
||||||
this->hideIntelGpu = config.getOption<Tristate>("dxgi.hideIntelGpu", 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");
|
this->enableHDR = config.getOption<bool>("dxgi.enableHDR", env::getEnvVar("DXVK_HDR") == "1");
|
||||||
if (this->enableHDR && isHDRDisallowed()) {
|
if (this->enableHDR && isHDRDisallowed()) {
|
||||||
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");
|
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");
|
||||||
this->enableHDR = false;
|
this->enableHDR = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->useMonitorFallback = config.getOption<bool>("dxgi.useMonitorFallback", env::getEnvVar("DXVK_MONITOR_FALLBACK") == "1");
|
|
||||||
if (this->useMonitorFallback)
|
|
||||||
Logger::info("Enabled useMonitorFallback option");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,6 @@ namespace dxvk {
|
||||||
/// Enable HDR
|
/// Enable HDR
|
||||||
bool enableHDR;
|
bool enableHDR;
|
||||||
|
|
||||||
/// Use monitor fallback to enumerating all monitors per output
|
|
||||||
bool useMonitorFallback;
|
|
||||||
|
|
||||||
/// Sync interval. Overrides the value
|
/// Sync interval. Overrides the value
|
||||||
/// passed to IDXGISwapChain::Present.
|
/// passed to IDXGISwapChain::Present.
|
||||||
int32_t syncInterval;
|
int32_t syncInterval;
|
||||||
|
|
|
@ -303,15 +303,22 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
||||||
return Present1(SyncInterval, Flags, nullptr);
|
return PresentBase(SyncInterval, Flags, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
||||||
UINT SyncInterval,
|
UINT SyncInterval,
|
||||||
UINT PresentFlags,
|
UINT PresentFlags,
|
||||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
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)
|
if (SyncInterval > 4)
|
||||||
return DXGI_ERROR_INVALID_CALL;
|
return DXGI_ERROR_INVALID_CALL;
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,10 @@ namespace dxvk {
|
||||||
DXGI_FORMAT Format,
|
DXGI_FORMAT Format,
|
||||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
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')
|
dxgi_link_depends += files('dxgi.sym')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res,
|
dxgi_dll = shared_library(dxvk_name_prefix+'dxgi', dxgi_src, dxgi_res,
|
||||||
name_prefix : dxvk_name_prefix,
|
|
||||||
dependencies : [ dxvk_dep ],
|
dependencies : [ dxvk_dep ],
|
||||||
include_directories : dxvk_include_path,
|
include_directories : dxvk_include_path,
|
||||||
install : true,
|
install : true,
|
||||||
vs_module_defs : 'dxgi'+def_spec_ext,
|
vs_module_defs : 'dxgi'+def_spec_ext,
|
||||||
link_args : dxgi_ld_args,
|
link_args : dxgi_ld_args,
|
||||||
link_depends : [ dxgi_link_depends ],
|
link_depends : [ dxgi_link_depends ],
|
||||||
|
kwargs : dxvk_so_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
dxgi_dep = declare_dependency(
|
dxgi_dep = declare_dependency(
|
||||||
link_with : [ dxgi_dll ],
|
link_with : [ dxgi_dll ],
|
||||||
include_directories : [ dxvk_include_path ],
|
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.bindings = m_bindings.data();
|
||||||
info.inputMask = m_inputMask;
|
info.inputMask = m_inputMask;
|
||||||
info.outputMask = m_outputMask;
|
info.outputMask = m_outputMask;
|
||||||
info.pushConstOffset = m_pushConstOffset;
|
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
info.pushConstSize = m_pushConstSize;
|
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||||
|
|
||||||
if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
|
if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
|
||||||
info.flatShadingInputs = m_ps.flatShadingMask;
|
info.flatShadingInputs = m_ps.flatShadingMask;
|
||||||
|
@ -3561,30 +3561,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
|
||||||
|
|
||||||
|
|
||||||
void DxsoCompiler::setupRenderStateInfo() {
|
void DxsoCompiler::setupRenderStateInfo() {
|
||||||
uint32_t count;
|
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -344,8 +344,6 @@ namespace dxvk {
|
||||||
// covers vertex input and fragment output.
|
// covers vertex input and fragment output.
|
||||||
uint32_t m_inputMask = 0u;
|
uint32_t m_inputMask = 0u;
|
||||||
uint32_t m_outputMask = 0u;
|
uint32_t m_outputMask = 0u;
|
||||||
uint32_t m_pushConstOffset = 0u;
|
|
||||||
uint32_t m_pushConstSize = 0u;
|
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
// Shader-specific data structures
|
// Shader-specific data structures
|
||||||
|
|
|
@ -346,6 +346,11 @@ namespace dxvk {
|
||||||
enabledFeatures.vk13.synchronization2 = VK_TRUE;
|
enabledFeatures.vk13.synchronization2 = VK_TRUE;
|
||||||
enabledFeatures.vk13.dynamicRendering = 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
|
// We expose depth clip rather than depth clamp to client APIs
|
||||||
enabledFeatures.extDepthClipEnable.depthClipEnable =
|
enabledFeatures.extDepthClipEnable.depthClipEnable =
|
||||||
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
|
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
|
||||||
|
@ -410,11 +415,15 @@ namespace dxvk {
|
||||||
m_deviceFeatures.khrPresentWait.presentWait;
|
m_deviceFeatures.khrPresentWait.presentWait;
|
||||||
|
|
||||||
// Unless we're on an Nvidia driver where these extensions are known to be broken
|
// 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.khrPresentId.presentId = VK_FALSE;
|
||||||
enabledFeatures.khrPresentWait.presentWait = 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
|
// Enable raw access chains for shader backends
|
||||||
enabledFeatures.nvRawAccessChains.shaderRawAccessChains =
|
enabledFeatures.nvRawAccessChains.shaderRawAccessChains =
|
||||||
m_deviceFeatures.nvRawAccessChains.shaderRawAccessChains;
|
m_deviceFeatures.nvRawAccessChains.shaderRawAccessChains;
|
||||||
|
@ -425,10 +434,7 @@ namespace dxvk {
|
||||||
// Log feature support info an extension list
|
// Log feature support info an extension list
|
||||||
Logger::info(str::format("Device properties:"
|
Logger::info(str::format("Device properties:"
|
||||||
"\n Device : ", m_deviceInfo.core.properties.deviceName,
|
"\n Device : ", m_deviceInfo.core.properties.deviceName,
|
||||||
"\n Driver : ", m_deviceInfo.vk12.driverName, " ",
|
"\n Driver : ", m_deviceInfo.vk12.driverName, " ", m_deviceInfo.driverVersion.toString()));
|
||||||
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
|
|
||||||
|
|
||||||
Logger::info("Enabled device extensions:");
|
Logger::info("Enabled device extensions:");
|
||||||
this->logNameList(extensionNameList);
|
this->logNameList(extensionNameList);
|
||||||
|
@ -610,6 +616,10 @@ namespace dxvk {
|
||||||
enabledFeatures.khrPresentWait = *reinterpret_cast<const VkPhysicalDevicePresentWaitFeaturesKHR*>(f);
|
enabledFeatures.khrPresentWait = *reinterpret_cast<const VkPhysicalDevicePresentWaitFeaturesKHR*>(f);
|
||||||
break;
|
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:
|
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV:
|
||||||
enabledFeatures.nvRawAccessChains = *reinterpret_cast<const VkPhysicalDeviceRawAccessChainsFeaturesNV*>(f);
|
enabledFeatures.nvRawAccessChains = *reinterpret_cast<const VkPhysicalDeviceRawAccessChainsFeaturesNV*>(f);
|
||||||
break;
|
break;
|
||||||
|
@ -626,9 +636,7 @@ namespace dxvk {
|
||||||
Logger::info(str::format("Device properties:"
|
Logger::info(str::format("Device properties:"
|
||||||
"\n Device name: ", m_deviceInfo.core.properties.deviceName,
|
"\n Device name: ", m_deviceInfo.core.properties.deviceName,
|
||||||
"\n Driver: ", m_deviceInfo.vk12.driverName, " ",
|
"\n Driver: ", m_deviceInfo.vk12.driverName, " ",
|
||||||
VK_VERSION_MAJOR(m_deviceInfo.core.properties.driverVersion), ".",
|
m_deviceInfo.driverVersion.toString()));
|
||||||
VK_VERSION_MINOR(m_deviceInfo.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_PATCH(m_deviceInfo.core.properties.driverVersion)));
|
|
||||||
|
|
||||||
Logger::info("Enabled device extensions:");
|
Logger::info("Enabled device extensions:");
|
||||||
this->logNameList(extensionNameList);
|
this->logNameList(extensionNameList);
|
||||||
|
@ -664,26 +672,29 @@ namespace dxvk {
|
||||||
|
|
||||||
bool DxvkAdapter::matchesDriver(
|
bool DxvkAdapter::matchesDriver(
|
||||||
VkDriverIdKHR driver,
|
VkDriverIdKHR driver,
|
||||||
uint32_t minVer,
|
Version minVer,
|
||||||
uint32_t maxVer) const {
|
Version maxVer) const {
|
||||||
bool driverMatches = driver == m_deviceInfo.vk12.driverID;
|
bool driverMatches = driver == m_deviceInfo.vk12.driverID;
|
||||||
|
|
||||||
if (minVer) driverMatches &= m_deviceInfo.core.properties.driverVersion >= minVer;
|
if (minVer) driverMatches &= m_deviceInfo.driverVersion >= minVer;
|
||||||
if (maxVer) driverMatches &= m_deviceInfo.core.properties.driverVersion < maxVer;
|
if (maxVer) driverMatches &= m_deviceInfo.driverVersion < maxVer;
|
||||||
|
|
||||||
return driverMatches;
|
return driverMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkAdapter::matchesDriver(
|
||||||
|
VkDriverIdKHR driver) const {
|
||||||
|
return driver == m_deviceInfo.vk12.driverID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkAdapter::logAdapterInfo() const {
|
void DxvkAdapter::logAdapterInfo() const {
|
||||||
const auto deviceInfo = this->devicePropertiesExt();
|
const auto deviceInfo = this->devicePropertiesExt();
|
||||||
const auto memoryInfo = this->memoryProperties();
|
const auto memoryInfo = this->memoryProperties();
|
||||||
|
|
||||||
Logger::info(str::format(deviceInfo.core.properties.deviceName, ":",
|
Logger::info(str::format(deviceInfo.core.properties.deviceName, ":",
|
||||||
"\n Driver : ", deviceInfo.vk12.driverName, " ",
|
"\n Driver : ", deviceInfo.vk12.driverName, " ", deviceInfo.driverVersion.toString()));
|
||||||
VK_VERSION_MAJOR(deviceInfo.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_MINOR(deviceInfo.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_PATCH(deviceInfo.core.properties.driverVersion)));
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < memoryInfo.memoryHeapCount; i++) {
|
for (uint32_t i = 0; i < memoryInfo.memoryHeapCount; i++) {
|
||||||
constexpr VkDeviceSize mib = 1024 * 1024;
|
constexpr VkDeviceSize mib = 1024 * 1024;
|
||||||
|
@ -785,22 +796,8 @@ namespace dxvk {
|
||||||
m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
|
m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
|
||||||
|
|
||||||
// Some drivers reports the driver version in a slightly different format
|
// Some drivers reports the driver version in a slightly different format
|
||||||
switch (m_deviceInfo.vk12.driverID) {
|
m_deviceInfo.driverVersion = decodeDriverVersion(
|
||||||
case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
|
m_deviceInfo.vk12.driverID, m_deviceInfo.core.properties.driverVersion);
|
||||||
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:;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -935,6 +932,11 @@ namespace dxvk {
|
||||||
m_deviceFeatures.khrPresentWait.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrPresentWait);
|
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)) {
|
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.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
|
||||||
m_deviceFeatures.nvRawAccessChains.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvRawAccessChains);
|
m_deviceFeatures.nvRawAccessChains.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvRawAccessChains);
|
||||||
|
@ -1007,6 +1009,7 @@ namespace dxvk {
|
||||||
&devExtensions.khrPresentWait,
|
&devExtensions.khrPresentWait,
|
||||||
&devExtensions.khrSwapchain,
|
&devExtensions.khrSwapchain,
|
||||||
&devExtensions.khrWin32KeyedMutex,
|
&devExtensions.khrWin32KeyedMutex,
|
||||||
|
&devExtensions.nvDescriptorPoolOverallocation,
|
||||||
&devExtensions.nvRawAccessChains,
|
&devExtensions.nvRawAccessChains,
|
||||||
&devExtensions.nvxBinaryImport,
|
&devExtensions.nvxBinaryImport,
|
||||||
&devExtensions.nvxImageViewHandle,
|
&devExtensions.nvxImageViewHandle,
|
||||||
|
@ -1147,6 +1150,11 @@ namespace dxvk {
|
||||||
enabledFeatures.khrPresentWait.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrPresentWait);
|
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) {
|
if (devExtensions.nvRawAccessChains) {
|
||||||
enabledFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
|
enabledFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
|
||||||
enabledFeatures.nvRawAccessChains.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvRawAccessChains);
|
enabledFeatures.nvRawAccessChains.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvRawAccessChains);
|
||||||
|
@ -1298,6 +1306,8 @@ namespace dxvk {
|
||||||
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
|
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
|
||||||
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
||||||
"\n presentWait : ", features.khrPresentWait.presentWait ? "1" : "0",
|
"\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", VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME,
|
||||||
"\n shaderRawAccessChains : ", features.nvRawAccessChains.shaderRawAccessChains ? "1" : "0",
|
"\n shaderRawAccessChains : ", features.nvRawAccessChains.shaderRawAccessChains ? "1" : "0",
|
||||||
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
|
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
|
||||||
|
@ -1316,4 +1326,25 @@ namespace dxvk {
|
||||||
"\n Sparse : ", queues.sparse != VK_QUEUE_FAMILY_IGNORED ? str::format(queues.sparse) : "n/a"));
|
"\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(
|
bool matchesDriver(
|
||||||
VkDriverIdKHR driver,
|
VkDriverIdKHR driver,
|
||||||
uint32_t minVer,
|
Version minVer,
|
||||||
uint32_t maxVer) const;
|
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
|
* \brief Logs DXVK adapter info
|
||||||
|
@ -343,6 +352,8 @@ namespace dxvk {
|
||||||
static void logFeatures(const DxvkDeviceFeatures& features);
|
static void logFeatures(const DxvkDeviceFeatures& features);
|
||||||
static void logQueueFamilies(const DxvkAdapterQueueIndices& queues);
|
static void logQueueFamilies(const DxvkAdapterQueueIndices& queues);
|
||||||
|
|
||||||
|
static Version decodeDriverVersion(VkDriverId driverId, uint32_t version);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,7 @@ namespace dxvk {
|
||||||
// Retrieve actual pipeline handle on first use. This
|
// Retrieve actual pipeline handle on first use. This
|
||||||
// may wait for an ongoing compile job to finish, or
|
// may wait for an ongoing compile job to finish, or
|
||||||
// compile the pipeline immediately on the calling thread.
|
// compile the pipeline immediately on the calling thread.
|
||||||
m_libraryHandle = m_library->acquirePipelineHandle(
|
m_libraryHandle = m_library->acquirePipelineHandle().handle;
|
||||||
DxvkShaderPipelineLibraryCompileArgs());
|
|
||||||
|
|
||||||
return m_libraryHandle;
|
return m_libraryHandle;
|
||||||
} else {
|
} else {
|
||||||
// Slow path for compute shaders that do use spec constants
|
// Slow path for compute shaders that do use spec constants
|
||||||
|
|
|
@ -1997,7 +1997,7 @@ namespace dxvk {
|
||||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
|
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
depthOp.loadLayout = imageView->imageInfo().layout;
|
depthOp.loadLayout = imageView->imageInfo().layout;
|
||||||
depthOp.storeLayout = imageView->imageInfo().layout;
|
depthOp.storeLayout = imageView->imageInfo().layout;
|
||||||
|
|
||||||
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
@ -2010,7 +2010,7 @@ namespace dxvk {
|
||||||
|
|
||||||
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
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;
|
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
|
||||||
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
|
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
|
||||||
|
@ -2041,6 +2041,8 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachmentIndex < 0) {
|
if (attachmentIndex < 0) {
|
||||||
|
bool hasViewFormatMismatch = imageView->info().format != imageView->imageInfo().format;
|
||||||
|
|
||||||
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
|
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
|
||||||
m_execBarriers.recordCommands(m_cmd);
|
m_execBarriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
|
@ -2075,6 +2077,11 @@ namespace dxvk {
|
||||||
|
|
||||||
attachmentInfo.loadOp = colorOp.loadOp;
|
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.colorAttachmentCount = 1;
|
||||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||||
|
|
||||||
|
@ -2110,6 +2117,20 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
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_cmd->cmdEndRendering();
|
||||||
|
|
||||||
m_execBarriers.accessImage(
|
m_execBarriers.accessImage(
|
||||||
|
@ -4741,8 +4762,10 @@ namespace dxvk {
|
||||||
this->renderPassEmitPostBarriers(framebufferInfo, ops);
|
this->renderPassEmitPostBarriers(framebufferInfo, ops);
|
||||||
|
|
||||||
uint32_t colorInfoCount = 0;
|
uint32_t colorInfoCount = 0;
|
||||||
|
uint32_t lateClearCount = 0;
|
||||||
|
|
||||||
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
|
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
|
||||||
|
std::array<VkClearAttachment, MaxNumRenderTargets> lateClears;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||||
const auto& colorTarget = framebufferInfo.getColorTarget(i);
|
const auto& colorTarget = framebufferInfo.getColorTarget(i);
|
||||||
|
@ -4754,9 +4777,21 @@ namespace dxvk {
|
||||||
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
|
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
|
||||||
colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
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;
|
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;
|
colorInfoCount = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4804,6 +4839,15 @@ namespace dxvk {
|
||||||
|
|
||||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
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++) {
|
for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) {
|
||||||
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
|
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
|
||||||
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
|
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
|
||||||
|
@ -4940,7 +4984,7 @@ namespace dxvk {
|
||||||
// Mark compute resources and push constants as dirty
|
// Mark compute resources and push constants as dirty
|
||||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT);
|
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.set(DxvkContextFlag::DirtyPushConstants);
|
||||||
|
|
||||||
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
|
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
|
||||||
|
@ -5014,7 +5058,7 @@ namespace dxvk {
|
||||||
|
|
||||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS);
|
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.set(DxvkContextFlag::DirtyPushConstants);
|
||||||
|
|
||||||
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
||||||
|
@ -5881,16 +5925,19 @@ namespace dxvk {
|
||||||
auto bindings = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
auto bindings = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
||||||
? m_state.gp.pipeline->getBindings()
|
? m_state.gp.pipeline->getBindings()
|
||||||
: m_state.cp.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)
|
if (!pushConstRange.size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Push constants should be compatible between complete and
|
|
||||||
// independent layouts, so always ask for the complete one
|
|
||||||
m_cmd->cmdPushConstants(
|
m_cmd->cmdPushConstants(
|
||||||
bindings->getPipelineLayout(false),
|
bindings->getPipelineLayout(independentSets),
|
||||||
pushConstRange.stageFlags,
|
pushConstRange.stageFlags,
|
||||||
pushConstRange.offset,
|
pushConstRange.offset,
|
||||||
pushConstRange.size,
|
pushConstRange.size,
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace dxvk {
|
||||||
// memory bloat. This may be necessary for off-screen
|
// memory bloat. This may be necessary for off-screen
|
||||||
// rendering applications, or in situations where games
|
// rendering applications, or in situations where games
|
||||||
// pre-render a lot of images without presenting in between.
|
// 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() {
|
void DxvkDescriptorPool::reset() {
|
||||||
// As a heuristic to save memory, check how many descriptors
|
// As a heuristic to save memory, check how many descriptor
|
||||||
// have actively been used in the past couple of submissions.
|
// sets were actually being used in past submissions.
|
||||||
bool isLowUsageFrame = false;
|
|
||||||
|
|
||||||
size_t poolCount = m_descriptorPools.size();
|
size_t poolCount = m_descriptorPools.size();
|
||||||
|
bool needsReset = poolCount > MaxDesiredPoolCount;
|
||||||
|
|
||||||
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
|
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
|
||||||
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
|
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;
|
m_setsUsed = 0;
|
||||||
|
|
||||||
if (m_lowUsageFrames < 16) {
|
if (!needsReset) {
|
||||||
for (auto& entry : m_setLists)
|
for (auto& entry : m_setLists)
|
||||||
entry.second.reset();
|
entry.second.reset();
|
||||||
} else {
|
} else {
|
||||||
// If most sets are no longer being used, reset and destroy
|
// If most sets are no longer needed, reset and destroy
|
||||||
// descriptor pools and reset all lookup tables in order to
|
// descriptor pools and reset all lookup tables in order
|
||||||
// accomodate more descriptors of different layouts.
|
// to accomodate more descriptors of different layouts.
|
||||||
for (auto pool : m_descriptorPools)
|
for (auto pool : m_descriptorPools)
|
||||||
m_manager->recycleVulkanDescriptorPool(pool);
|
m_manager->recycleVulkanDescriptorPool(pool);
|
||||||
|
|
||||||
|
@ -131,7 +127,6 @@ namespace dxvk {
|
||||||
m_setMaps.clear();
|
m_setMaps.clear();
|
||||||
|
|
||||||
m_setsAllocated = 0;
|
m_setsAllocated = 0;
|
||||||
m_lowUsageFrames = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cachedEntry = { nullptr, nullptr };
|
m_cachedEntry = { nullptr, nullptr };
|
||||||
|
@ -311,7 +306,12 @@ namespace dxvk {
|
||||||
info.maxSets = m_maxSets;
|
info.maxSets = m_maxSets;
|
||||||
info.poolSizeCount = pools.size();
|
info.poolSizeCount = pools.size();
|
||||||
info.pPoolSizes = pools.data();
|
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;
|
VkDescriptorPool pool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (vk->vkCreateDescriptorPool(vk->device(), &info, nullptr, &pool) != VK_SUCCESS)
|
if (vk->vkCreateDescriptorPool(vk->device(), &info, nullptr, &pool) != VK_SUCCESS)
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace dxvk {
|
||||||
* to be updated.
|
* to be updated.
|
||||||
*/
|
*/
|
||||||
class DxvkDescriptorPool : public RcObject {
|
class DxvkDescriptorPool : public RcObject {
|
||||||
|
constexpr static uint32_t MaxDesiredPoolCount = 2;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkDescriptorPool(
|
DxvkDescriptorPool(
|
||||||
|
@ -155,8 +155,6 @@ namespace dxvk {
|
||||||
|
|
||||||
uint32_t m_prevSetsAllocated = 0;
|
uint32_t m_prevSetsAllocated = 0;
|
||||||
|
|
||||||
uint32_t m_lowUsageFrames = 0;
|
|
||||||
|
|
||||||
DxvkDescriptorSetMap* getSetMapCached(
|
DxvkDescriptorSetMap* getSetMapCached(
|
||||||
const DxvkBindingLayoutObjects* layout);
|
const DxvkBindingLayoutObjects* layout);
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace dxvk {
|
||||||
|
|
||||||
// Disable lifetime tracking for drivers that do not have any
|
// Disable lifetime tracking for drivers that do not have any
|
||||||
// significant issues with 32-bit address space to begin with
|
// 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 false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -325,12 +325,12 @@ namespace dxvk {
|
||||||
DxvkDevicePerfHints DxvkDevice::getPerfHints() {
|
DxvkDevicePerfHints DxvkDevice::getPerfHints() {
|
||||||
DxvkDevicePerfHints hints;
|
DxvkDevicePerfHints hints;
|
||||||
hints.preferFbDepthStencilCopy = m_features.extShaderStencilExport
|
hints.preferFbDepthStencilCopy = m_features.extShaderStencilExport
|
||||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR, 0, 0)
|
&& (m_adapter->matchesDriver(VK_DRIVER_ID_MESA_RADV_KHR)
|
||||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|
||||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
|
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
|
||||||
hints.preferFbResolve = m_features.amdShaderFragmentMask
|
hints.preferFbResolve = m_features.amdShaderFragmentMask
|
||||||
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0)
|
&& (m_adapter->matchesDriver(VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR)
|
||||||
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0));
|
|| m_adapter->matchesDriver(VK_DRIVER_ID_AMD_PROPRIETARY_KHR));
|
||||||
return hints;
|
return hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
bool DxvkDeviceFilter::testAdapter(const VkPhysicalDeviceProperties& properties) const {
|
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 ",
|
Logger::warn(str::format("Skipping Vulkan ",
|
||||||
VK_VERSION_MAJOR(properties.apiVersion), ".",
|
VK_API_VERSION_MAJOR(properties.apiVersion), ".",
|
||||||
VK_VERSION_MINOR(properties.apiVersion), " adapter: ",
|
VK_API_VERSION_MINOR(properties.apiVersion), " adapter: ",
|
||||||
properties.deviceName));
|
properties.deviceName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "dxvk_include.h"
|
#include "dxvk_include.h"
|
||||||
|
|
||||||
|
#include "../util/util_version.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +15,7 @@ namespace dxvk {
|
||||||
* so before using them, check whether they are supported.
|
* so before using them, check whether they are supported.
|
||||||
*/
|
*/
|
||||||
struct DxvkDeviceInfo {
|
struct DxvkDeviceInfo {
|
||||||
|
Version driverVersion;
|
||||||
VkPhysicalDeviceProperties2 core;
|
VkPhysicalDeviceProperties2 core;
|
||||||
VkPhysicalDeviceVulkan11Properties vk11;
|
VkPhysicalDeviceVulkan11Properties vk11;
|
||||||
VkPhysicalDeviceVulkan12Properties vk12;
|
VkPhysicalDeviceVulkan12Properties vk12;
|
||||||
|
@ -68,6 +71,7 @@ namespace dxvk {
|
||||||
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
|
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
|
||||||
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
|
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
|
||||||
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
|
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
|
||||||
|
VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV nvDescriptorPoolOverallocation;
|
||||||
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
|
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
|
||||||
VkBool32 nvxBinaryImport;
|
VkBool32 nvxBinaryImport;
|
||||||
VkBool32 nvxImageViewHandle;
|
VkBool32 nvxImageViewHandle;
|
||||||
|
|
|
@ -325,6 +325,7 @@ namespace dxvk {
|
||||||
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
|
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||||
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
|
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
|
||||||
DxvkExt khrWin32KeyedMutex = { VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, DxvkExtMode::Optional };
|
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 nvRawAccessChains = { VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME, DxvkExtMode::Optional };
|
||||||
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
|
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
|
||||||
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
|
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
|
||||||
|
|
|
@ -1111,7 +1111,9 @@ namespace dxvk {
|
||||||
|
|
||||||
if (doCreateBasePipeline)
|
if (doCreateBasePipeline)
|
||||||
baseHandle = this->getBasePipeline(state);
|
baseHandle = this->getBasePipeline(state);
|
||||||
else
|
|
||||||
|
// Fast-linking may fail in some situations
|
||||||
|
if (!baseHandle)
|
||||||
fastHandle = this->getOptimizedPipeline(state);
|
fastHandle = this->getOptimizedPipeline(state);
|
||||||
|
|
||||||
// Log pipeline state if requested, or on failure
|
// Log pipeline state if requested, or on failure
|
||||||
|
@ -1148,6 +1150,13 @@ namespace dxvk {
|
||||||
|| (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering))
|
|| (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering))
|
||||||
return false;
|
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 (m_shaders.tcs != nullptr) {
|
||||||
// If tessellation shaders are present, the input patch
|
// If tessellation shaders are present, the input patch
|
||||||
// vertex count must match the shader's definition.
|
// vertex count must match the shader's definition.
|
||||||
|
@ -1219,9 +1228,6 @@ namespace dxvk {
|
||||||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
||||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
||||||
|
|
||||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable)
|
|
||||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
|
||||||
|
|
||||||
auto entry = m_basePipelines.find(key);
|
auto entry = m_basePipelines.find(key);
|
||||||
if (entry != m_basePipelines.end())
|
if (entry != m_basePipelines.end())
|
||||||
return entry->second;
|
return entry->second;
|
||||||
|
@ -1236,10 +1242,11 @@ namespace dxvk {
|
||||||
const DxvkGraphicsPipelineBaseInstanceKey& key) const {
|
const DxvkGraphicsPipelineBaseInstanceKey& key) const {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle();
|
||||||
|
DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle();
|
||||||
|
|
||||||
std::array<VkPipeline, 4> libraries = {{
|
std::array<VkPipeline, 4> libraries = {{
|
||||||
key.viLibrary->getHandle(),
|
key.viLibrary->getHandle(), vs.handle, fs.handle,
|
||||||
m_vsLibrary->acquirePipelineHandle(key.args),
|
|
||||||
m_fsLibrary->acquirePipelineHandle(key.args),
|
|
||||||
key.foLibrary->getHandle(),
|
key.foLibrary->getHandle(),
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
@ -1248,13 +1255,14 @@ namespace dxvk {
|
||||||
libInfo.pLibraries = libraries.data();
|
libInfo.pLibraries = libraries.data();
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
||||||
|
info.flags = vs.linkFlags | fs.linkFlags;
|
||||||
info.layout = m_bindings->getPipelineLayout(true);
|
info.layout = m_bindings->getPipelineLayout(true);
|
||||||
info.basePipelineIndex = -1;
|
info.basePipelineIndex = -1;
|
||||||
|
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
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));
|
Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr));
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
|
|
|
@ -381,19 +381,16 @@ namespace dxvk {
|
||||||
struct DxvkGraphicsPipelineBaseInstanceKey {
|
struct DxvkGraphicsPipelineBaseInstanceKey {
|
||||||
const DxvkGraphicsPipelineVertexInputLibrary* viLibrary = nullptr;
|
const DxvkGraphicsPipelineVertexInputLibrary* viLibrary = nullptr;
|
||||||
const DxvkGraphicsPipelineFragmentOutputLibrary* foLibrary = nullptr;
|
const DxvkGraphicsPipelineFragmentOutputLibrary* foLibrary = nullptr;
|
||||||
DxvkShaderPipelineLibraryCompileArgs args;
|
|
||||||
|
|
||||||
bool eq(const DxvkGraphicsPipelineBaseInstanceKey& other) const {
|
bool eq(const DxvkGraphicsPipelineBaseInstanceKey& other) const {
|
||||||
return viLibrary == other.viLibrary
|
return viLibrary == other.viLibrary
|
||||||
&& foLibrary == other.foLibrary
|
&& foLibrary == other.foLibrary;
|
||||||
&& args == other.args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash() const {
|
size_t hash() const {
|
||||||
DxvkHashState hash;
|
DxvkHashState hash;
|
||||||
hash.add(size_t(viLibrary));
|
hash.add(size_t(viLibrary));
|
||||||
hash.add(size_t(foLibrary));
|
hash.add(size_t(foLibrary));
|
||||||
hash.add(args.hash());
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "dxvk_openvr.h"
|
#include "dxvk_openvr.h"
|
||||||
#include "dxvk_openxr.h"
|
#include "dxvk_openxr.h"
|
||||||
#include "dxvk_platform_exts.h"
|
#include "dxvk_platform_exts.h"
|
||||||
|
#include "../wsi/wsi_platform.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -20,6 +21,8 @@ namespace dxvk {
|
||||||
Logger::info(str::format("Game: ", env::getExeName()));
|
Logger::info(str::format("Game: ", env::getExeName()));
|
||||||
Logger::info(str::format("DXVK: ", DXVK_VERSION));
|
Logger::info(str::format("DXVK: ", DXVK_VERSION));
|
||||||
|
|
||||||
|
wsi::init();
|
||||||
|
|
||||||
m_config = Config::getUserConfig();
|
m_config = Config::getUserConfig();
|
||||||
m_config.merge(Config::getAppConfig(env::getExePath()));
|
m_config.merge(Config::getAppConfig(env::getExePath()));
|
||||||
m_config.logOptions();
|
m_config.logOptions();
|
||||||
|
@ -64,6 +67,8 @@ namespace dxvk {
|
||||||
DxvkInstance::~DxvkInstance() {
|
DxvkInstance::~DxvkInstance() {
|
||||||
if (m_messenger)
|
if (m_messenger)
|
||||||
m_vki->vkDestroyDebugUtilsMessengerEXT(m_vki->instance(), m_messenger, nullptr);
|
m_vki->vkDestroyDebugUtilsMessengerEXT(m_vki->instance(), m_messenger, nullptr);
|
||||||
|
|
||||||
|
wsi::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,8 +182,8 @@ namespace dxvk {
|
||||||
appInfo.pApplicationName = appName.c_str();
|
appInfo.pApplicationName = appName.c_str();
|
||||||
appInfo.applicationVersion = flags.raw();
|
appInfo.applicationVersion = flags.raw();
|
||||||
appInfo.pEngineName = "DXVK";
|
appInfo.pEngineName = "DXVK";
|
||||||
appInfo.engineVersion = VK_MAKE_VERSION(2, 3, 1);
|
appInfo.engineVersion = VK_MAKE_API_VERSION(0, 2, 3, 2);
|
||||||
appInfo.apiVersion = VK_MAKE_VERSION(1, 3, 0);
|
appInfo.apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0);
|
||||||
|
|
||||||
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
|
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
|
||||||
info.pApplicationInfo = &appInfo;
|
info.pApplicationInfo = &appInfo;
|
||||||
|
|
|
@ -205,7 +205,7 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
DxvkBindingLayout::DxvkBindingLayout(VkShaderStageFlags stages)
|
DxvkBindingLayout::DxvkBindingLayout(VkShaderStageFlags stages)
|
||||||
: m_pushConst { 0, 0, 0 }, m_stages(stages) {
|
: m_pushConst { 0, 0, 0 }, m_pushConstStages(0), m_stages(stages) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,11 +249,17 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingLayout::addPushConstantStage(VkShaderStageFlagBits stage) {
|
||||||
|
m_pushConstStages |= stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkBindingLayout::merge(const DxvkBindingLayout& layout) {
|
void DxvkBindingLayout::merge(const DxvkBindingLayout& layout) {
|
||||||
for (uint32_t i = 0; i < layout.m_bindings.size(); i++)
|
for (uint32_t i = 0; i < layout.m_bindings.size(); i++)
|
||||||
m_bindings[i].merge(layout.m_bindings[i]);
|
m_bindings[i].merge(layout.m_bindings[i]);
|
||||||
|
|
||||||
addPushConstantRange(layout.m_pushConst);
|
addPushConstantRange(layout.m_pushConst);
|
||||||
|
m_pushConstStages |= layout.m_pushConstStages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,6 +272,9 @@ namespace dxvk {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pushConstStages != other.m_pushConstStages)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (m_pushConst.stageFlags != other.m_pushConst.stageFlags
|
if (m_pushConst.stageFlags != other.m_pushConst.stageFlags
|
||||||
|| m_pushConst.offset != other.m_pushConst.offset
|
|| m_pushConst.offset != other.m_pushConst.offset
|
||||||
|| m_pushConst.size != other.m_pushConst.size)
|
|| m_pushConst.size != other.m_pushConst.size)
|
||||||
|
@ -282,6 +291,7 @@ namespace dxvk {
|
||||||
for (uint32_t i = 0; i < m_bindings.size(); i++)
|
for (uint32_t i = 0; i < m_bindings.size(); i++)
|
||||||
hash.add(m_bindings[i].hash());
|
hash.add(m_bindings[i].hash());
|
||||||
|
|
||||||
|
hash.add(m_pushConstStages);
|
||||||
hash.add(m_pushConst.stageFlags);
|
hash.add(m_pushConst.stageFlags);
|
||||||
hash.add(m_pushConst.offset);
|
hash.add(m_pushConst.offset);
|
||||||
hash.add(m_pushConst.size);
|
hash.add(m_pushConst.size);
|
||||||
|
@ -334,15 +344,16 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create pipeline layout objects
|
// Create pipeline layout objects
|
||||||
VkPushConstantRange pushConst = m_layout.getPushConstantRange();
|
VkPushConstantRange pushConstComplete = m_layout.getPushConstantRange(false);
|
||||||
|
VkPushConstantRange pushConstIndependent = m_layout.getPushConstantRange(true);
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
||||||
pipelineLayoutInfo.setLayoutCount = setCount;
|
pipelineLayoutInfo.setLayoutCount = setCount;
|
||||||
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
|
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
|
||||||
|
|
||||||
if (pushConst.stageFlags && pushConst.size) {
|
if (pushConstComplete.stageFlags && pushConstComplete.size) {
|
||||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutInfo.pPushConstantRanges = &pushConst;
|
pipelineLayoutInfo.pPushConstantRanges = &pushConstComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the full set is defined, create a layout without INDEPENDENT_SET_BITS
|
// If the full set is defined, create a layout without INDEPENDENT_SET_BITS
|
||||||
|
@ -356,6 +367,11 @@ namespace dxvk {
|
||||||
if (m_device->canUseGraphicsPipelineLibrary() && (m_layout.getStages() & VK_SHADER_STAGE_ALL_GRAPHICS)) {
|
if (m_device->canUseGraphicsPipelineLibrary() && (m_layout.getStages() & VK_SHADER_STAGE_ALL_GRAPHICS)) {
|
||||||
pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
|
pipelineLayoutInfo.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
|
||||||
|
|
||||||
|
if (pushConstIndependent.stageFlags && pushConstIndependent.size) {
|
||||||
|
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutInfo.pPushConstantRanges = &pushConstIndependent;
|
||||||
|
}
|
||||||
|
|
||||||
if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_independentLayout))
|
if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_independentLayout))
|
||||||
throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout");
|
throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout");
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,8 +292,19 @@ namespace dxvk {
|
||||||
* \brief Retrieves push constant range
|
* \brief Retrieves push constant range
|
||||||
* \returns Push constant range
|
* \returns Push constant range
|
||||||
*/
|
*/
|
||||||
VkPushConstantRange getPushConstantRange() const {
|
VkPushConstantRange getPushConstantRange(bool independent) const {
|
||||||
return m_pushConst;
|
VkPushConstantRange result = m_pushConst;
|
||||||
|
|
||||||
|
if (!independent) {
|
||||||
|
result.stageFlags &= m_pushConstStages;
|
||||||
|
|
||||||
|
if (!result.stageFlags) {
|
||||||
|
result.offset = 0;
|
||||||
|
result.size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -324,6 +335,12 @@ namespace dxvk {
|
||||||
*/
|
*/
|
||||||
void addPushConstantRange(VkPushConstantRange range);
|
void addPushConstantRange(VkPushConstantRange range);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds a stage that actively uses push constants
|
||||||
|
* \param [in] stage Shader stage
|
||||||
|
*/
|
||||||
|
void addPushConstantStage(VkShaderStageFlagBits stage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Merges binding layouts
|
* \brief Merges binding layouts
|
||||||
*
|
*
|
||||||
|
@ -353,6 +370,7 @@ namespace dxvk {
|
||||||
|
|
||||||
std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings;
|
std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings;
|
||||||
VkPushConstantRange m_pushConst;
|
VkPushConstantRange m_pushConst;
|
||||||
|
VkShaderStageFlags m_pushConstStages;
|
||||||
VkShaderStageFlags m_stages;
|
VkShaderStageFlags m_stages;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
#include "../dxvk_platform_exts.h"
|
#include "dxvk_platform_exts.h"
|
||||||
|
#include "../wsi/wsi_platform.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkPlatformExts DxvkPlatformExts::s_instance;
|
DxvkPlatformExts DxvkPlatformExts::s_instance;
|
||||||
|
|
||||||
std::string_view DxvkPlatformExts::getName() {
|
std::string_view DxvkPlatformExts::getName() {
|
||||||
return "Win32 WSI";
|
return "Platform WSI";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
|
DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
|
||||||
|
std::vector<const char *> extensionNames = wsi::getInstanceExtensions();
|
||||||
|
|
||||||
DxvkNameSet names;
|
DxvkNameSet names;
|
||||||
names.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
for (const char* name : extensionNames)
|
||||||
|
names.add(name);
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
@ -33,4 +37,4 @@ namespace dxvk {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -382,6 +382,9 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
bool Presenter::supportsColorSpace(VkColorSpaceKHR colorspace) {
|
bool Presenter::supportsColorSpace(VkColorSpaceKHR colorspace) {
|
||||||
|
if (!m_surface)
|
||||||
|
return false;
|
||||||
|
|
||||||
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
||||||
getSupportedFormats(surfaceFormats, VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT);
|
getSupportedFormats(surfaceFormats, VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT);
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,8 @@ namespace dxvk {
|
||||||
|
|
||||||
if (info.pushConstSize) {
|
if (info.pushConstSize) {
|
||||||
VkPushConstantRange pushConst;
|
VkPushConstantRange pushConst;
|
||||||
pushConst.stageFlags = info.stage;
|
pushConst.stageFlags = info.pushConstStages;
|
||||||
pushConst.offset = info.pushConstOffset;
|
pushConst.offset = 0;
|
||||||
pushConst.size = info.pushConstSize;
|
pushConst.size = info.pushConstSize;
|
||||||
|
|
||||||
m_bindings.addPushConstantRange(pushConst);
|
m_bindings.addPushConstantRange(pushConst);
|
||||||
|
@ -75,6 +75,8 @@ namespace dxvk {
|
||||||
|
|
||||||
// Run an analysis pass over the SPIR-V code to gather some
|
// Run an analysis pass over the SPIR-V code to gather some
|
||||||
// info that we may need during pipeline compilation.
|
// info that we may need during pipeline compilation.
|
||||||
|
bool usesPushConstants = false;
|
||||||
|
|
||||||
std::vector<BindingOffsets> bindingOffsets;
|
std::vector<BindingOffsets> bindingOffsets;
|
||||||
std::vector<uint32_t> varIds;
|
std::vector<uint32_t> varIds;
|
||||||
std::vector<uint32_t> sampleMaskIds;
|
std::vector<uint32_t> sampleMaskIds;
|
||||||
|
@ -154,6 +156,9 @@ namespace dxvk {
|
||||||
if (std::find(sampleMaskIds.begin(), sampleMaskIds.end(), ins.arg(2)) != sampleMaskIds.end())
|
if (std::find(sampleMaskIds.begin(), sampleMaskIds.end(), ins.arg(2)) != sampleMaskIds.end())
|
||||||
m_flags.set(DxvkShaderFlag::ExportsSampleMask);
|
m_flags.set(DxvkShaderFlag::ExportsSampleMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ins.arg(3) == spv::StorageClassPushConstant)
|
||||||
|
usesPushConstants = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the actual shader code, there's nothing interesting for us in there.
|
// Ignore the actual shader code, there's nothing interesting for us in there.
|
||||||
|
@ -169,6 +174,11 @@ namespace dxvk {
|
||||||
m_bindingOffsets.push_back(info);
|
m_bindingOffsets.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set flag for stages that actually use push constants
|
||||||
|
// so that they can be trimmed for optimized pipelines.
|
||||||
|
if (usesPushConstants)
|
||||||
|
m_bindings.addPushConstantStage(info.stage);
|
||||||
|
|
||||||
// Don't set pipeline library flag if the shader
|
// Don't set pipeline library flag if the shader
|
||||||
// doesn't actually support pipeline libraries
|
// doesn't actually support pipeline libraries
|
||||||
m_needsLibraryCompile = canUsePipelineLibrary(true);
|
m_needsLibraryCompile = canUsePipelineLibrary(true);
|
||||||
|
@ -1012,7 +1022,7 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary::~DxvkShaderPipelineLibrary() {
|
DxvkShaderPipelineLibrary::~DxvkShaderPipelineLibrary() {
|
||||||
this->destroyShaderPipelinesLocked();
|
this->destroyShaderPipelineLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1032,22 +1042,17 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::acquirePipelineHandle(
|
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::acquirePipelineHandle() {
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args) {
|
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
if (m_device->mustTrackPipelineLifetime())
|
if (m_device->mustTrackPipelineLifetime())
|
||||||
m_useCount += 1;
|
m_useCount += 1;
|
||||||
|
|
||||||
VkPipeline& pipeline = (m_shaders.vs && !args.depthClipEnable)
|
if (m_pipeline.handle)
|
||||||
? m_pipelineNoDepthClip
|
return m_pipeline;
|
||||||
: m_pipeline;
|
|
||||||
|
|
||||||
if (pipeline)
|
m_pipeline = compileShaderPipelineLocked();
|
||||||
return pipeline;
|
return m_pipeline;
|
||||||
|
|
||||||
pipeline = compileShaderPipelineLocked(args);
|
|
||||||
return pipeline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1056,7 +1061,7 @@ namespace dxvk {
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
if (!(--m_useCount))
|
if (!(--m_useCount))
|
||||||
this->destroyShaderPipelinesLocked();
|
this->destroyShaderPipelineLocked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1069,17 +1074,16 @@ namespace dxvk {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Compile the pipeline with default args
|
// Compile the pipeline with default args
|
||||||
VkPipeline pipeline = compileShaderPipelineLocked(
|
DxvkShaderPipelineLibraryHandle pipeline = compileShaderPipelineLocked();
|
||||||
DxvkShaderPipelineLibraryCompileArgs());
|
|
||||||
|
|
||||||
// On 32-bit, destroy the pipeline immediately in order to
|
// On 32-bit, destroy the pipeline immediately in order to
|
||||||
// save memory. We should hit the driver's disk cache once
|
// save memory. We should hit the driver's disk cache once
|
||||||
// we need to recreate the pipeline.
|
// we need to recreate the pipeline.
|
||||||
if (m_device->mustTrackPipelineLifetime()) {
|
if (m_device->mustTrackPipelineLifetime()) {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
vk->vkDestroyPipeline(vk->device(), pipeline, nullptr);
|
vk->vkDestroyPipeline(vk->device(), pipeline.handle, nullptr);
|
||||||
|
|
||||||
pipeline = VK_NULL_HANDLE;
|
pipeline.handle = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write back pipeline handle for future use
|
// Write back pipeline handle for future use
|
||||||
|
@ -1087,37 +1091,32 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkShaderPipelineLibrary::destroyShaderPipelinesLocked() {
|
void DxvkShaderPipelineLibrary::destroyShaderPipelineLocked() {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
vk->vkDestroyPipeline(vk->device(), m_pipeline, nullptr);
|
vk->vkDestroyPipeline(vk->device(), m_pipeline.handle, nullptr);
|
||||||
vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip, nullptr);
|
|
||||||
|
|
||||||
m_pipeline = VK_NULL_HANDLE;
|
m_pipeline.handle = VK_NULL_HANDLE;
|
||||||
m_pipelineNoDepthClip = VK_NULL_HANDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipelineLocked(
|
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipelineLocked() {
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args) {
|
|
||||||
this->notifyLibraryCompile();
|
this->notifyLibraryCompile();
|
||||||
|
|
||||||
// If this is not the first time we're compiling the pipeline,
|
// If this is not the first time we're compiling the pipeline,
|
||||||
// try to get a cache hit using the shader module identifier
|
// try to get a cache hit using the shader module identifier
|
||||||
// so that we don't have to decompress our SPIR-V shader again.
|
// so that we don't have to decompress our SPIR-V shader again.
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
DxvkShaderPipelineLibraryHandle pipeline = { VK_NULL_HANDLE, 0 };
|
||||||
|
|
||||||
if (m_compiledOnce && canUsePipelineCacheControl()) {
|
if (m_compiledOnce && canUsePipelineCacheControl())
|
||||||
pipeline = this->compileShaderPipeline(args,
|
pipeline = this->compileShaderPipeline(VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
|
||||||
VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pipeline)
|
if (!pipeline.handle)
|
||||||
pipeline = this->compileShaderPipeline(args, 0);
|
pipeline = this->compileShaderPipeline(0);
|
||||||
|
|
||||||
// Well that didn't work
|
// Well that didn't work
|
||||||
if (!pipeline)
|
if (!pipeline.handle)
|
||||||
return VK_NULL_HANDLE;
|
return { VK_NULL_HANDLE, 0 };
|
||||||
|
|
||||||
// Increment stat counter the first time this
|
// Increment stat counter the first time this
|
||||||
// shader pipeline gets compiled successfully
|
// shader pipeline gets compiled successfully
|
||||||
|
@ -1134,8 +1133,7 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipeline(
|
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
|
||||||
VkPipelineCreateFlags flags) {
|
VkPipelineCreateFlags flags) {
|
||||||
DxvkShaderStageInfo stageInfo(m_device);
|
DxvkShaderStageInfo stageInfo(m_device);
|
||||||
VkShaderStageFlags stageMask = getShaderStages();
|
VkShaderStageFlags stageMask = getShaderStages();
|
||||||
|
@ -1151,7 +1149,7 @@ namespace dxvk {
|
||||||
// Fail if we have no idenfitier for whatever reason, caller
|
// Fail if we have no idenfitier for whatever reason, caller
|
||||||
// should fall back to the slow path if this happens
|
// should fall back to the slow path if this happens
|
||||||
if (!identifier->identifierSize)
|
if (!identifier->identifierSize)
|
||||||
return VK_NULL_HANDLE;
|
return { VK_NULL_HANDLE, 0 };
|
||||||
|
|
||||||
stageInfo.addStage(stage, *identifier, nullptr);
|
stageInfo.addStage(stage, *identifier, nullptr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1168,22 +1166,21 @@ namespace dxvk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (stageMask & VK_SHADER_STAGE_VERTEX_BIT)
|
if (stageMask & VK_SHADER_STAGE_VERTEX_BIT)
|
||||||
return compileVertexShaderPipeline(args, stageInfo, flags);
|
pipeline = compileVertexShaderPipeline(stageInfo, flags);
|
||||||
|
else if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT)
|
pipeline = compileFragmentShaderPipeline(stageInfo, flags);
|
||||||
return compileFragmentShaderPipeline(stageInfo, flags);
|
else if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
|
pipeline = compileComputeShaderPipeline(stageInfo, flags);
|
||||||
if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
|
|
||||||
return compileComputeShaderPipeline(stageInfo, flags);
|
|
||||||
|
|
||||||
// Should be unreachable
|
// Should be unreachable
|
||||||
return VK_NULL_HANDLE;
|
return { pipeline, flags };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
|
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
|
||||||
const DxvkShaderStageInfo& stageInfo,
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
VkPipelineCreateFlags flags) {
|
VkPipelineCreateFlags flags) {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
@ -1230,10 +1227,10 @@ namespace dxvk {
|
||||||
// Only use the fixed depth clip state if we can't make it dynamic
|
// Only use the fixed depth clip state if we can't make it dynamic
|
||||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable) {
|
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable) {
|
||||||
rsDepthClipInfo.pNext = std::exchange(rsInfo.pNext, &rsDepthClipInfo);
|
rsDepthClipInfo.pNext = std::exchange(rsInfo.pNext, &rsDepthClipInfo);
|
||||||
rsDepthClipInfo.depthClipEnable = args.depthClipEnable;
|
rsDepthClipInfo.depthClipEnable = VK_TRUE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rsInfo.depthClampEnable = !args.depthClipEnable;
|
rsInfo.depthClampEnable = VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only the view mask is used as input, and since we do not use MultiView, it is always 0
|
// Only the view mask is used as input, and since we do not use MultiView, it is always 0
|
||||||
|
@ -1256,7 +1253,7 @@ namespace dxvk {
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
|
|
||||||
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
|
if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
|
||||||
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create vertex shader pipeline: ", vr));
|
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create vertex shader pipeline: ", vr));
|
||||||
|
|
||||||
return vr ? VK_NULL_HANDLE : pipeline;
|
return vr ? VK_NULL_HANDLE : pipeline;
|
||||||
|
@ -1367,7 +1364,7 @@ namespace dxvk {
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
VkResult vr = vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
VkResult vr = vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
|
|
||||||
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
|
if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
|
||||||
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create compute shader pipeline: ", vr));
|
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create compute shader pipeline: ", vr));
|
||||||
|
|
||||||
return vr ? VK_NULL_HANDLE : pipeline;
|
return vr ? VK_NULL_HANDLE : pipeline;
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace dxvk {
|
||||||
/// Flat shading input mask
|
/// Flat shading input mask
|
||||||
uint32_t flatShadingInputs = 0;
|
uint32_t flatShadingInputs = 0;
|
||||||
/// Push constant range
|
/// Push constant range
|
||||||
uint32_t pushConstOffset = 0;
|
VkShaderStageFlags pushConstStages = 0;
|
||||||
uint32_t pushConstSize = 0;
|
uint32_t pushConstSize = 0;
|
||||||
/// Uniform buffer data
|
/// Uniform buffer data
|
||||||
uint32_t uniformSize = 0;
|
uint32_t uniformSize = 0;
|
||||||
|
@ -368,26 +368,6 @@ namespace dxvk {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Shader pipeline library compile args
|
|
||||||
*/
|
|
||||||
struct DxvkShaderPipelineLibraryCompileArgs {
|
|
||||||
VkBool32 depthClipEnable = VK_TRUE;
|
|
||||||
|
|
||||||
bool operator == (const DxvkShaderPipelineLibraryCompileArgs& other) const {
|
|
||||||
return depthClipEnable == other.depthClipEnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator != (const DxvkShaderPipelineLibraryCompileArgs& other) const {
|
|
||||||
return !this->operator == (other);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t hash() const {
|
|
||||||
return size_t(depthClipEnable);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Shader set
|
* \brief Shader set
|
||||||
*
|
*
|
||||||
|
@ -482,6 +462,17 @@ namespace dxvk {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pipeline library handle
|
||||||
|
*
|
||||||
|
* Stores a pipeline library handle and the necessary link flags.
|
||||||
|
*/
|
||||||
|
struct DxvkShaderPipelineLibraryHandle {
|
||||||
|
VkPipeline handle;
|
||||||
|
VkPipelineCreateFlags linkFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Shader pipeline library
|
* \brief Shader pipeline library
|
||||||
*
|
*
|
||||||
|
@ -521,11 +512,9 @@ namespace dxvk {
|
||||||
* Either returns an already compiled pipeline library object, or
|
* Either returns an already compiled pipeline library object, or
|
||||||
* performs the compilation step if that has not happened yet.
|
* performs the compilation step if that has not happened yet.
|
||||||
* Increments the use count by one.
|
* Increments the use count by one.
|
||||||
* \param [in] args Compile arguments
|
|
||||||
* \returns Vulkan pipeline handle
|
* \returns Vulkan pipeline handle
|
||||||
*/
|
*/
|
||||||
VkPipeline acquirePipelineHandle(
|
DxvkShaderPipelineLibraryHandle acquirePipelineHandle();
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Releases pipeline
|
* \brief Releases pipeline
|
||||||
|
@ -552,26 +541,22 @@ namespace dxvk {
|
||||||
DxvkShaderSet m_shaders;
|
DxvkShaderSet m_shaders;
|
||||||
const DxvkBindingLayoutObjects* m_layout;
|
const DxvkBindingLayoutObjects* m_layout;
|
||||||
|
|
||||||
dxvk::mutex m_mutex;
|
dxvk::mutex m_mutex;
|
||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
DxvkShaderPipelineLibraryHandle m_pipeline = { VK_NULL_HANDLE, 0 };
|
||||||
VkPipeline m_pipelineNoDepthClip = VK_NULL_HANDLE;
|
uint32_t m_useCount = 0u;
|
||||||
uint32_t m_useCount = 0u;
|
bool m_compiledOnce = false;
|
||||||
bool m_compiledOnce = false;
|
|
||||||
|
|
||||||
dxvk::mutex m_identifierMutex;
|
dxvk::mutex m_identifierMutex;
|
||||||
DxvkShaderIdentifierSet m_identifiers;
|
DxvkShaderIdentifierSet m_identifiers;
|
||||||
|
|
||||||
void destroyShaderPipelinesLocked();
|
void destroyShaderPipelineLocked();
|
||||||
|
|
||||||
VkPipeline compileShaderPipelineLocked(
|
DxvkShaderPipelineLibraryHandle compileShaderPipelineLocked();
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
|
||||||
|
|
||||||
VkPipeline compileShaderPipeline(
|
DxvkShaderPipelineLibraryHandle compileShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
|
||||||
VkPipelineCreateFlags flags);
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
VkPipeline compileVertexShaderPipeline(
|
VkPipeline compileVertexShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
|
||||||
const DxvkShaderStageInfo& stageInfo,
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
VkPipelineCreateFlags flags);
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,8 @@ namespace dxvk {
|
||||||
|
|
||||||
DxvkShaderCreateInfo vsInfo;
|
DxvkShaderCreateInfo vsInfo;
|
||||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
vsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||||
vsInfo.outputMask = 0x1;
|
vsInfo.outputMask = 0x1;
|
||||||
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
||||||
|
|
||||||
|
@ -336,6 +338,7 @@ namespace dxvk {
|
||||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
fsInfo.bindingCount = fsBindings.size();
|
fsInfo.bindingCount = fsBindings.size();
|
||||||
fsInfo.bindings = fsBindings.data();
|
fsInfo.bindings = fsBindings.data();
|
||||||
|
fsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
fsInfo.pushConstSize = sizeof(PresenterArgs);
|
fsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||||
fsInfo.inputMask = 0x1;
|
fsInfo.inputMask = 0x1;
|
||||||
fsInfo.outputMask = 0x1;
|
fsInfo.outputMask = 0x1;
|
||||||
|
|
|
@ -129,12 +129,8 @@ namespace dxvk::hud {
|
||||||
|
|
||||||
std::string driverInfo = props.vk12.driverInfo;
|
std::string driverInfo = props.vk12.driverInfo;
|
||||||
|
|
||||||
if (driverInfo.empty()) {
|
if (driverInfo.empty())
|
||||||
driverInfo = str::format(
|
driverInfo = props.driverVersion.toString();
|
||||||
VK_VERSION_MAJOR(props.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_MINOR(props.core.properties.driverVersion), ".",
|
|
||||||
VK_VERSION_PATCH(props.core.properties.driverVersion));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_deviceName = props.core.properties.deviceName;
|
m_deviceName = props.core.properties.deviceName;
|
||||||
m_driverName = str::format("Driver: ", props.vk12.driverName);
|
m_driverName = str::format("Driver: ", props.vk12.driverName);
|
||||||
|
|
|
@ -183,14 +183,17 @@ namespace dxvk::hud {
|
||||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
vsInfo.bindingCount = vsBindings.size();
|
vsInfo.bindingCount = vsBindings.size();
|
||||||
vsInfo.bindings = vsBindings.data();
|
vsInfo.bindings = vsBindings.data();
|
||||||
vsInfo.outputMask = 0x3;
|
vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
vsInfo.pushConstSize = sizeof(HudTextPushConstants);
|
vsInfo.pushConstSize = sizeof(HudTextPushConstants);
|
||||||
|
vsInfo.outputMask = 0x3;
|
||||||
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
||||||
|
|
||||||
DxvkShaderCreateInfo fsInfo;
|
DxvkShaderCreateInfo fsInfo;
|
||||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
fsInfo.bindingCount = fsBindings.size();
|
fsInfo.bindingCount = fsBindings.size();
|
||||||
fsInfo.bindings = fsBindings.data();
|
fsInfo.bindings = fsBindings.data();
|
||||||
|
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
fsInfo.pushConstSize = sizeof(HudTextPushConstants);
|
||||||
fsInfo.inputMask = 0x3;
|
fsInfo.inputMask = 0x3;
|
||||||
fsInfo.outputMask = 0x1;
|
fsInfo.outputMask = 0x1;
|
||||||
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
||||||
|
@ -212,6 +215,7 @@ namespace dxvk::hud {
|
||||||
DxvkShaderCreateInfo vsInfo;
|
DxvkShaderCreateInfo vsInfo;
|
||||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
vsInfo.outputMask = 0x1;
|
vsInfo.outputMask = 0x1;
|
||||||
|
vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
vsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
vsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
||||||
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
||||||
|
|
||||||
|
@ -221,6 +225,7 @@ namespace dxvk::hud {
|
||||||
fsInfo.bindings = fsBindings.data();
|
fsInfo.bindings = fsBindings.data();
|
||||||
fsInfo.inputMask = 0x1;
|
fsInfo.inputMask = 0x1;
|
||||||
fsInfo.outputMask = 0x1;
|
fsInfo.outputMask = 0x1;
|
||||||
|
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
fsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
fsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
||||||
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ dxvk_src = [
|
||||||
'dxvk_options.cpp',
|
'dxvk_options.cpp',
|
||||||
'dxvk_pipelayout.cpp',
|
'dxvk_pipelayout.cpp',
|
||||||
'dxvk_pipemanager.cpp',
|
'dxvk_pipemanager.cpp',
|
||||||
|
'dxvk_platform_exts.cpp',
|
||||||
'dxvk_presenter.cpp',
|
'dxvk_presenter.cpp',
|
||||||
'dxvk_queue.cpp',
|
'dxvk_queue.cpp',
|
||||||
'dxvk_resource.cpp',
|
'dxvk_resource.cpp',
|
||||||
|
@ -117,20 +118,6 @@ if platform == 'windows'
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if dxvk_wsi == 'win32'
|
|
||||||
dxvk_src += [
|
|
||||||
'platform/dxvk_win32_exts.cpp'
|
|
||||||
]
|
|
||||||
elif dxvk_wsi == 'sdl2'
|
|
||||||
dxvk_src += [
|
|
||||||
'platform/dxvk_sdl2_exts.cpp'
|
|
||||||
]
|
|
||||||
elif dxvk_wsi == 'glfw'
|
|
||||||
dxvk_src += [
|
|
||||||
'platform/dxvk_glfw_exts.cpp'
|
|
||||||
]
|
|
||||||
endif
|
|
||||||
|
|
||||||
dxvk_extra_deps = [ dependency('threads') ]
|
dxvk_extra_deps = [ dependency('threads') ]
|
||||||
if platform == 'linux'
|
if platform == 'linux'
|
||||||
dxvk_extra_deps += [ cpp.find_library('dl', required: false) ]
|
dxvk_extra_deps += [ cpp.find_library('dl', required: false) ]
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
#include "../dxvk_platform_exts.h"
|
|
||||||
|
|
||||||
#include "../../vulkan/vulkan_loader.h"
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
namespace dxvk {
|
|
||||||
|
|
||||||
DxvkPlatformExts DxvkPlatformExts::s_instance;
|
|
||||||
|
|
||||||
std::string_view DxvkPlatformExts::getName() {
|
|
||||||
return "GLFW WSI";
|
|
||||||
}
|
|
||||||
|
|
||||||
DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
|
|
||||||
if (!glfwVulkanSupported())
|
|
||||||
throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!"));
|
|
||||||
|
|
||||||
uint32_t extensionCount = 0;
|
|
||||||
const char** extensionArray = glfwGetRequiredInstanceExtensions(&extensionCount);
|
|
||||||
|
|
||||||
if (extensionCount == 0)
|
|
||||||
throw DxvkError(str::format("GLFW WSI: Failed to get required instance extensions"));
|
|
||||||
|
|
||||||
DxvkNameSet names;
|
|
||||||
for (uint32_t i = 0; i < extensionCount; ++i) {
|
|
||||||
names.add(extensionArray[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DxvkNameSet DxvkPlatformExts::getDeviceExtensions(
|
|
||||||
uint32_t adapterId) {
|
|
||||||
return DxvkNameSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkPlatformExts::initInstanceExtensions() {
|
|
||||||
//Nothing needs to be done here on GLFW
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkPlatformExts::initDeviceExtensions(
|
|
||||||
const DxvkInstance* instance) {
|
|
||||||
//Nothing needs to be done here on GLFW
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
#include "../dxvk_platform_exts.h"
|
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#include <SDL2/SDL_vulkan.h>
|
|
||||||
|
|
||||||
namespace dxvk {
|
|
||||||
|
|
||||||
DxvkPlatformExts DxvkPlatformExts::s_instance;
|
|
||||||
|
|
||||||
std::string_view DxvkPlatformExts::getName() {
|
|
||||||
return "SDL2 WSI";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
|
|
||||||
SDL_Vulkan_LoadLibrary(nullptr);
|
|
||||||
|
|
||||||
uint32_t extensionCount = 0;
|
|
||||||
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, nullptr))
|
|
||||||
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", SDL_GetError()));
|
|
||||||
|
|
||||||
auto extensionNames = std::vector<const char *>(extensionCount);
|
|
||||||
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data()))
|
|
||||||
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError()));
|
|
||||||
|
|
||||||
DxvkNameSet names;
|
|
||||||
for (const char* name : extensionNames)
|
|
||||||
names.add(name);
|
|
||||||
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DxvkNameSet DxvkPlatformExts::getDeviceExtensions(
|
|
||||||
uint32_t adapterId) {
|
|
||||||
return DxvkNameSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkPlatformExts::initInstanceExtensions() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkPlatformExts::initDeviceExtensions(
|
|
||||||
const DxvkInstance* instance) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -13,7 +13,10 @@
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
const static std::vector<std::pair<const char*, Config>> g_appDefaults = {{
|
using ProfileList = std::vector<std::pair<const char*, Config>>;
|
||||||
|
|
||||||
|
|
||||||
|
const static ProfileList g_profiles = {{
|
||||||
/* Assassin's Creed Syndicate: amdags issues */
|
/* Assassin's Creed Syndicate: amdags issues */
|
||||||
{ R"(\\ACS\.exe$)", {{
|
{ R"(\\ACS\.exe$)", {{
|
||||||
{ "dxgi.customVendorId", "10de" },
|
{ "dxgi.customVendorId", "10de" },
|
||||||
|
@ -122,8 +125,6 @@ namespace dxvk {
|
||||||
}} },
|
}} },
|
||||||
/* NieR Replicant */
|
/* NieR Replicant */
|
||||||
{ R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
|
{ R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
|
||||||
{ "dxgi.syncInterval", "1" },
|
|
||||||
{ "dxgi.maxFrameRate", "60" },
|
|
||||||
{ "d3d11.cachedDynamicResources", "vi" },
|
{ "d3d11.cachedDynamicResources", "vi" },
|
||||||
}} },
|
}} },
|
||||||
/* SteamVR performance test */
|
/* SteamVR performance test */
|
||||||
|
@ -138,6 +139,10 @@ namespace dxvk {
|
||||||
{ R"(\\h1(_[ms]p64_ship|-mod)\.exe$)", {{
|
{ R"(\\h1(_[ms]p64_ship|-mod)\.exe$)", {{
|
||||||
{ "dxgi.customVendorId", "10de" },
|
{ "dxgi.customVendorId", "10de" },
|
||||||
}} },
|
}} },
|
||||||
|
/* H2M-Mod - Modern Warfare Remastered */
|
||||||
|
{ R"(\\h2m-mod\.exe$)", {{
|
||||||
|
{ "dxgi.customVendorId", "10de" },
|
||||||
|
}} },
|
||||||
/* Modern Warfare 2 Campaign Remastered *
|
/* Modern Warfare 2 Campaign Remastered *
|
||||||
* AMD AGS crash same as above */
|
* AMD AGS crash same as above */
|
||||||
{ R"(\\MW2CR\.exe$)", {{
|
{ R"(\\MW2CR\.exe$)", {{
|
||||||
|
@ -331,11 +336,6 @@ namespace dxvk {
|
||||||
{ R"(\\SonicFrontiers\.exe$)", {{
|
{ R"(\\SonicFrontiers\.exe$)", {{
|
||||||
{ "dxgi.maxFrameLatency", "1" },
|
{ "dxgi.maxFrameLatency", "1" },
|
||||||
}} },
|
}} },
|
||||||
/* TRAHA Global *
|
|
||||||
* Shadow issues when it sees AMD/Nvidia */
|
|
||||||
{ R"(\\RapaNui-Win64-Shipping\.exe$)", {{
|
|
||||||
{ "dxgi.customVendorId", "8086" },
|
|
||||||
}} },
|
|
||||||
/* SpellForce 3 Reforced & expansions *
|
/* SpellForce 3 Reforced & expansions *
|
||||||
* Greatly improves CPU bound performance */
|
* Greatly improves CPU bound performance */
|
||||||
{ R"(\\SF3ClientFinal\.exe$)", {{
|
{ R"(\\SF3ClientFinal\.exe$)", {{
|
||||||
|
@ -370,6 +370,10 @@ namespace dxvk {
|
||||||
{ R"(\\EADesktop\.exe$)", {{
|
{ R"(\\EADesktop\.exe$)", {{
|
||||||
{ "dxvk.maxChunkSize", "1" },
|
{ "dxvk.maxChunkSize", "1" },
|
||||||
}} },
|
}} },
|
||||||
|
/* Origin app (legacy EA Desktop) */
|
||||||
|
{ R"(\\Origin\.exe$)", {{
|
||||||
|
{ "dxvk.maxChunkSize", "1" },
|
||||||
|
}} },
|
||||||
/* GOG Galaxy */
|
/* GOG Galaxy */
|
||||||
{ R"(\\GalaxyClient\.exe$)", {{
|
{ R"(\\GalaxyClient\.exe$)", {{
|
||||||
{ "dxvk.maxChunkSize", "1" },
|
{ "dxvk.maxChunkSize", "1" },
|
||||||
|
@ -411,11 +415,6 @@ namespace dxvk {
|
||||||
{ R"(\\RidersRepublic(_BE)?\.exe$)", {{
|
{ R"(\\RidersRepublic(_BE)?\.exe$)", {{
|
||||||
{ "dxgi.hideAmdGpu", "True" },
|
{ "dxgi.hideAmdGpu", "True" },
|
||||||
}} },
|
}} },
|
||||||
/* HoloCure - Save the Fans!
|
|
||||||
Same as Cyberpunk 2077 */
|
|
||||||
{ R"(\\HoloCure\.exe$)", {{
|
|
||||||
{ "dxgi.useMonitorFallback", "True" },
|
|
||||||
}} },
|
|
||||||
/* Kenshi *
|
/* Kenshi *
|
||||||
* Helps CPU bound performance */
|
* Helps CPU bound performance */
|
||||||
{ R"(\\kenshi_x64\.exe$)", {{
|
{ R"(\\kenshi_x64\.exe$)", {{
|
||||||
|
@ -429,6 +428,16 @@ namespace dxvk {
|
||||||
{ "d3d11.exposeDriverCommandLists", "False" },
|
{ "d3d11.exposeDriverCommandLists", "False" },
|
||||||
{ "dxgi.hideNvidiaGpu", "False" },
|
{ "dxgi.hideNvidiaGpu", "False" },
|
||||||
}} },
|
}} },
|
||||||
|
/* Red Faction Guerrilla Re-Mars-tered *
|
||||||
|
* Broken skybox */
|
||||||
|
{ R"(\\rfg\.exe$)", {{
|
||||||
|
{ "d3d11.longMad", "True" },
|
||||||
|
}} },
|
||||||
|
/* Guild Wars 2 - Fixes invisibility effect *
|
||||||
|
* flicker when invariantPosition is enabled */
|
||||||
|
{ R"(\\Gw2-64\.exe$)", {{
|
||||||
|
{ "d3d11.longMad", "True" },
|
||||||
|
}} },
|
||||||
|
|
||||||
/**********************************************/
|
/**********************************************/
|
||||||
/* D3D9 GAMES */
|
/* D3D9 GAMES */
|
||||||
|
@ -877,6 +886,27 @@ namespace dxvk {
|
||||||
{ R"(\\ShippingPC-SkyGame\.exe$)", {{
|
{ R"(\\ShippingPC-SkyGame\.exe$)", {{
|
||||||
{ "d3d9.maxFrameRate", "60" },
|
{ "d3d9.maxFrameRate", "60" },
|
||||||
}} },
|
}} },
|
||||||
|
/* 9th Dawn II *
|
||||||
|
* OpenGL game that also spins up d3d9 *
|
||||||
|
* Black screens without config */
|
||||||
|
{ R"(\\ninthdawnii\.exe$)", {{
|
||||||
|
{ "d3d9.deferSurfaceCreation", "True" },
|
||||||
|
}} },
|
||||||
|
/* Delta Force: Xtreme 1 & 2 *
|
||||||
|
* Black screen on Alt-Tab and performance */
|
||||||
|
{ R"(\\(DFX|dfx2)\.exe$)", {{
|
||||||
|
{ "d3d9.deviceLossOnFocusLoss", "True" },
|
||||||
|
{ "d3d9.cachedDynamicBuffers", "True" },
|
||||||
|
}} },
|
||||||
|
/* The Sims 3 - Black screen on alt-tab */
|
||||||
|
{ R"(\\TS3(W)?\.exe$)", {{
|
||||||
|
{ "d3d9.deviceLossOnFocusLoss", "True" },
|
||||||
|
}} },
|
||||||
|
/* Prototype *
|
||||||
|
* Incorrect shadows on AMD & Intel */
|
||||||
|
{ R"(\\prototypef\.exe$)", {{
|
||||||
|
{ "d3d9.supportDFFormats", "False" },
|
||||||
|
}} },
|
||||||
|
|
||||||
|
|
||||||
/**********************************************/
|
/**********************************************/
|
||||||
|
@ -901,13 +931,6 @@ namespace dxvk {
|
||||||
{ R"(\\RiftApart\.exe$)", {{
|
{ R"(\\RiftApart\.exe$)", {{
|
||||||
{ "dxgi.hideNvidiaGpu", "False" },
|
{ "dxgi.hideNvidiaGpu", "False" },
|
||||||
}} },
|
}} },
|
||||||
/* CP2077 enumerates display outputs each frame.
|
|
||||||
* Avoid using QueryDisplayConfig to avoid
|
|
||||||
* performance degradation until the
|
|
||||||
* optimization of that function is in Proton. */
|
|
||||||
{ R"(\\Cyberpunk2077\.exe$)", {{
|
|
||||||
{ "dxgi.useMonitorFallback", "True" },
|
|
||||||
}} },
|
|
||||||
/* Metro Exodus Enhanced Edition picks GPU adapters
|
/* Metro Exodus Enhanced Edition picks GPU adapters
|
||||||
* by available VRAM, which causes issues on some
|
* by available VRAM, which causes issues on some
|
||||||
* systems with integrated graphics. */
|
* systems with integrated graphics. */
|
||||||
|
@ -922,6 +945,28 @@ namespace dxvk {
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
const static ProfileList g_deckProfiles = {{
|
||||||
|
/* Fallout 4: Defaults to 45 FPS on OLED, but also breaks above 60 FPS */
|
||||||
|
{ R"(\\Fallout4\.exe$)", {{
|
||||||
|
{ "dxgi.syncInterval", "1" },
|
||||||
|
{ "dxgi.maxFrameRate", "60" },
|
||||||
|
}} },
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
const Config* findProfile(const ProfileList& profiles, const std::string& appName) {
|
||||||
|
auto appConfig = std::find_if(profiles.begin(), profiles.end(),
|
||||||
|
[&appName] (const std::pair<const char*, Config>& pair) {
|
||||||
|
std::regex expr(pair.first, std::regex::extended | std::regex::icase);
|
||||||
|
return std::regex_search(appName, expr);
|
||||||
|
});
|
||||||
|
|
||||||
|
return appConfig != profiles.end()
|
||||||
|
? &appConfig->second
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool isWhitespace(char ch) {
|
static bool isWhitespace(char ch) {
|
||||||
return ch == ' ' || ch == '\x9' || ch == '\r';
|
return ch == ' ' || ch == '\x9' || ch == '\r';
|
||||||
}
|
}
|
||||||
|
@ -1171,20 +1216,22 @@ namespace dxvk {
|
||||||
|
|
||||||
|
|
||||||
Config Config::getAppConfig(const std::string& appName) {
|
Config Config::getAppConfig(const std::string& appName) {
|
||||||
auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.end(),
|
const Config* config = nullptr;
|
||||||
[&appName] (const std::pair<const char*, Config>& pair) {
|
|
||||||
std::regex expr(pair.first, std::regex::extended | std::regex::icase);
|
|
||||||
return std::regex_search(appName, expr);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (appConfig != g_appDefaults.end()) {
|
if (env::getEnvVar("SteamDeck") == "1")
|
||||||
|
config = findProfile(g_deckProfiles, appName);
|
||||||
|
|
||||||
|
if (!config)
|
||||||
|
config = findProfile(g_profiles, appName);
|
||||||
|
|
||||||
|
if (config) {
|
||||||
// Inform the user that we loaded a default config
|
// Inform the user that we loaded a default config
|
||||||
Logger::info(str::format("Found built-in config:"));
|
Logger::info(str::format("Found built-in config:"));
|
||||||
|
|
||||||
for (auto& pair : appConfig->second.m_options)
|
for (auto& pair : config->m_options)
|
||||||
Logger::info(str::format(" ", pair.first, " = ", pair.second));
|
Logger::info(str::format(" ", pair.first, " = ", pair.second));
|
||||||
|
|
||||||
return appConfig->second;
|
return *config;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Config();
|
return Config();
|
||||||
|
|
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
|
GpuFlushTracker::GpuFlushTracker(
|
||||||
|
bool ensureReproducibleHeuristic)
|
||||||
|
: m_ensureReproducibleHeuristic(ensureReproducibleHeuristic) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool GpuFlushTracker::considerFlush(
|
bool GpuFlushTracker::considerFlush(
|
||||||
GpuFlushType flushType,
|
GpuFlushType flushType,
|
||||||
uint64_t chunkId,
|
uint64_t chunkId,
|
||||||
|
@ -17,6 +23,9 @@ namespace dxvk {
|
||||||
if (!chunkCount)
|
if (!chunkCount)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (m_ensureReproducibleHeuristic && flushType != GpuFlushType::ExplicitFlush)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Take any earlier missed flush with a stronger hint into account, so
|
// Take any earlier missed flush with a stronger hint into account, so
|
||||||
// that we still flush those as soon as possible. Ignore synchronization
|
// that we still flush those as soon as possible. Ignore synchronization
|
||||||
// commands since they will either perform a flush or not need it at all.
|
// commands since they will either perform a flush or not need it at all.
|
||||||
|
|
|
@ -34,6 +34,8 @@ namespace dxvk {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
GpuFlushTracker(bool ensureReproducibleHeuristic);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Checks whether a context flush should be performed
|
* \brief Checks whether a context flush should be performed
|
||||||
*
|
*
|
||||||
|
@ -61,6 +63,8 @@ namespace dxvk {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool m_ensureReproducibleHeuristic;
|
||||||
|
|
||||||
GpuFlushType m_lastMissedType = GpuFlushType::ImplicitWeakHint;
|
GpuFlushType m_lastMissedType = GpuFlushType::ImplicitWeakHint;
|
||||||
|
|
||||||
uint64_t m_lastFlushChunkId = 0ull;
|
uint64_t m_lastFlushChunkId = 0ull;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "../vulkan/vulkan_loader.h"
|
||||||
|
|
||||||
|
#include "util_string.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decoded driver version
|
||||||
|
*/
|
||||||
|
class Version {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Version() = default;
|
||||||
|
|
||||||
|
Version(uint32_t major, uint32_t minor, uint32_t patch)
|
||||||
|
: m_raw((uint64_t(major) << 48) | (uint64_t(minor) << 24) | uint64_t(patch)) { }
|
||||||
|
|
||||||
|
uint32_t major() const { return uint32_t(m_raw >> 48); }
|
||||||
|
uint32_t minor() const { return uint32_t(m_raw >> 24) & 0xffffffu; }
|
||||||
|
uint32_t patch() const { return uint32_t(m_raw) & 0xffffffu; }
|
||||||
|
|
||||||
|
bool operator == (const Version& other) const { return m_raw == other.m_raw; }
|
||||||
|
bool operator != (const Version& other) const { return m_raw != other.m_raw; }
|
||||||
|
bool operator >= (const Version& other) const { return m_raw >= other.m_raw; }
|
||||||
|
bool operator <= (const Version& other) const { return m_raw <= other.m_raw; }
|
||||||
|
bool operator > (const Version& other) const { return m_raw > other.m_raw; }
|
||||||
|
bool operator < (const Version& other) const { return m_raw < other.m_raw; }
|
||||||
|
|
||||||
|
std::string toString() const {
|
||||||
|
return str::format(major(), ".", minor(), ".", patch());
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool () const {
|
||||||
|
return m_raw != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint64_t m_raw = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
|
||||||
#include "../wsi_monitor.h"
|
#include "../wsi_monitor.h"
|
||||||
|
|
||||||
#include "wsi/native_wsi.h"
|
#include "wsi/native_wsi.h"
|
||||||
|
@ -11,22 +13,22 @@
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
HMONITOR getDefaultMonitor() {
|
HMONITOR GlfwWsiDriver::getDefaultMonitor() {
|
||||||
return enumMonitors(0);
|
return enumMonitors(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HMONITOR enumMonitors(uint32_t index) {
|
HMONITOR GlfwWsiDriver::enumMonitors(uint32_t index) {
|
||||||
return isDisplayValid(int32_t(index))
|
return isDisplayValid(int32_t(index))
|
||||||
? toHmonitor(index)
|
? toHmonitor(index)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
HMONITOR GlfwWsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
||||||
return enumMonitors(index);
|
return enumMonitors(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getDisplayName(
|
bool GlfwWsiDriver::getDisplayName(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WCHAR (&Name)[32]) {
|
WCHAR (&Name)[32]) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -46,7 +48,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopCoordinates(
|
bool GlfwWsiDriver::getDesktopCoordinates(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
RECT* pRect) {
|
RECT* pRect) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -97,7 +99,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDisplayMode(
|
bool GlfwWsiDriver::getDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
uint32_t ModeNumber,
|
uint32_t ModeNumber,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
|
@ -121,7 +123,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getCurrentDisplayMode(
|
bool GlfwWsiDriver::getCurrentDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -141,7 +143,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopDisplayMode(
|
bool GlfwWsiDriver::getDesktopDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -159,9 +161,11 @@ namespace dxvk::wsi {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> getMonitorEdid(HMONITOR hMonitor) {
|
std::vector<uint8_t> GlfwWsiDriver::getMonitorEdid(HMONITOR hMonitor) {
|
||||||
Logger::err("getMonitorEdid not implemented on this platform.");
|
Logger::err("getMonitorEdid not implemented on this platform.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
|
||||||
|
#include "wsi_platform_glfw.h"
|
||||||
|
#include "../../util/util_error.h"
|
||||||
|
#include "../../util/util_string.h"
|
||||||
|
#include "../../util/util_win32_compat.h"
|
||||||
|
|
||||||
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
GlfwWsiDriver::GlfwWsiDriver() {
|
||||||
|
libglfw = LoadLibraryA( // FIXME: Get soname as string from meson
|
||||||
|
#if defined(_WIN32)
|
||||||
|
"glfw.dll"
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
"libglfw.3.dylib"
|
||||||
|
#else
|
||||||
|
"libglfw.so.3"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
if (libglfw == nullptr)
|
||||||
|
throw DxvkError("GLFW WSI: Failed to load GLFW DLL.");
|
||||||
|
|
||||||
|
#define GLFW_PROC(ret, name, params) \
|
||||||
|
name = reinterpret_cast<pfn_##name>(GetProcAddress(libglfw, #name)); \
|
||||||
|
if (name == nullptr) { \
|
||||||
|
FreeLibrary(libglfw); \
|
||||||
|
libglfw = nullptr; \
|
||||||
|
throw DxvkError("GLFW WSI: Failed to load " #name "."); \
|
||||||
|
}
|
||||||
|
#include "wsi_platform_glfw_funcs.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
GlfwWsiDriver::~GlfwWsiDriver() {
|
||||||
|
FreeLibrary(libglfw);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char *> GlfwWsiDriver::getInstanceExtensions() {
|
||||||
|
if (!glfwVulkanSupported())
|
||||||
|
throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!"));
|
||||||
|
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
const char** extensionArray = glfwGetRequiredInstanceExtensions(&extensionCount);
|
||||||
|
|
||||||
|
if (extensionCount == 0)
|
||||||
|
throw DxvkError(str::format("GLFW WSI: Failed to get required instance extensions"));
|
||||||
|
|
||||||
|
std::vector<const char *> names(extensionCount);
|
||||||
|
for (uint32_t i = 0; i < extensionCount; ++i) {
|
||||||
|
names.push_back(extensionArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createGlfwWsiDriver(WsiDriver **driver) {
|
||||||
|
try {
|
||||||
|
*driver = new GlfwWsiDriver();
|
||||||
|
} catch (const DxvkError& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WsiBootstrap GlfwWSI = {
|
||||||
|
"GLFW",
|
||||||
|
createGlfwWsiDriver
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,21 +3,108 @@
|
||||||
#include "../../vulkan/vulkan_loader.h"
|
#include "../../vulkan/vulkan_loader.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include "../wsi_monitor.h"
|
#include "../wsi_platform.h"
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
/**
|
class GlfwWsiDriver : public WsiDriver {
|
||||||
* \brief Impl-dependent state
|
private:
|
||||||
*/
|
HMODULE libglfw;
|
||||||
struct DxvkWindowState {
|
#define GLFW_PROC(ret, name, params) \
|
||||||
|
typedef ret (*pfn_##name) params; \
|
||||||
|
pfn_##name name;
|
||||||
|
#include "wsi_platform_glfw_funcs.h"
|
||||||
|
|
||||||
|
inline bool isDisplayValid(int32_t displayId) {
|
||||||
|
int32_t displayCount = 0;
|
||||||
|
glfwGetMonitors(&displayCount);
|
||||||
|
|
||||||
|
return displayId < displayCount && displayId >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GlfwWsiDriver();
|
||||||
|
~GlfwWsiDriver();
|
||||||
|
|
||||||
|
// Platform
|
||||||
|
virtual std::vector<const char *> getInstanceExtensions();
|
||||||
|
|
||||||
|
// Monitor
|
||||||
|
virtual HMONITOR getDefaultMonitor();
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(uint32_t index);
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index);
|
||||||
|
|
||||||
|
virtual bool getDisplayName(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WCHAR (&Name)[32]);
|
||||||
|
|
||||||
|
virtual bool getDesktopCoordinates(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
RECT* pRect);
|
||||||
|
|
||||||
|
virtual bool getDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
uint32_t modeNumber,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getCurrentDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getDesktopDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor);
|
||||||
|
|
||||||
|
// Window
|
||||||
|
|
||||||
|
virtual void getWindowSize(
|
||||||
|
HWND hWindow,
|
||||||
|
uint32_t* pWidth,
|
||||||
|
uint32_t* pWeight);
|
||||||
|
|
||||||
|
virtual void resizeWindow(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t weight);
|
||||||
|
|
||||||
|
virtual bool setWindowMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
const WsiMode& mode);
|
||||||
|
|
||||||
|
virtual bool enterFullscreenMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
[[maybe_unused]]
|
||||||
|
bool modeSwitch);
|
||||||
|
|
||||||
|
virtual bool leaveFullscreenMode(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
bool restoreCoordinates);
|
||||||
|
|
||||||
|
virtual bool restoreDisplayMode();
|
||||||
|
|
||||||
|
virtual HMONITOR getWindowMonitor(HWND hWindow);
|
||||||
|
|
||||||
|
virtual bool isWindow(HWND hWindow);
|
||||||
|
|
||||||
|
virtual void updateFullscreenWindow(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
bool forceTopmost);
|
||||||
|
|
||||||
|
virtual VkResult createSurface(
|
||||||
|
HWND hWindow,
|
||||||
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool isDisplayValid(int32_t displayId) {
|
|
||||||
int32_t displayCount = 0;
|
|
||||||
glfwGetMonitors(&displayCount);
|
|
||||||
|
|
||||||
return displayId < displayCount && displayId >= 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
GLFW_PROC(VkResult, glfwCreateWindowSurface, (VkInstance, GLFWwindow*, const VkAllocationCallbacks*, VkSurfaceKHR*))
|
||||||
|
GLFW_PROC(GLFWmonitor**, glfwGetMonitors, (int*))
|
||||||
|
GLFW_PROC(void, glfwGetMonitorWorkarea, (GLFWmonitor*, int*, int*, int*, int*))
|
||||||
|
GLFW_PROC(GLFWmonitor*, glfwGetPrimaryMonitor, (void))
|
||||||
|
GLFW_PROC(const char**, glfwGetRequiredInstanceExtensions, (uint32_t*))
|
||||||
|
GLFW_PROC(const GLFWvidmode*, glfwGetVideoMode, (GLFWmonitor*))
|
||||||
|
GLFW_PROC(const GLFWvidmode*, glfwGetVideoModes, (GLFWmonitor*, int*))
|
||||||
|
GLFW_PROC(void, glfwGetWindowSize, (GLFWwindow*, int*, int*))
|
||||||
|
GLFW_PROC(void, glfwSetWindowMonitor, (GLFWwindow*, GLFWmonitor*, int, int, int, int, int))
|
||||||
|
GLFW_PROC(void, glfwSetWindowSize, (GLFWwindow*, int, int))
|
||||||
|
GLFW_PROC(int, glfwVulkanSupported, (void))
|
||||||
|
#undef GLFW_PROC
|
|
@ -1,6 +1,8 @@
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
|
||||||
#include "../wsi_window.h"
|
#include "../wsi_window.h"
|
||||||
|
|
||||||
#include "native/wsi/native_wsi.h"
|
#include "native/wsi/native_glfw.h"
|
||||||
#include "wsi_platform_glfw.h"
|
#include "wsi_platform_glfw.h"
|
||||||
|
|
||||||
#include "../../util/util_string.h"
|
#include "../../util/util_string.h"
|
||||||
|
@ -12,7 +14,7 @@
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
void getWindowSize(
|
void GlfwWsiDriver::getWindowSize(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
uint32_t* pWidth,
|
uint32_t* pWidth,
|
||||||
uint32_t* pHeight) {
|
uint32_t* pHeight) {
|
||||||
|
@ -29,7 +31,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void resizeWindow(
|
void GlfwWsiDriver::resizeWindow(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
uint32_t Width,
|
uint32_t Width,
|
||||||
|
@ -40,7 +42,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool setWindowMode(
|
bool GlfwWsiDriver::setWindowMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
const WsiMode& pMode) {
|
const WsiMode& pMode) {
|
||||||
|
@ -67,7 +69,7 @@ namespace dxvk::wsi {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enterFullscreenMode(
|
bool GlfwWsiDriver::enterFullscreenMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
|
@ -89,7 +91,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool leaveFullscreenMode(
|
bool GlfwWsiDriver::leaveFullscreenMode(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
bool restoreCoordinates) {
|
bool restoreCoordinates) {
|
||||||
|
@ -103,13 +105,13 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool restoreDisplayMode() {
|
bool GlfwWsiDriver::restoreDisplayMode() {
|
||||||
// Don't need to do anything with GLFW here.
|
// Don't need to do anything with GLFW here.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
HMONITOR GlfwWsiDriver::getWindowMonitor(HWND hWindow) {
|
||||||
// TODO: implement this with glfwGetWindowMonitor
|
// TODO: implement this with glfwGetWindowMonitor
|
||||||
// (or maybe not? glfwGetWindowMonitor only seems to reference *fullscreen* windows)
|
// (or maybe not? glfwGetWindowMonitor only seems to reference *fullscreen* windows)
|
||||||
// GLFWwindow* window = fromHwnd(hWindow);
|
// GLFWwindow* window = fromHwnd(hWindow);
|
||||||
|
@ -119,19 +121,19 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isWindow(HWND hWindow) {
|
bool GlfwWsiDriver::isWindow(HWND hWindow) {
|
||||||
GLFWwindow* window = fromHwnd(hWindow);
|
GLFWwindow* window = fromHwnd(hWindow);
|
||||||
return window != nullptr;
|
return window != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateFullscreenWindow(
|
void GlfwWsiDriver::updateFullscreenWindow(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
bool forceTopmost) {
|
bool forceTopmost) {
|
||||||
// Don't need to do anything with GLFW here.
|
// Don't need to do anything with GLFW here.
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult createSurface(
|
VkResult GlfwWsiDriver::createSurface(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
VkInstance instance,
|
VkInstance instance,
|
||||||
|
@ -141,4 +143,6 @@ namespace dxvk::wsi {
|
||||||
return glfwCreateWindowSurface(instance, window, nullptr, pSurface);
|
return glfwCreateWindowSurface(instance, window, nullptr, pSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,33 +1,24 @@
|
||||||
wsi_common_src = [
|
wsi_src = [
|
||||||
'wsi_edid.cpp',
|
'wsi_edid.cpp',
|
||||||
]
|
'wsi_platform.cpp',
|
||||||
|
|
||||||
wsi_win32_src = [
|
|
||||||
'win32/wsi_monitor_win32.cpp',
|
'win32/wsi_monitor_win32.cpp',
|
||||||
|
'win32/wsi_platform_win32.cpp',
|
||||||
'win32/wsi_window_win32.cpp',
|
'win32/wsi_window_win32.cpp',
|
||||||
]
|
|
||||||
|
|
||||||
wsi_sdl2_src = [
|
|
||||||
'sdl2/wsi_monitor_sdl2.cpp',
|
'sdl2/wsi_monitor_sdl2.cpp',
|
||||||
|
'sdl2/wsi_platform_sdl2.cpp',
|
||||||
'sdl2/wsi_window_sdl2.cpp',
|
'sdl2/wsi_window_sdl2.cpp',
|
||||||
]
|
|
||||||
|
|
||||||
wsi_glfw_src = [
|
|
||||||
'glfw/wsi_monitor_glfw.cpp',
|
'glfw/wsi_monitor_glfw.cpp',
|
||||||
|
'glfw/wsi_platform_glfw.cpp',
|
||||||
'glfw/wsi_window_glfw.cpp',
|
'glfw/wsi_window_glfw.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
if dxvk_wsi == 'win32'
|
wsi_deps = [ dep_displayinfo ]
|
||||||
wsi_src = wsi_common_src + wsi_win32_src
|
|
||||||
wsi_deps = [ dep_displayinfo ]
|
if platform != 'windows'
|
||||||
elif dxvk_wsi == 'sdl2'
|
wsi_deps += [
|
||||||
wsi_src = wsi_common_src + wsi_sdl2_src
|
lib_sdl2.partial_dependency(compile_args: true, includes: true),
|
||||||
wsi_deps = [ dep_displayinfo, lib_sdl2 ]
|
lib_glfw.partial_dependency(compile_args: true, includes: true),
|
||||||
elif dxvk_wsi == 'glfw'
|
]
|
||||||
wsi_src = wsi_common_src + wsi_glfw_src
|
|
||||||
wsi_deps = [ dep_displayinfo, lib_glfw ]
|
|
||||||
else
|
|
||||||
error('Unknown wsi')
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
wsi_lib = static_library('wsi', wsi_src,
|
wsi_lib = static_library('wsi', wsi_src,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
|
||||||
#include "../wsi_monitor.h"
|
#include "../wsi_monitor.h"
|
||||||
|
|
||||||
#include "wsi/native_wsi.h"
|
#include "wsi/native_wsi.h"
|
||||||
|
@ -12,22 +14,22 @@
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
HMONITOR getDefaultMonitor() {
|
HMONITOR Sdl2WsiDriver::getDefaultMonitor() {
|
||||||
return enumMonitors(0);
|
return enumMonitors(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HMONITOR enumMonitors(uint32_t index) {
|
HMONITOR Sdl2WsiDriver::enumMonitors(uint32_t index) {
|
||||||
return isDisplayValid(int32_t(index))
|
return isDisplayValid(int32_t(index))
|
||||||
? toHmonitor(index)
|
? toHmonitor(index)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
HMONITOR Sdl2WsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
||||||
return enumMonitors(index);
|
return enumMonitors(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getDisplayName(
|
bool Sdl2WsiDriver::getDisplayName(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WCHAR (&Name)[32]) {
|
WCHAR (&Name)[32]) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -47,7 +49,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopCoordinates(
|
bool Sdl2WsiDriver::getDesktopCoordinates(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
RECT* pRect) {
|
RECT* pRect) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -90,7 +92,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDisplayMode(
|
bool Sdl2WsiDriver::getDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
uint32_t ModeNumber,
|
uint32_t ModeNumber,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
|
@ -109,7 +111,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getCurrentDisplayMode(
|
bool Sdl2WsiDriver::getCurrentDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -129,7 +131,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopDisplayMode(
|
bool Sdl2WsiDriver::getDesktopDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
const int32_t displayId = fromHmonitor(hMonitor);
|
const int32_t displayId = fromHmonitor(hMonitor);
|
||||||
|
@ -148,9 +150,11 @@ namespace dxvk::wsi {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> getMonitorEdid(HMONITOR hMonitor) {
|
std::vector<uint8_t> Sdl2WsiDriver::getMonitorEdid(HMONITOR hMonitor) {
|
||||||
Logger::err("getMonitorEdid not implemented on this platform.");
|
Logger::err("getMonitorEdid not implemented on this platform.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
|
||||||
|
#include "wsi_platform_sdl2.h"
|
||||||
|
#include "../../util/util_error.h"
|
||||||
|
#include "../../util/util_string.h"
|
||||||
|
#include "../../util/util_win32_compat.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_vulkan.h>
|
||||||
|
|
||||||
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
Sdl2WsiDriver::Sdl2WsiDriver() {
|
||||||
|
libsdl = LoadLibraryA( // FIXME: Get soname as string from meson
|
||||||
|
#if defined(_WIN32)
|
||||||
|
"SDL2.dll"
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
"libSDL2-2.0.0.dylib"
|
||||||
|
#else
|
||||||
|
"libSDL2-2.0.so.0"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
if (libsdl == nullptr)
|
||||||
|
throw DxvkError("SDL2 WSI: Failed to load SDL2 DLL.");
|
||||||
|
|
||||||
|
#define SDL_PROC(ret, name, params) \
|
||||||
|
name = reinterpret_cast<pfn_##name>(GetProcAddress(libsdl, #name)); \
|
||||||
|
if (name == nullptr) { \
|
||||||
|
FreeLibrary(libsdl); \
|
||||||
|
libsdl = nullptr; \
|
||||||
|
throw DxvkError("SDL2 WSI: Failed to load " #name "."); \
|
||||||
|
}
|
||||||
|
#include "wsi_platform_sdl2_funcs.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
Sdl2WsiDriver::~Sdl2WsiDriver() {
|
||||||
|
FreeLibrary(libsdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char *> Sdl2WsiDriver::getInstanceExtensions() {
|
||||||
|
SDL_Vulkan_LoadLibrary(nullptr);
|
||||||
|
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, nullptr))
|
||||||
|
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", SDL_GetError()));
|
||||||
|
|
||||||
|
auto extensionNames = std::vector<const char *>(extensionCount);
|
||||||
|
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data()))
|
||||||
|
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError()));
|
||||||
|
|
||||||
|
return extensionNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createSdl2WsiDriver(WsiDriver **driver) {
|
||||||
|
try {
|
||||||
|
*driver = new Sdl2WsiDriver();
|
||||||
|
} catch (const DxvkError& e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WsiBootstrap Sdl2WSI = {
|
||||||
|
"SDL2",
|
||||||
|
createSdl2WsiDriver
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,21 +1,108 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include "../wsi_monitor.h"
|
#include "../wsi_platform.h"
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
/**
|
class Sdl2WsiDriver : public WsiDriver {
|
||||||
* \brief Impl-dependent state
|
private:
|
||||||
*/
|
HMODULE libsdl;
|
||||||
struct DxvkWindowState {
|
#define SDL_PROC(ret, name, params) \
|
||||||
|
typedef ret (SDLCALL *pfn_##name) params; \
|
||||||
|
pfn_##name name;
|
||||||
|
#include "wsi_platform_sdl2_funcs.h"
|
||||||
|
|
||||||
|
inline bool isDisplayValid(int32_t displayId) {
|
||||||
|
const int32_t displayCount = SDL_GetNumVideoDisplays();
|
||||||
|
|
||||||
|
return displayId < displayCount && displayId >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Sdl2WsiDriver();
|
||||||
|
~Sdl2WsiDriver();
|
||||||
|
|
||||||
|
// Platform
|
||||||
|
virtual std::vector<const char *> getInstanceExtensions();
|
||||||
|
|
||||||
|
// Monitor
|
||||||
|
virtual HMONITOR getDefaultMonitor();
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(uint32_t index);
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index);
|
||||||
|
|
||||||
|
virtual bool getDisplayName(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WCHAR (&Name)[32]);
|
||||||
|
|
||||||
|
virtual bool getDesktopCoordinates(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
RECT* pRect);
|
||||||
|
|
||||||
|
virtual bool getDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
uint32_t modeNumber,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getCurrentDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getDesktopDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor);
|
||||||
|
|
||||||
|
// Window
|
||||||
|
|
||||||
|
virtual void getWindowSize(
|
||||||
|
HWND hWindow,
|
||||||
|
uint32_t* pWidth,
|
||||||
|
uint32_t* pWeight);
|
||||||
|
|
||||||
|
virtual void resizeWindow(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t weight);
|
||||||
|
|
||||||
|
virtual bool setWindowMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
const WsiMode& mode);
|
||||||
|
|
||||||
|
virtual bool enterFullscreenMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
[[maybe_unused]]
|
||||||
|
bool modeSwitch);
|
||||||
|
|
||||||
|
virtual bool leaveFullscreenMode(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
bool restoreCoordinates);
|
||||||
|
|
||||||
|
virtual bool restoreDisplayMode();
|
||||||
|
|
||||||
|
virtual HMONITOR getWindowMonitor(HWND hWindow);
|
||||||
|
|
||||||
|
virtual bool isWindow(HWND hWindow);
|
||||||
|
|
||||||
|
virtual void updateFullscreenWindow(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
bool forceTopmost);
|
||||||
|
|
||||||
|
virtual VkResult createSurface(
|
||||||
|
HWND hWindow,
|
||||||
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool isDisplayValid(int32_t displayId) {
|
|
||||||
const int32_t displayCount = SDL_GetNumVideoDisplays();
|
|
||||||
|
|
||||||
return displayId < displayCount && displayId >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
SDL_PROC(SDL_DisplayMode*, SDL_GetClosestDisplayMode, (int, const SDL_DisplayMode*, SDL_DisplayMode*))
|
||||||
|
SDL_PROC(int, SDL_GetCurrentDisplayMode, (int, SDL_DisplayMode*))
|
||||||
|
SDL_PROC(int, SDL_GetDesktopDisplayMode, (int, SDL_DisplayMode*))
|
||||||
|
SDL_PROC(int, SDL_GetDisplayBounds, (int, SDL_Rect*))
|
||||||
|
SDL_PROC(int, SDL_GetDisplayMode, (int, int, SDL_DisplayMode*))
|
||||||
|
SDL_PROC(const char*, SDL_GetError, (void))
|
||||||
|
SDL_PROC(int, SDL_GetNumVideoDisplays, (void))
|
||||||
|
SDL_PROC(int, SDL_GetWindowDisplayIndex, (SDL_Window*))
|
||||||
|
SDL_PROC(int, SDL_SetWindowDisplayMode, (SDL_Window*, const SDL_DisplayMode*))
|
||||||
|
SDL_PROC(int, SDL_SetWindowFullscreen, (SDL_Window*, Uint32))
|
||||||
|
SDL_PROC(void, SDL_GetWindowSize, (SDL_Window*, int*, int*))
|
||||||
|
SDL_PROC(void, SDL_SetWindowSize, (SDL_Window*, int, int))
|
||||||
|
SDL_PROC(SDL_bool, SDL_Vulkan_CreateSurface, (SDL_Window*, VkInstance, VkSurfaceKHR*))
|
||||||
|
SDL_PROC(SDL_bool, SDL_Vulkan_GetInstanceExtensions, (SDL_Window*, unsigned int*, const char**))
|
||||||
|
SDL_PROC(int, SDL_Vulkan_LoadLibrary, (const char*))
|
||||||
|
#undef SDL_PROC
|
|
@ -1,17 +1,19 @@
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
|
||||||
#include "../wsi_window.h"
|
#include "../wsi_window.h"
|
||||||
|
|
||||||
#include "native/wsi/native_wsi.h"
|
#include "native/wsi/native_sdl2.h"
|
||||||
#include "wsi_platform_sdl2.h"
|
#include "wsi_platform_sdl2.h"
|
||||||
|
|
||||||
#include "../../util/util_string.h"
|
#include "../../util/util_string.h"
|
||||||
#include "../../util/log/log.h"
|
#include "../../util/log/log.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <SDL2/SDL_vulkan.h>
|
#include <SDL_vulkan.h>
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
void getWindowSize(
|
void Sdl2WsiDriver::getWindowSize(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
uint32_t* pWidth,
|
uint32_t* pWidth,
|
||||||
uint32_t* pHeight) {
|
uint32_t* pHeight) {
|
||||||
|
@ -28,7 +30,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void resizeWindow(
|
void Sdl2WsiDriver::resizeWindow(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
uint32_t Width,
|
uint32_t Width,
|
||||||
|
@ -39,7 +41,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool setWindowMode(
|
bool Sdl2WsiDriver::setWindowMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
const WsiMode& pMode) {
|
const WsiMode& pMode) {
|
||||||
|
@ -73,7 +75,7 @@ namespace dxvk::wsi {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool enterFullscreenMode(
|
bool Sdl2WsiDriver::enterFullscreenMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
|
@ -99,7 +101,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool leaveFullscreenMode(
|
bool Sdl2WsiDriver::leaveFullscreenMode(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
bool restoreCoordinates) {
|
bool restoreCoordinates) {
|
||||||
|
@ -114,13 +116,13 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool restoreDisplayMode() {
|
bool Sdl2WsiDriver::restoreDisplayMode() {
|
||||||
// Don't need to do anything with SDL2 here.
|
// Don't need to do anything with SDL2 here.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
HMONITOR Sdl2WsiDriver::getWindowMonitor(HWND hWindow) {
|
||||||
SDL_Window* window = fromHwnd(hWindow);
|
SDL_Window* window = fromHwnd(hWindow);
|
||||||
const int32_t displayId = SDL_GetWindowDisplayIndex(window);
|
const int32_t displayId = SDL_GetWindowDisplayIndex(window);
|
||||||
|
|
||||||
|
@ -128,13 +130,13 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isWindow(HWND hWindow) {
|
bool Sdl2WsiDriver::isWindow(HWND hWindow) {
|
||||||
SDL_Window* window = fromHwnd(hWindow);
|
SDL_Window* window = fromHwnd(hWindow);
|
||||||
return window != nullptr;
|
return window != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void updateFullscreenWindow(
|
void Sdl2WsiDriver::updateFullscreenWindow(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
bool forceTopmost) {
|
bool forceTopmost) {
|
||||||
|
@ -142,7 +144,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkResult createSurface(
|
VkResult Sdl2WsiDriver::createSurface(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
VkInstance instance,
|
VkInstance instance,
|
||||||
|
@ -155,3 +157,5 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "../wsi_monitor.h"
|
#if defined(DXVK_WSI_WIN32)
|
||||||
|
|
||||||
|
#include "wsi_platform_win32.h"
|
||||||
|
|
||||||
#include "../../util/util_string.h"
|
#include "../../util/util_string.h"
|
||||||
#include "../../util/log/log.h"
|
#include "../../util/log/log.h"
|
||||||
|
@ -13,7 +15,7 @@
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
HMONITOR getDefaultMonitor() {
|
HMONITOR Win32WsiDriver::getDefaultMonitor() {
|
||||||
return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ namespace dxvk::wsi {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMONITOR enumMonitors(uint32_t index) {
|
HMONITOR Win32WsiDriver::enumMonitors(uint32_t index) {
|
||||||
MonitorEnumInfo info;
|
MonitorEnumInfo info;
|
||||||
info.iMonitorId = index;
|
info.iMonitorId = index;
|
||||||
info.oMonitor = nullptr;
|
info.oMonitor = nullptr;
|
||||||
|
@ -58,7 +60,7 @@ namespace dxvk::wsi {
|
||||||
return info.oMonitor;
|
return info.oMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
HMONITOR Win32WsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
||||||
if (!numLUIDs)
|
if (!numLUIDs)
|
||||||
return enumMonitors(index);
|
return enumMonitors(index);
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDisplayName(
|
bool Win32WsiDriver::getDisplayName(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WCHAR (&Name)[32]) {
|
WCHAR (&Name)[32]) {
|
||||||
// Query monitor info to get the device name
|
// Query monitor info to get the device name
|
||||||
|
@ -150,7 +152,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopCoordinates(
|
bool Win32WsiDriver::getDesktopCoordinates(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
RECT* pRect) {
|
RECT* pRect) {
|
||||||
::MONITORINFOEXW monInfo;
|
::MONITORINFOEXW monInfo;
|
||||||
|
@ -200,7 +202,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDisplayMode(
|
bool Win32WsiDriver::getDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
uint32_t modeNumber,
|
uint32_t modeNumber,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
|
@ -208,14 +210,14 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getCurrentDisplayMode(
|
bool Win32WsiDriver::getCurrentDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode);
|
return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getDesktopDisplayMode(
|
bool Win32WsiDriver::getDesktopDisplayMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
WsiMode* pMode) {
|
WsiMode* pMode) {
|
||||||
return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode);
|
return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode);
|
||||||
|
@ -308,7 +310,7 @@ namespace dxvk::wsi {
|
||||||
wchar_t extraChars[MAX_DEVICE_ID_LEN];
|
wchar_t extraChars[MAX_DEVICE_ID_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
WsiEdidData getMonitorEdid(HMONITOR hMonitor) {
|
WsiEdidData Win32WsiDriver::getMonitorEdid(HMONITOR hMonitor) {
|
||||||
static constexpr GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 };
|
static constexpr GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 };
|
||||||
static auto pfnSetupDiGetClassDevsW = reinterpret_cast<decltype(SetupDiGetClassDevsW)*> (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiGetClassDevsW"));
|
static auto pfnSetupDiGetClassDevsW = reinterpret_cast<decltype(SetupDiGetClassDevsW)*> (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiGetClassDevsW"));
|
||||||
static auto pfnSetupDiEnumDeviceInterfaces = reinterpret_cast<decltype(SetupDiEnumDeviceInterfaces)*> (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiEnumDeviceInterfaces"));
|
static auto pfnSetupDiEnumDeviceInterfaces = reinterpret_cast<decltype(SetupDiEnumDeviceInterfaces)*> (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiEnumDeviceInterfaces"));
|
||||||
|
@ -370,3 +372,5 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#if defined(DXVK_WSI_WIN32)
|
||||||
|
|
||||||
|
#include "wsi_platform_win32.h"
|
||||||
|
|
||||||
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
std::vector<const char *> Win32WsiDriver::getInstanceExtensions() {
|
||||||
|
return { VK_KHR_WIN32_SURFACE_EXTENSION_NAME };
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool createWin32WsiDriver(WsiDriver **driver) {
|
||||||
|
*driver = new Win32WsiDriver();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WsiBootstrap Win32WSI = {
|
||||||
|
"Win32",
|
||||||
|
createWin32WsiDriver
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,15 +2,91 @@
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "../wsi_platform.h"
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
/**
|
class Win32WsiDriver : public WsiDriver {
|
||||||
* \brief Impl-dependent state
|
public:
|
||||||
*/
|
// Platform
|
||||||
struct DxvkWindowState {
|
virtual std::vector<const char *> getInstanceExtensions();
|
||||||
LONG style = 0;
|
|
||||||
LONG exstyle = 0;
|
// Monitor
|
||||||
RECT rect = { 0, 0, 0, 0 };
|
virtual HMONITOR getDefaultMonitor();
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(uint32_t index);
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index);
|
||||||
|
|
||||||
|
virtual bool getDisplayName(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WCHAR (&Name)[32]);
|
||||||
|
|
||||||
|
virtual bool getDesktopCoordinates(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
RECT* pRect);
|
||||||
|
|
||||||
|
virtual bool getDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
uint32_t modeNumber,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getCurrentDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual bool getDesktopDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode);
|
||||||
|
|
||||||
|
virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor);
|
||||||
|
|
||||||
|
// Window
|
||||||
|
|
||||||
|
virtual void getWindowSize(
|
||||||
|
HWND hWindow,
|
||||||
|
uint32_t* pWidth,
|
||||||
|
uint32_t* pWeight);
|
||||||
|
|
||||||
|
virtual void resizeWindow(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t weight);
|
||||||
|
|
||||||
|
virtual bool setWindowMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
const WsiMode& mode);
|
||||||
|
|
||||||
|
virtual bool enterFullscreenMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
[[maybe_unused]]
|
||||||
|
bool modeSwitch);
|
||||||
|
|
||||||
|
virtual bool leaveFullscreenMode(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
bool restoreCoordinates);
|
||||||
|
|
||||||
|
virtual bool restoreDisplayMode();
|
||||||
|
|
||||||
|
virtual HMONITOR getWindowMonitor(HWND hWindow);
|
||||||
|
|
||||||
|
virtual bool isWindow(HWND hWindow);
|
||||||
|
|
||||||
|
virtual void updateFullscreenWindow(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
bool forceTopmost);
|
||||||
|
|
||||||
|
virtual VkResult createSurface(
|
||||||
|
HWND hWindow,
|
||||||
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR* pSurface);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "../wsi_window.h"
|
#if defined(DXVK_WSI_WIN32)
|
||||||
#include "../wsi_monitor.h"
|
|
||||||
|
#include "wsi_platform_win32.h"
|
||||||
|
|
||||||
#include "../../util/util_string.h"
|
#include "../../util/util_string.h"
|
||||||
#include "../../util/log/log.h"
|
#include "../../util/log/log.h"
|
||||||
|
@ -94,7 +95,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void getWindowSize(
|
void Win32WsiDriver::getWindowSize(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
uint32_t* pWidth,
|
uint32_t* pWidth,
|
||||||
uint32_t* pHeight) {
|
uint32_t* pHeight) {
|
||||||
|
@ -109,7 +110,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void resizeWindow(
|
void Win32WsiDriver::resizeWindow(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
|
@ -130,7 +131,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool setWindowMode(
|
bool Win32WsiDriver::setWindowMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
const WsiMode& mode) {
|
const WsiMode& mode) {
|
||||||
|
@ -163,21 +164,21 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool enterFullscreenMode(
|
bool Win32WsiDriver::enterFullscreenMode(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
bool modeSwitch) {
|
bool modeSwitch) {
|
||||||
// Find a display mode that matches what we need
|
// Find a display mode that matches what we need
|
||||||
::GetWindowRect(hWindow, &pState->rect);
|
::GetWindowRect(hWindow, &pState->win.rect);
|
||||||
|
|
||||||
// Change the window flags to remove the decoration etc.
|
// Change the window flags to remove the decoration etc.
|
||||||
LONG style = ::GetWindowLongW(hWindow, GWL_STYLE);
|
LONG style = ::GetWindowLongW(hWindow, GWL_STYLE);
|
||||||
LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE);
|
LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE);
|
||||||
|
|
||||||
pState->style = style;
|
pState->win.style = style;
|
||||||
pState->exstyle = exstyle;
|
pState->win.exstyle = exstyle;
|
||||||
|
|
||||||
style &= ~WS_OVERLAPPEDWINDOW;
|
style &= ~WS_OVERLAPPEDWINDOW;
|
||||||
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
|
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
|
||||||
|
@ -196,7 +197,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool leaveFullscreenMode(
|
bool Win32WsiDriver::leaveFullscreenMode(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
DxvkWindowState* pState,
|
DxvkWindowState* pState,
|
||||||
bool restoreCoordinates) {
|
bool restoreCoordinates) {
|
||||||
|
@ -205,27 +206,27 @@ namespace dxvk::wsi {
|
||||||
LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE;
|
LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE;
|
||||||
LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
|
LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
|
||||||
|
|
||||||
if (curStyle == (pState->style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
if (curStyle == (pState->win.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
||||||
&& curExstyle == (pState->exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
&& curExstyle == (pState->win.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
||||||
::SetWindowLongW(hWindow, GWL_STYLE, pState->style);
|
::SetWindowLongW(hWindow, GWL_STYLE, pState->win.style);
|
||||||
::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->exstyle);
|
::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->win.exstyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore window position and apply the style
|
// Restore window position and apply the style
|
||||||
UINT flags = SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
UINT flags = SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
||||||
const RECT rect = pState->rect;
|
const RECT rect = pState->win.rect;
|
||||||
|
|
||||||
if (!restoreCoordinates)
|
if (!restoreCoordinates)
|
||||||
flags |= SWP_NOSIZE | SWP_NOMOVE;
|
flags |= SWP_NOSIZE | SWP_NOMOVE;
|
||||||
|
|
||||||
::SetWindowPos(hWindow, (pState->exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST,
|
::SetWindowPos(hWindow, (pState->win.exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags);
|
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool restoreDisplayMode() {
|
bool Win32WsiDriver::restoreDisplayMode() {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
bool result = ::EnumDisplayMonitors(nullptr, nullptr,
|
bool result = ::EnumDisplayMonitors(nullptr, nullptr,
|
||||||
&restoreDisplayModeCallback,
|
&restoreDisplayModeCallback,
|
||||||
|
@ -235,7 +236,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
HMONITOR Win32WsiDriver::getWindowMonitor(HWND hWindow) {
|
||||||
RECT windowRect = { 0, 0, 0, 0 };
|
RECT windowRect = { 0, 0, 0, 0 };
|
||||||
::GetWindowRect(hWindow, &windowRect);
|
::GetWindowRect(hWindow, &windowRect);
|
||||||
|
|
||||||
|
@ -248,12 +249,12 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isWindow(HWND hWindow) {
|
bool Win32WsiDriver::isWindow(HWND hWindow) {
|
||||||
return ::IsWindow(hWindow);
|
return ::IsWindow(hWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void updateFullscreenWindow(
|
void Win32WsiDriver::updateFullscreenWindow(
|
||||||
HMONITOR hMonitor,
|
HMONITOR hMonitor,
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
bool forceTopmost) {
|
bool forceTopmost) {
|
||||||
|
@ -274,7 +275,7 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkResult createSurface(
|
VkResult Win32WsiDriver::createSurface(
|
||||||
HWND hWindow,
|
HWND hWindow,
|
||||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
VkInstance instance,
|
VkInstance instance,
|
||||||
|
@ -296,3 +297,5 @@ namespace dxvk::wsi {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
#include "wsi_platform.h"
|
||||||
|
#include "wsi_monitor.h"
|
||||||
|
#include "wsi_window.h"
|
||||||
|
#include "../util/util_env.h"
|
||||||
|
#include "../util/util_error.h"
|
||||||
|
|
||||||
|
namespace dxvk::wsi {
|
||||||
|
static WsiDriver* s_driver = nullptr;
|
||||||
|
static int s_refcount = 0;
|
||||||
|
|
||||||
|
static const WsiBootstrap *wsiBootstrap[] = {
|
||||||
|
#if defined(DXVK_WSI_WIN32)
|
||||||
|
&Win32WSI,
|
||||||
|
#endif
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
&Sdl2WSI,
|
||||||
|
#endif
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
&GlfwWSI,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
if (s_refcount++ > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string hint = dxvk::env::getEnvVar("DXVK_WSI_DRIVER");
|
||||||
|
if (hint == "") {
|
||||||
|
// At least for Windows, it is reasonable to fall back to a default;
|
||||||
|
// for other platforms however we _need_ to know which WSI to use!
|
||||||
|
#if defined(DXVK_WSI_WIN32)
|
||||||
|
hint = "Win32";
|
||||||
|
#else
|
||||||
|
throw DxvkError("DXVK_WSI_DRIVER environment variable unset");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
for (const WsiBootstrap *b : wsiBootstrap) {
|
||||||
|
if (hint == b->name && b->createDriver(&s_driver)) {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
throw DxvkError("Failed to initialize WSI.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
if (s_refcount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_refcount--;
|
||||||
|
if (s_refcount == 0) {
|
||||||
|
delete s_driver;
|
||||||
|
s_driver = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char *> getInstanceExtensions() {
|
||||||
|
return s_driver->getInstanceExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getWindowSize(
|
||||||
|
HWND hWindow,
|
||||||
|
uint32_t* pWidth,
|
||||||
|
uint32_t* pHeight) {
|
||||||
|
s_driver->getWindowSize(hWindow, pWidth, pHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeWindow(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
s_driver->resizeWindow(hWindow, pState, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setWindowMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
const WsiMode& mode) {
|
||||||
|
return s_driver->setWindowMode(hMonitor, hWindow, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enterFullscreenMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
[[maybe_unused]]
|
||||||
|
bool modeSwitch) {
|
||||||
|
return s_driver->enterFullscreenMode(hMonitor, hWindow, pState, modeSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool leaveFullscreenMode(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
bool restoreCoordinates) {
|
||||||
|
return s_driver->leaveFullscreenMode(hWindow, pState, restoreCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool restoreDisplayMode() {
|
||||||
|
return s_driver->restoreDisplayMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
HMONITOR getWindowMonitor(HWND hWindow) {
|
||||||
|
return s_driver->getWindowMonitor(hWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWindow(HWND hWindow) {
|
||||||
|
return s_driver->isWindow(hWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateFullscreenWindow(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
bool forceTopmost) {
|
||||||
|
s_driver->updateFullscreenWindow(hMonitor, hWindow, forceTopmost);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult createSurface(
|
||||||
|
HWND hWindow,
|
||||||
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR* pSurface) {
|
||||||
|
return s_driver->createSurface(hWindow, pfnVkGetInstanceProcAddr, instance, pSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMONITOR getDefaultMonitor() {
|
||||||
|
return s_driver->getDefaultMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
HMONITOR enumMonitors(uint32_t index) {
|
||||||
|
return s_driver->enumMonitors(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
|
||||||
|
return s_driver->enumMonitors(adapterLUID, numLUIDs, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getDisplayName(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WCHAR (&Name)[32]) {
|
||||||
|
return s_driver->getDisplayName(hMonitor, Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getDesktopCoordinates(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
RECT* pRect) {
|
||||||
|
return s_driver->getDesktopCoordinates(hMonitor, pRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
uint32_t modeNumber,
|
||||||
|
WsiMode* pMode) {
|
||||||
|
return s_driver->getDisplayMode(hMonitor, modeNumber, pMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCurrentDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode) {
|
||||||
|
return s_driver->getCurrentDisplayMode(hMonitor, pMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getDesktopDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode) {
|
||||||
|
return s_driver->getDesktopDisplayMode(hMonitor, pMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
WsiEdidData getMonitorEdid(HMONITOR hMonitor) {
|
||||||
|
return s_driver->getMonitorEdid(hMonitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,114 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "wsi_window.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
class WsiDriver {
|
||||||
|
public:
|
||||||
|
virtual ~WsiDriver() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform
|
||||||
|
virtual std::vector<const char *> getInstanceExtensions() = 0;
|
||||||
|
|
||||||
|
// Monitor
|
||||||
|
virtual HMONITOR getDefaultMonitor() = 0;
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(uint32_t index) = 0;
|
||||||
|
|
||||||
|
virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) = 0;
|
||||||
|
|
||||||
|
virtual bool getDisplayName(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WCHAR (&Name)[32]) = 0;
|
||||||
|
|
||||||
|
virtual bool getDesktopCoordinates(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
RECT* pRect) = 0;
|
||||||
|
|
||||||
|
virtual bool getDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
uint32_t modeNumber,
|
||||||
|
WsiMode* pMode) = 0;
|
||||||
|
|
||||||
|
virtual bool getCurrentDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode) = 0;
|
||||||
|
|
||||||
|
virtual bool getDesktopDisplayMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
WsiMode* pMode) = 0;
|
||||||
|
|
||||||
|
virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor) = 0;
|
||||||
|
|
||||||
|
// Window
|
||||||
|
|
||||||
|
virtual void getWindowSize(
|
||||||
|
HWND hWindow,
|
||||||
|
uint32_t* pWidth,
|
||||||
|
uint32_t* pWeight) = 0;
|
||||||
|
|
||||||
|
virtual void resizeWindow(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t weight) = 0;
|
||||||
|
|
||||||
|
virtual bool setWindowMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
const WsiMode& mode) = 0;
|
||||||
|
|
||||||
|
virtual bool enterFullscreenMode(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
[[maybe_unused]]
|
||||||
|
bool modeSwitch) = 0;
|
||||||
|
|
||||||
|
virtual bool leaveFullscreenMode(
|
||||||
|
HWND hWindow,
|
||||||
|
DxvkWindowState* pState,
|
||||||
|
bool restoreCoordinates) = 0;
|
||||||
|
|
||||||
|
virtual bool restoreDisplayMode() = 0;
|
||||||
|
|
||||||
|
virtual HMONITOR getWindowMonitor(HWND hWindow) = 0;
|
||||||
|
|
||||||
|
virtual bool isWindow(HWND hWindow) = 0;
|
||||||
|
|
||||||
|
virtual void updateFullscreenWindow(
|
||||||
|
HMONITOR hMonitor,
|
||||||
|
HWND hWindow,
|
||||||
|
bool forceTopmost) = 0;
|
||||||
|
|
||||||
|
virtual VkResult createSurface(
|
||||||
|
HWND hWindow,
|
||||||
|
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||||
|
VkInstance instance,
|
||||||
|
VkSurfaceKHR* pSurface) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WsiBootstrap {
|
||||||
|
const std::string name;
|
||||||
|
bool (*createDriver)(WsiDriver **driver);
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(DXVK_WSI_WIN32)
|
#if defined(DXVK_WSI_WIN32)
|
||||||
#include "win32/wsi_platform_win32.h"
|
extern WsiBootstrap Win32WSI;
|
||||||
#elif defined(DXVK_WSI_SDL2)
|
|
||||||
#include "sdl2/wsi_platform_sdl2.h"
|
|
||||||
#elif defined(DXVK_WSI_GLFW)
|
|
||||||
#include "glfw/wsi_platform_glfw.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
extern WsiBootstrap Sdl2WSI;
|
||||||
|
#endif
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
extern WsiBootstrap GlfwWSI;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void quit();
|
||||||
|
std::vector<const char *> getInstanceExtensions();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -3,12 +3,30 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "wsi_monitor.h"
|
#include "wsi_monitor.h"
|
||||||
#include "wsi_platform.h"
|
|
||||||
|
|
||||||
#include "../vulkan/vulkan_loader.h"
|
#include "../vulkan/vulkan_loader.h"
|
||||||
|
|
||||||
namespace dxvk::wsi {
|
namespace dxvk::wsi {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Impl-dependent state
|
||||||
|
*/
|
||||||
|
struct DxvkWindowState {
|
||||||
|
#if defined(DXVK_WSI_WIN32)
|
||||||
|
struct {
|
||||||
|
LONG style = 0;
|
||||||
|
LONG exstyle = 0;
|
||||||
|
RECT rect = { 0, 0, 0, 0 };
|
||||||
|
} win;
|
||||||
|
#endif
|
||||||
|
#if defined(DXVK_WSI_SDL2)
|
||||||
|
// Nothing to store
|
||||||
|
#endif
|
||||||
|
#if defined(DXVK_WSI_GLFW)
|
||||||
|
// Nothing to store
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The size of the window
|
* \brief The size of the window
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue