mirror of https://github.com/doitsujin/dxvk
Compare commits
48 Commits
Author | SHA1 | Date |
---|---|---|
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 |
19
README.md
19
README.md
|
@ -163,3 +163,22 @@ For non debian based distros, make sure that your mingw-w64-gcc cross compiler
|
|||
does have `--enable-threads=posix` enabled during configure. If your distro does
|
||||
ship its mingw-w64-gcc binary with `--enable-threads=win32` you might have to
|
||||
recompile locally or open a bug at your distro's bugtracker to ask for it.
|
||||
|
||||
# DXVK Native
|
||||
|
||||
DXVK Native is a version of DXVK which allows it to be used natively without Wine.
|
||||
|
||||
This is primarily useful for game and application ports to either avoid having to write another rendering backend, or to help with port bringup during development.
|
||||
|
||||
[Release builds](https://github.com/doitsujin/dxvk/releases) are built using the Steam Runtime.
|
||||
|
||||
### How does it work?
|
||||
|
||||
DXVK Native replaces certain Windows-isms with a platform and framework-agnostic replacement, for example, `HWND`s can become `SDL_Window*`s, etc.
|
||||
All it takes to do that is to add another WSI backend.
|
||||
|
||||
**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL2` and `GLFW`.
|
||||
|
||||
DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
|
||||
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
|
||||
- `__uuidof(type)` is supported, but `__uuidof(variable)` is not supported. Use `__uuidof_var(variable)` instead.
|
||||
|
|
17
dxvk.conf
17
dxvk.conf
|
@ -499,6 +499,7 @@
|
|||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d11.longMad = False
|
||||
# d3d9.longMad = False
|
||||
|
||||
# Device Local Constant Buffers
|
||||
|
@ -514,7 +515,9 @@
|
|||
|
||||
# Support DF formats
|
||||
#
|
||||
# Support the vendor extension DF floating point depth formats
|
||||
# Support the vendor extension DF floating point depth formats on AMD and Intel.
|
||||
# Note that this config is ignored and disabled by default on Nvidia, or when
|
||||
# spoofing a Nvidia GPU, as it does not support these formats natively.
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
@ -644,18 +647,6 @@
|
|||
|
||||
# d3d9.textureMemory = 100
|
||||
|
||||
# Always enumerate all monitors on each dxgi output
|
||||
#
|
||||
# Used to avoid performance degradation in some games
|
||||
# (will be deprecated once QueryDisplayConfig optimization
|
||||
# is in Proton Wine).
|
||||
#
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# dxgi.useMonitorFallback = False
|
||||
|
||||
|
||||
# Hide integrated graphics from applications
|
||||
#
|
||||
# Only has an effect when dedicated GPUs are present on the system. It is
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
|
@ -22,4 +22,4 @@ namespace dxvk::wsi {
|
|||
return reinterpret_cast<HMONITOR>(static_cast<intptr_t>(displayId + 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
17
meson.build
17
meson.build
|
@ -115,7 +115,6 @@ if platform == 'windows'
|
|||
)
|
||||
endif
|
||||
|
||||
dxvk_wsi = 'win32'
|
||||
dxvk_name_prefix = ''
|
||||
compiler_args += ['-DDXVK_WSI_WIN32']
|
||||
else
|
||||
|
@ -128,15 +127,17 @@ else
|
|||
'./include/native/directx'
|
||||
]
|
||||
|
||||
dxvk_wsi = get_option('dxvk_native_wsi')
|
||||
|
||||
if dxvk_wsi == 'sdl2'
|
||||
lib_sdl2 = cpp.find_library('SDL2')
|
||||
lib_sdl2 = dependency('SDL2', required: false)
|
||||
lib_glfw = dependency('glfw', required: false)
|
||||
if lib_sdl2.found()
|
||||
compiler_args += ['-DDXVK_WSI_SDL2']
|
||||
elif dxvk_wsi == 'glfw'
|
||||
lib_glfw = cpp.find_library('glfw')
|
||||
endif
|
||||
if lib_glfw.found()
|
||||
compiler_args += ['-DDXVK_WSI_GLFW']
|
||||
endif
|
||||
if (not lib_sdl2.found() and not lib_glfw.found())
|
||||
error('SDL2 or GLFW are required to build dxvk-native')
|
||||
endif
|
||||
|
||||
dxvk_name_prefix = 'libdxvk_'
|
||||
|
||||
|
@ -160,7 +161,7 @@ def_spec_ext = '.def'
|
|||
glsl_compiler = find_program('glslang', 'glslangValidator')
|
||||
glsl_args = [
|
||||
'--quiet',
|
||||
'--target-env', 'vulkan1.2',
|
||||
'--target-env', 'vulkan1.3',
|
||||
'--vn', '@BASENAME@',
|
||||
'--depfile', '@DEPFILE@',
|
||||
'@INPUT@',
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace dxvk {
|
|||
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
|
||||
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
|
||||
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
|
||||
this->longMad = config.getOption<bool>("d3d11.longMad", false);
|
||||
|
||||
// Clamp LOD bias so that people don't abuse this in unintended ways
|
||||
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);
|
||||
|
|
|
@ -120,6 +120,9 @@ namespace dxvk {
|
|||
|
||||
/// Shader dump path
|
||||
std::string shaderDumpPath;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
};
|
||||
|
||||
}
|
|
@ -58,9 +58,6 @@ namespace dxvk {
|
|||
"\n MiscFlags: ", m_desc.MiscFlags,
|
||||
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
|
||||
|
||||
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
|
||||
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
|
||||
|
||||
imageInfo.shared = true;
|
||||
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
|
||||
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
|
||||
|
|
|
@ -1262,12 +1262,28 @@ namespace dxvk {
|
|||
viewport.height = float(cStreamState.dstRect.bottom) - viewport.y;
|
||||
}
|
||||
|
||||
VkExtent3D viewExtent = cViews[0]->mipLevelExtent(0);
|
||||
|
||||
VkRect2D srcRect;
|
||||
srcRect.offset = { 0, 0 };
|
||||
srcRect.extent = { viewExtent.width, viewExtent.height };
|
||||
|
||||
if (cStreamState.srcRectEnabled) {
|
||||
srcRect.offset.x = cStreamState.srcRect.left;
|
||||
srcRect.offset.y = cStreamState.srcRect.top;
|
||||
srcRect.extent.width = cStreamState.srcRect.right - srcRect.offset.x;
|
||||
srcRect.extent.height = cStreamState.srcRect.bottom - srcRect.offset.y;
|
||||
}
|
||||
|
||||
UboData uboData = { };
|
||||
uboData.colorMatrix[0][0] = 1.0f;
|
||||
uboData.colorMatrix[1][1] = 1.0f;
|
||||
uboData.colorMatrix[2][2] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = 1.0f;
|
||||
uboData.coordMatrix[1][1] = 1.0f;
|
||||
uboData.coordMatrix[0][0] = float(srcRect.extent.width) / float(viewExtent.width);
|
||||
uboData.coordMatrix[1][1] = float(srcRect.extent.height) / float(viewExtent.height);
|
||||
uboData.coordMatrix[2][0] = float(srcRect.offset.x) / float(viewExtent.width);
|
||||
uboData.coordMatrix[2][1] = float(srcRect.offset.y) / float(viewExtent.height);
|
||||
uboData.srcRect = srcRect;
|
||||
uboData.yMin = 0.0f;
|
||||
uboData.yMax = 1.0f;
|
||||
uboData.isPlanar = cViews[1] != nullptr;
|
||||
|
@ -1290,17 +1306,14 @@ namespace dxvk {
|
|||
ctx->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fs));
|
||||
|
||||
ctx->bindUniformBuffer(VK_SHADER_STAGE_FRAGMENT_BIT, 0, DxvkBufferSlice(m_ubo));
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, Rc<DxvkSampler>(m_sampler));
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, Rc<DxvkImageView>(cViews[i]));
|
||||
|
||||
ctx->draw(3, 1, 0, 0);
|
||||
|
||||
ctx->bindResourceSampler(VK_SHADER_STAGE_FRAGMENT_BIT, 1, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < cViews.size(); i++)
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 2 + i, nullptr);
|
||||
ctx->bindResourceImageView(VK_SHADER_STAGE_FRAGMENT_BIT, 1 + i, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1315,38 +1328,14 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateSampler() {
|
||||
DxvkSamplerCreateInfo samplerInfo;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.mipmapLodBias = 0.0f;
|
||||
samplerInfo.mipmapLodMin = 0.0f;
|
||||
samplerInfo.mipmapLodMax = 0.0f;
|
||||
samplerInfo.useAnisotropy = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.compareToDepth = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
||||
samplerInfo.borderColor = VkClearColorValue();
|
||||
samplerInfo.usePixelCoord = VK_FALSE;
|
||||
samplerInfo.nonSeamless = VK_FALSE;
|
||||
m_sampler = m_device->createSampler(samplerInfo);
|
||||
}
|
||||
|
||||
|
||||
void D3D11VideoContext::CreateShaders() {
|
||||
SpirvCodeBuffer vsCode(d3d11_video_blit_vert);
|
||||
SpirvCodeBuffer fsCode(d3d11_video_blit_frag);
|
||||
|
||||
const std::array<DxvkBindingInfo, 4> fsBindings = {{
|
||||
const std::array<DxvkBindingInfo, 3> fsBindings = {{
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_UNIFORM_READ_BIT, VK_TRUE },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_IMAGE_VIEW_TYPE_MAX_ENUM, VK_SHADER_STAGE_FRAGMENT_BIT, 0 },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 3, VK_IMAGE_VIEW_TYPE_2D, VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT },
|
||||
}};
|
||||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
|
@ -1368,7 +1357,6 @@ namespace dxvk {
|
|||
if (std::exchange(m_resourcesCreated, true))
|
||||
return;
|
||||
|
||||
CreateSampler();
|
||||
CreateUniformBuffer();
|
||||
CreateShaders();
|
||||
}
|
||||
|
|
|
@ -584,6 +584,7 @@ namespace dxvk {
|
|||
struct alignas(16) UboData {
|
||||
float colorMatrix[3][4];
|
||||
float coordMatrix[3][2];
|
||||
VkRect2D srcRect;
|
||||
float yMin, yMax;
|
||||
VkBool32 isPlanar;
|
||||
};
|
||||
|
@ -593,7 +594,6 @@ namespace dxvk {
|
|||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkShader> m_vs;
|
||||
Rc<DxvkShader> m_fs;
|
||||
Rc<DxvkSampler> m_sampler;
|
||||
Rc<DxvkBuffer> m_ubo;
|
||||
|
||||
VkExtent2D m_dstExtent = { 0u, 0u };
|
||||
|
@ -613,8 +613,6 @@ namespace dxvk {
|
|||
|
||||
void CreateUniformBuffer();
|
||||
|
||||
void CreateSampler();
|
||||
|
||||
void CreateShaders();
|
||||
|
||||
void CreateResources();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#version 450
|
||||
|
||||
#extension GL_EXT_samplerless_texture_functions : require
|
||||
|
||||
// Can't use matrix types here since even a two-row
|
||||
// matrix will be padded to 16 bytes per column for
|
||||
// absolutely no reason
|
||||
|
@ -11,6 +13,8 @@ uniform ubo_t {
|
|||
vec2 coord_matrix_c1;
|
||||
vec2 coord_matrix_c2;
|
||||
vec2 coord_matrix_c3;
|
||||
uvec2 src_offset;
|
||||
uvec2 src_extent;
|
||||
float y_min;
|
||||
float y_max;
|
||||
bool is_planar;
|
||||
|
@ -19,9 +23,8 @@ uniform ubo_t {
|
|||
layout(location = 0) in vec2 i_texcoord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler s_sampler;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 3) uniform texture2D s_inputCbCr;
|
||||
layout(set = 0, binding = 1) uniform texture2D s_inputY;
|
||||
layout(set = 0, binding = 2) uniform texture2D s_inputCbCr;
|
||||
|
||||
void main() {
|
||||
// Transform input texture coordinates to
|
||||
|
@ -31,25 +34,61 @@ void main() {
|
|||
coord_matrix_c2,
|
||||
coord_matrix_c3);
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
|
||||
// Fetch source image color
|
||||
vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texture(sampler2D(s_inputY, s_sampler), coord).r;
|
||||
color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
} else {
|
||||
color = texture(sampler2D(s_inputY, s_sampler), coord);
|
||||
}
|
||||
|
||||
// Color space transformation
|
||||
// Load color space transform
|
||||
mat3x4 color_matrix = mat3x4(
|
||||
color_matrix_r1,
|
||||
color_matrix_r2,
|
||||
color_matrix_r3);
|
||||
|
||||
o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
o_color.a = color.a;
|
||||
// Compute actual pixel coordinates to sample. We filter
|
||||
// manually in order to avoid bleeding from pixels outside
|
||||
// the source rectangle.
|
||||
vec2 abs_size_y = vec2(textureSize(s_inputY, 0));
|
||||
vec2 abs_size_c = vec2(textureSize(s_inputCbCr, 0));
|
||||
|
||||
vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f);
|
||||
coord -= 0.5f / abs_size_y;
|
||||
|
||||
vec2 size_factor = abs_size_c / abs_size_y;
|
||||
|
||||
vec2 src_lo = vec2(src_offset);
|
||||
vec2 src_hi = vec2(src_offset + src_extent - 1u);
|
||||
|
||||
vec2 abs_coord = coord * abs_size_y;
|
||||
vec2 fract_coord = fract(clamp(abs_coord, src_lo, src_hi));
|
||||
|
||||
vec4 accum = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ivec2 offset = ivec2(i & 1, i >> 1);
|
||||
|
||||
// Compute exact pixel coordinates for the current
|
||||
// iteration and clamp it to the source rectangle.
|
||||
vec2 fetch_coord = clamp(abs_coord + vec2(offset), src_lo, src_hi);
|
||||
|
||||
// Fetch actual pixel color in source color space
|
||||
vec4 color;
|
||||
|
||||
if (is_planar) {
|
||||
color.g = texelFetch(s_inputY, ivec2(fetch_coord), 0).r;
|
||||
color.rb = texelFetch(s_inputCbCr, ivec2(fetch_coord * size_factor), 0).gr;
|
||||
color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f);
|
||||
color.a = 1.0f;
|
||||
} else {
|
||||
color = texelFetch(s_inputY, ivec2(fetch_coord), 0);
|
||||
}
|
||||
|
||||
// Transform color space before accumulation
|
||||
color.rgb = vec4(color.rgb, 1.0f) * color_matrix;
|
||||
|
||||
// Filter and accumulate final pixel color
|
||||
vec2 factor = fract_coord;
|
||||
|
||||
if (offset.x == 0) factor.x = 1.0f - factor.x;
|
||||
if (offset.y == 0) factor.y = 1.0f - factor.y;
|
||||
|
||||
accum += factor.x * factor.y * color;
|
||||
}
|
||||
|
||||
o_color = accum;
|
||||
}
|
||||
|
|
|
@ -162,6 +162,9 @@ namespace dxvk {
|
|||
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
||||
return D3D_OK;
|
||||
|
||||
|
@ -224,11 +227,15 @@ namespace dxvk {
|
|||
if (!IsDepthFormat(DepthStencilFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto dsfMapping = ConvertFormatUnfixed(DepthStencilFormat);
|
||||
if (dsfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RenderTargetFormat == dxvk::D3D9Format::NULL_FORMAT)
|
||||
return D3D_OK;
|
||||
|
||||
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
auto rtfMapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (rtfMapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return D3D_OK;
|
||||
|
|
|
@ -118,6 +118,7 @@ namespace dxvk {
|
|||
|
||||
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc) {
|
||||
auto* options = pDevice->GetOptions();
|
||||
|
||||
|
@ -131,6 +132,11 @@ namespace dxvk {
|
|||
options->disableA8RT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Cube textures with depth formats are not supported on any native
|
||||
// driver, and allowing them triggers a broken code path in Gothic 3.
|
||||
if (ResourceType == D3DRTYPE_CUBETEXTURE && mapping.Aspect != VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// If the mapping is invalid then lets return invalid
|
||||
// Some edge cases:
|
||||
// NULL format does not map to anything, but should succeed
|
||||
|
|
|
@ -179,11 +179,14 @@ namespace dxvk {
|
|||
* Fills in undefined values and validates the texture
|
||||
* parameters. Any error returned by this method should
|
||||
* be forwarded to the application.
|
||||
* \param [in] pDevice D3D9 device
|
||||
* \param [in] ResourceType Resource type
|
||||
* \param [in,out] pDesc Texture description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc);
|
||||
|
||||
/**
|
||||
|
|
|
@ -594,7 +594,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -664,7 +664,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_VOLUMETEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -721,7 +721,7 @@ namespace dxvk {
|
|||
|| (Usage & D3DUSAGE_DYNAMIC)
|
||||
|| IsVendorFormat(EnumerateFormat(Format));
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_CUBETEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -3798,7 +3798,7 @@ namespace dxvk {
|
|||
desc.IsAttachmentOnly = TRUE;
|
||||
desc.IsLockable = Lockable;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -3846,7 +3846,7 @@ namespace dxvk {
|
|||
// Docs: Off-screen plain surfaces are always lockable, regardless of their pool types.
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (pSharedHandle != nullptr && Pool != D3DPOOL_DEFAULT)
|
||||
|
@ -3901,7 +3901,7 @@ namespace dxvk {
|
|||
// Docs don't say anything, so just assume it's lockable.
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
try {
|
||||
|
@ -7891,7 +7891,7 @@ namespace dxvk {
|
|||
// Docs: Also note that - unlike textures - swap chain back buffers, render targets [..] can be locked
|
||||
desc.IsLockable = TRUE;
|
||||
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, &desc)))
|
||||
if (FAILED(D3D9CommonTexture::NormalizeTextureProperties(this, D3DRTYPE_TEXTURE, &desc)))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
m_autoDepthStencil = new D3D9Surface(this, &desc, nullptr, nullptr);
|
||||
|
|
|
@ -336,7 +336,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count) {
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule) {
|
||||
uint32_t floatType = spvModule.defFloatType(32);
|
||||
uint32_t uintType = spvModule.defIntType(32, 0);
|
||||
uint32_t vec3Type = spvModule.defVectorType(floatType, 3);
|
||||
|
@ -357,7 +357,7 @@ namespace dxvk {
|
|||
floatType,
|
||||
}};
|
||||
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(count, rsMembers.data());
|
||||
uint32_t rsStruct = spvModule.defStructTypeUnique(rsMembers.size(), rsMembers.data());
|
||||
uint32_t rsBlock = spvModule.newVar(
|
||||
spvModule.defPointerType(rsStruct, spv::StorageClassPushConstant),
|
||||
spv::StorageClassPushConstant);
|
||||
|
@ -369,9 +369,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t memberIdx = 0;
|
||||
auto SetMemberName = [&](const char* name, uint32_t offset) {
|
||||
if (memberIdx >= count)
|
||||
return;
|
||||
|
||||
spvModule.setDebugMemberName (rsStruct, memberIdx, name);
|
||||
spvModule.memberDecorateOffset (rsStruct, memberIdx, offset);
|
||||
memberIdx++;
|
||||
|
@ -781,8 +778,6 @@ namespace dxvk {
|
|||
uint32_t m_inputMask = 0u;
|
||||
uint32_t m_outputMask = 0u;
|
||||
uint32_t m_flatShadingMask = 0u;
|
||||
uint32_t m_pushConstOffset = 0u;
|
||||
uint32_t m_pushConstSize = 0u;
|
||||
|
||||
DxsoProgramType m_programType;
|
||||
D3D9FFShaderKeyVS m_vsKey;
|
||||
|
@ -892,8 +887,8 @@ namespace dxvk {
|
|||
info.inputMask = m_inputMask;
|
||||
info.outputMask = m_outputMask;
|
||||
info.flatShadingInputs = m_flatShadingMask;
|
||||
info.pushConstOffset = m_pushConstOffset;
|
||||
info.pushConstSize = m_pushConstSize;
|
||||
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||
|
||||
return new DxvkShader(info, m_module.compile());
|
||||
}
|
||||
|
@ -1384,20 +1379,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
void D3D9FFShaderCompiler::setupRenderStateInfo() {
|
||||
uint32_t count;
|
||||
|
||||
if (m_programType == DxsoProgramType::PixelShader) {
|
||||
m_pushConstOffset = 0;
|
||||
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
count = 5;
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
m_pushConstSize = sizeof(float) * 6;
|
||||
count = 11;
|
||||
}
|
||||
|
||||
m_rsBlock = SetupRenderStateBlock(m_module, count);
|
||||
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace dxvk {
|
|||
void DoFixedFunctionAlphaTest(SpirvModule& spvModule, const D3D9AlphaTestContext& ctx);
|
||||
|
||||
// Returns a render state block
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule, uint32_t count);
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
|
||||
|
||||
struct D3D9PointSizeInfoVS {
|
||||
uint32_t defaultValue;
|
||||
|
|
|
@ -438,7 +438,11 @@ namespace dxvk {
|
|||
D3D9VkFormatTable::D3D9VkFormatTable(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const D3D9Options& options) {
|
||||
m_dfSupport = options.supportDFFormats;
|
||||
|
||||
const auto& props = adapter->deviceProperties();
|
||||
uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId);
|
||||
|
||||
m_dfSupport = options.supportDFFormats && DxvkGpuVendor(vendorId) != DxvkGpuVendor::Nvidia;
|
||||
m_x4r4g4b4Support = options.supportX4R4G4B4;
|
||||
m_d32supportFinal = options.supportD32;
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ namespace dxvk {
|
|||
info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.bindingCount = bindings.size();
|
||||
info.bindings = bindings.data();
|
||||
info.pushConstOffset = 0;
|
||||
info.pushConstStages = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
info.pushConstSize = sizeof(VkExtent2D);
|
||||
|
||||
return new DxvkShader(info, std::move(code));
|
||||
|
|
|
@ -41,11 +41,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
||||
}
|
||||
|
@ -246,11 +241,6 @@ namespace dxvk {
|
|||
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
|
||||
m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -276,7 +266,6 @@ namespace dxvk {
|
|||
void D3D9Query::Begin(DxvkContext* ctx) {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
ctx->beginQuery(m_query[0]);
|
||||
break;
|
||||
|
||||
|
@ -296,7 +285,6 @@ namespace dxvk {
|
|||
ctx->writeTimestamp(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
ctx->endQuery(m_query[0]);
|
||||
break;
|
||||
|
@ -314,7 +302,6 @@ namespace dxvk {
|
|||
|
||||
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
||||
return QueryType == D3DQUERYTYPE_OCCLUSION
|
||||
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|
||||
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
||||
}
|
||||
|
||||
|
@ -338,7 +325,6 @@ namespace dxvk {
|
|||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
return D3D_OK;
|
||||
|
||||
default:
|
||||
|
|
|
@ -87,9 +87,9 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < ins.dstCount; i++) {
|
||||
if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[0].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[0].mask;
|
||||
if (ins.dst[i].type == DxbcOperandType::IndexableTemp) {
|
||||
uint32_t index = ins.dst[i].idx[0].offset;
|
||||
m_analysis->xRegMasks[index] |= ins.dst[i].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,11 @@ namespace dxvk {
|
|||
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
|
||||
entry.componentType = componentTypes.at(reader.readu32());
|
||||
entry.registerId = reader.readu32();
|
||||
entry.componentMask = bit::extract(reader.readu32(), 0, 3);
|
||||
|
||||
uint32_t mask = reader.readu32();
|
||||
|
||||
entry.componentMask = bit::extract(mask, 0, 3);
|
||||
entry.componentUsed = bit::extract(mask, 8, 11);
|
||||
|
||||
if (hasPrecision)
|
||||
reader.readu32();
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace dxvk {
|
|||
uint32_t semanticIndex;
|
||||
uint32_t registerId;
|
||||
DxbcRegMask componentMask;
|
||||
DxbcRegMask componentUsed;
|
||||
DxbcScalarType componentType;
|
||||
DxbcSystemValue systemValue;
|
||||
uint32_t streamId;
|
||||
|
|
|
@ -257,14 +257,13 @@ namespace dxvk {
|
|||
info.outputMask = m_outputMask;
|
||||
info.uniformSize = m_immConstData.size();
|
||||
info.uniformData = m_immConstData.data();
|
||||
info.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(DxbcPushConstants);
|
||||
info.outputTopology = m_outputTopology;
|
||||
|
||||
if (m_programInfo.type() == DxbcProgramType::HullShader)
|
||||
info.patchVertexCount = m_hs.vertexCountIn;
|
||||
|
||||
if (m_programInfo.type() == DxbcProgramType::PixelShader && m_ps.pushConstantId)
|
||||
info.pushConstSize = sizeof(DxbcPushConstants);
|
||||
|
||||
if (m_moduleInfo.xfb) {
|
||||
info.xfbRasterizedStream = m_moduleInfo.xfb->rasterizedStream;
|
||||
|
||||
|
@ -1624,8 +1623,13 @@ namespace dxvk {
|
|||
|
||||
case DxbcOpcode::Mad:
|
||||
case DxbcOpcode::DFma:
|
||||
dst.id = m_module.opFFma(typeId,
|
||||
src.at(0).id, src.at(1).id, src.at(2).id);
|
||||
if (likely(!m_moduleInfo.options.longMad)) {
|
||||
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;
|
||||
|
||||
case DxbcOpcode::Max:
|
||||
|
@ -2464,58 +2468,6 @@ namespace dxvk {
|
|||
if (m_uavs.at(registerId).ctrId == 0)
|
||||
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
|
||||
DxbcRegisterInfo ptrType;
|
||||
ptrType.type.ctype = DxbcScalarType::Uint32;
|
||||
|
@ -2547,13 +2499,14 @@ namespace dxvk {
|
|||
switch (ins.op) {
|
||||
case DxbcOpcode::ImmAtomicAlloc:
|
||||
value.id = m_module.opAtomicIAdd(typeId, ptrId,
|
||||
scopeId, semanticsId, laneCount);
|
||||
scopeId, semanticsId, m_module.constu32(1));
|
||||
break;
|
||||
|
||||
case DxbcOpcode::ImmAtomicConsume:
|
||||
value.id = m_module.opAtomicISub(typeId, ptrId,
|
||||
scopeId, semanticsId, laneCount);
|
||||
value.id = m_module.opISub(typeId, value.id, laneCount);
|
||||
scopeId, semanticsId, m_module.constu32(1));
|
||||
value.id = m_module.opISub(typeId, value.id,
|
||||
m_module.constu32(1));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2563,26 +2516,6 @@ namespace dxvk {
|
|||
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
|
||||
emitRegisterStore(ins.dst[0], value);
|
||||
}
|
||||
|
@ -5584,12 +5517,12 @@ namespace dxvk {
|
|||
result.type.ctype = DxbcScalarType::Uint32;
|
||||
result.type.ccount = 1;
|
||||
|
||||
if (info.image.sampled == 1) {
|
||||
if (info.image.ms == 0 && info.image.sampled == 1) {
|
||||
result.id = m_module.opImageQueryLevels(
|
||||
getVectorTypeId(result.type),
|
||||
m_module.opLoad(info.typeId, info.varId));
|
||||
} else {
|
||||
// Report one LOD in case of UAVs
|
||||
// Report one LOD in case of UAVs or multisampled images
|
||||
result.id = m_module.constu32(1);
|
||||
}
|
||||
|
||||
|
@ -7799,6 +7732,21 @@ namespace dxvk {
|
|||
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 {
|
||||
switch (m_programInfo.type()) {
|
||||
|
@ -7829,8 +7777,25 @@ namespace dxvk {
|
|||
result.ctype = DxbcScalarType::Float32;
|
||||
result.ccount = 4;
|
||||
|
||||
if (m_isgn->findByRegister(regIdx))
|
||||
result.ccount = m_isgn->regMask(regIdx).minComponents();
|
||||
if (m_isgn == nullptr || !m_isgn->findByRegister(regIdx))
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1221,6 +1221,9 @@ namespace dxvk {
|
|||
uint32_t getUavCoherence(
|
||||
uint32_t registerId,
|
||||
DxbcUavFlags flags);
|
||||
|
||||
bool ignoreInputSystemValue(
|
||||
DxbcSystemValue sv) const;
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
|
|
|
@ -17,9 +17,6 @@ namespace dxvk {
|
|||
|
||||
useDepthClipWorkaround
|
||||
= !devFeatures.extDepthClipEnable.depthClipEnable;
|
||||
useSubgroupOpsForAtomicCounters
|
||||
= (devInfo.vk11.subgroupSupportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
&& (devInfo.vk11.subgroupSupportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
|
||||
|
||||
VkFormatFeatureFlags2 r32Features
|
||||
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
|
||||
|
@ -41,6 +38,7 @@ namespace dxvk {
|
|||
disableMsaa = options.disableMsaa;
|
||||
forceSampleRateShading = options.forceSampleRateShading;
|
||||
enableSampleShadingInterlock = device->features().extFragmentShaderInterlock.fragmentShaderSampleInterlock;
|
||||
longMad = options.longMad;
|
||||
|
||||
// Figure out float control flags to match D3D11 rules
|
||||
if (options.floatControls) {
|
||||
|
|
|
@ -30,10 +30,6 @@ namespace dxvk {
|
|||
/// Determines whether raw access chains are supported
|
||||
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
|
||||
bool zeroInitWorkgroupMemory = false;
|
||||
|
||||
|
@ -58,6 +54,9 @@ namespace dxvk {
|
|||
|
||||
/// Minimum storage buffer alignment
|
||||
VkDeviceSize minSsboAlignment = 0;
|
||||
|
||||
/// Should we make our Mads a FFma or do it the long way with an FMul and an FAdd?
|
||||
bool longMad;
|
||||
};
|
||||
|
||||
}
|
|
@ -130,7 +130,7 @@ namespace dxvk {
|
|||
// We can't really reconstruct the version numbers
|
||||
// returned by Windows drivers from Vulkan data
|
||||
if (SUCCEEDED(hr) && pUMDVersion)
|
||||
pUMDVersion->QuadPart = ~0ull;
|
||||
pUMDVersion->QuadPart = INT64_MAX;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
Logger::err("DXGI: CheckInterfaceSupport: Unsupported interface");
|
||||
|
|
|
@ -124,13 +124,10 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// If any monitors are left on the list, enable the
|
||||
// fallback to always enumerate all monitors.
|
||||
if ((m_monitorFallback = !monitors.empty()))
|
||||
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;
|
||||
|
||||
IDXGISwapChain1* swapChain = nullptr;
|
||||
HRESULT hr = CreateSwapChainForHwnd(
|
||||
HRESULT hr = CreateSwapChainForHwndBase(
|
||||
pDevice, pDesc->OutputWindow,
|
||||
&desc, &descFs, nullptr,
|
||||
&swapChain);
|
||||
|
@ -247,6 +244,19 @@ namespace dxvk {
|
|||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
return CreateSwapChainForHwndBase(
|
||||
pDevice, hWnd,
|
||||
pDesc, pFullscreenDesc, pRestrictToOutput,
|
||||
ppSwapChain);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain) {
|
||||
|
|
|
@ -200,6 +200,14 @@ namespace dxvk {
|
|||
UINT m_flags;
|
||||
BOOL m_monitorFallback;
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase(
|
||||
IUnknown* pDevice,
|
||||
HWND hWnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pDesc,
|
||||
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
|
||||
IDXGIOutput* pRestrictToOutput,
|
||||
IDXGISwapChain1** ppSwapChain);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,21 @@ namespace dxvk {
|
|||
return id;
|
||||
}
|
||||
|
||||
/* First generation XeSS causes crash on proton for Intel due to missing
|
||||
* Intel interface. Avoid crash by pretending to be non-Intel if the
|
||||
* libxess.dll module is loaded by an application.
|
||||
*/
|
||||
static bool isXessUsed() {
|
||||
#ifdef _WIN32
|
||||
if (GetModuleHandleA("libxess") != nullptr ||
|
||||
GetModuleHandleA("libxess_dx11") != nullptr)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isNvapiEnabled() {
|
||||
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
|
||||
|
@ -95,15 +110,17 @@ namespace dxvk {
|
|||
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
|
||||
this->hideIntelGpu = config.getOption<Tristate>("dxgi.hideIntelGpu", Tristate::Auto) == Tristate::True;
|
||||
|
||||
/* Force vendor ID to non-Intel ID when XeSS is in use */
|
||||
if (isXessUsed()) {
|
||||
Logger::info(str::format("Detected XeSS usage, hiding Intel GPU Vendor"));
|
||||
this->hideIntelGpu = true;
|
||||
}
|
||||
|
||||
this->enableHDR = config.getOption<bool>("dxgi.enableHDR", env::getEnvVar("DXVK_HDR") == "1");
|
||||
if (this->enableHDR && isHDRDisallowed()) {
|
||||
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");
|
||||
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
|
||||
bool enableHDR;
|
||||
|
||||
/// Use monitor fallback to enumerating all monitors per output
|
||||
bool useMonitorFallback;
|
||||
|
||||
/// Sync interval. Overrides the value
|
||||
/// passed to IDXGISwapChain::Present.
|
||||
int32_t syncInterval;
|
||||
|
|
|
@ -303,15 +303,22 @@ namespace dxvk {
|
|||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
|
||||
return Present1(SyncInterval, Flags, nullptr);
|
||||
return PresentBase(SyncInterval, Flags, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
return PresentBase(SyncInterval, PresentFlags, pPresentParameters);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DxgiSwapChain::PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
|
||||
|
||||
if (SyncInterval > 4)
|
||||
return DXGI_ERROR_INVALID_CALL;
|
||||
|
||||
|
|
|
@ -233,6 +233,10 @@ namespace dxvk {
|
|||
DXGI_FORMAT Format,
|
||||
DXGI_COLOR_SPACE_TYPE ColorSpace);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE PresentBase(
|
||||
UINT SyncInterval,
|
||||
UINT PresentFlags,
|
||||
const DXGI_PRESENT_PARAMETERS* pPresentParameters);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -228,8 +228,8 @@ namespace dxvk {
|
|||
info.bindings = m_bindings.data();
|
||||
info.inputMask = m_inputMask;
|
||||
info.outputMask = m_outputMask;
|
||||
info.pushConstOffset = m_pushConstOffset;
|
||||
info.pushConstSize = m_pushConstSize;
|
||||
info.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
info.pushConstSize = sizeof(D3D9RenderStateInfo);
|
||||
|
||||
if (m_programInfo.type() == DxsoProgramTypes::PixelShader)
|
||||
info.flatShadingInputs = m_ps.flatShadingMask;
|
||||
|
@ -3561,30 +3561,7 @@ void DxsoCompiler::emitControlFlowGenericLoop(
|
|||
|
||||
|
||||
void DxsoCompiler::setupRenderStateInfo() {
|
||||
uint32_t count;
|
||||
|
||||
// Only need alpha ref for PS 3.
|
||||
// No FF fog component.
|
||||
if (m_programInfo.type() == DxsoProgramType::PixelShader) {
|
||||
if (m_programInfo.majorVersion() == 3) {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, alphaRef);
|
||||
m_pushConstSize = sizeof(float);
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = 0;
|
||||
m_pushConstSize = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
}
|
||||
|
||||
count = 5;
|
||||
}
|
||||
else {
|
||||
m_pushConstOffset = offsetof(D3D9RenderStateInfo, pointSize);
|
||||
// Point scale never triggers on programmable
|
||||
m_pushConstSize = sizeof(float) * 3;
|
||||
count = 8;
|
||||
}
|
||||
|
||||
m_rsBlock = SetupRenderStateBlock(m_module, count);
|
||||
m_rsBlock = SetupRenderStateBlock(m_module);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -344,8 +344,6 @@ namespace dxvk {
|
|||
// covers vertex input and fragment output.
|
||||
uint32_t m_inputMask = 0u;
|
||||
uint32_t m_outputMask = 0u;
|
||||
uint32_t m_pushConstOffset = 0u;
|
||||
uint32_t m_pushConstSize = 0u;
|
||||
|
||||
///////////////////////////////////
|
||||
// Shader-specific data structures
|
||||
|
|
|
@ -346,6 +346,11 @@ namespace dxvk {
|
|||
enabledFeatures.vk13.synchronization2 = VK_TRUE;
|
||||
enabledFeatures.vk13.dynamicRendering = VK_TRUE;
|
||||
|
||||
// Maintenance4 may cause performance problems on amdvlk in some cases
|
||||
if (m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_OPEN_SOURCE
|
||||
&& m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_PROPRIETARY)
|
||||
enabledFeatures.vk13.maintenance4 = VK_TRUE;
|
||||
|
||||
// We expose depth clip rather than depth clamp to client APIs
|
||||
enabledFeatures.extDepthClipEnable.depthClipEnable =
|
||||
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
|
||||
|
|
|
@ -48,9 +48,7 @@ namespace dxvk {
|
|||
// Retrieve actual pipeline handle on first use. This
|
||||
// may wait for an ongoing compile job to finish, or
|
||||
// compile the pipeline immediately on the calling thread.
|
||||
m_libraryHandle = m_library->acquirePipelineHandle(
|
||||
DxvkShaderPipelineLibraryCompileArgs());
|
||||
|
||||
m_libraryHandle = m_library->acquirePipelineHandle().handle;
|
||||
return m_libraryHandle;
|
||||
} else {
|
||||
// Slow path for compute shaders that do use spec constants
|
||||
|
|
|
@ -1997,7 +1997,7 @@ namespace dxvk {
|
|||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthOp.loadLayout = imageView->imageInfo().layout;
|
||||
depthOp.storeLayout = imageView->imageInfo().layout;
|
||||
|
||||
|
||||
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
|
@ -2010,7 +2010,7 @@ namespace dxvk {
|
|||
|
||||
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
|
||||
else if (discardAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
|
||||
|
@ -2041,6 +2041,8 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
if (attachmentIndex < 0) {
|
||||
bool hasViewFormatMismatch = imageView->info().format != imageView->imageInfo().format;
|
||||
|
||||
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
|
||||
m_execBarriers.recordCommands(m_cmd);
|
||||
|
||||
|
@ -2075,6 +2077,11 @@ namespace dxvk {
|
|||
|
||||
attachmentInfo.loadOp = colorOp.loadOp;
|
||||
|
||||
// We can't use LOAD_OP_CLEAR if the view format does not match the
|
||||
// underlying image format, so just discard here and use clear later.
|
||||
if (hasViewFormatMismatch && attachmentInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||
|
||||
|
@ -2110,6 +2117,20 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
||||
|
||||
if (hasViewFormatMismatch) {
|
||||
VkClearAttachment clearInfo = { };
|
||||
clearInfo.aspectMask = imageView->info().aspect;
|
||||
clearInfo.clearValue = clearValue;
|
||||
|
||||
VkClearRect clearRect = { };
|
||||
clearRect.rect.extent.width = extent.width;
|
||||
clearRect.rect.extent.height = extent.height;
|
||||
clearRect.layerCount = imageView->info().numLayers;
|
||||
|
||||
m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
|
||||
}
|
||||
|
||||
m_cmd->cmdEndRendering();
|
||||
|
||||
m_execBarriers.accessImage(
|
||||
|
@ -4741,8 +4762,10 @@ namespace dxvk {
|
|||
this->renderPassEmitPostBarriers(framebufferInfo, ops);
|
||||
|
||||
uint32_t colorInfoCount = 0;
|
||||
uint32_t lateClearCount = 0;
|
||||
|
||||
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
|
||||
std::array<VkClearAttachment, MaxNumRenderTargets> lateClears;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
||||
const auto& colorTarget = framebufferInfo.getColorTarget(i);
|
||||
|
@ -4754,9 +4777,21 @@ namespace dxvk {
|
|||
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
|
||||
colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
|
||||
colorInfos[i].clearValue.color = ops.colorOps[i].clearValue;
|
||||
|
||||
// We can't use LOAD_OP_CLEAR if the view format does not match the
|
||||
// underlying image format, so just discard here and use clear later.
|
||||
if (colorTarget.view->info().format != colorTarget.view->imageInfo().format) {
|
||||
colorInfos[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
auto& clear = lateClears[lateClearCount++];
|
||||
clear.colorAttachment = i;
|
||||
clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clear.clearValue.color = ops.colorOps[i].clearValue;
|
||||
}
|
||||
}
|
||||
|
||||
colorInfoCount = i + 1;
|
||||
}
|
||||
}
|
||||
|
@ -4804,6 +4839,15 @@ namespace dxvk {
|
|||
|
||||
m_cmd->cmdBeginRendering(&renderingInfo);
|
||||
|
||||
if (lateClearCount) {
|
||||
VkClearRect clearRect = { };
|
||||
clearRect.rect.extent.width = fbSize.width;
|
||||
clearRect.rect.extent.height = fbSize.height;
|
||||
clearRect.layerCount = fbSize.layers;
|
||||
|
||||
m_cmd->cmdClearAttachments(lateClearCount, lateClears.data(), 1, &clearRect);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) {
|
||||
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
|
||||
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
|
||||
|
@ -4940,7 +4984,7 @@ namespace dxvk {
|
|||
// Mark compute resources and push constants as dirty
|
||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
|
||||
m_flags.set(DxvkContextFlag::DirtyPushConstants);
|
||||
|
||||
m_flags.clr(DxvkContextFlag::CpDirtyPipelineState);
|
||||
|
@ -5014,7 +5058,7 @@ namespace dxvk {
|
|||
|
||||
m_descriptorState.dirtyStages(VK_SHADER_STAGE_ALL_GRAPHICS);
|
||||
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange().size)
|
||||
if (newPipeline->getBindings()->layout().getPushConstantRange(true).size)
|
||||
m_flags.set(DxvkContextFlag::DirtyPushConstants);
|
||||
|
||||
m_flags.clr(DxvkContextFlag::GpDirtyPipeline);
|
||||
|
@ -5881,16 +5925,19 @@ namespace dxvk {
|
|||
auto bindings = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
||||
? m_state.gp.pipeline->getBindings()
|
||||
: m_state.cp.pipeline->getBindings();
|
||||
|
||||
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange();
|
||||
|
||||
// Optimized pipelines may have push constants trimmed, so look up
|
||||
// the exact layout used for the currently bound pipeline.
|
||||
bool independentSets = BindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS
|
||||
&& m_flags.test(DxvkContextFlag::GpIndependentSets);
|
||||
|
||||
VkPushConstantRange pushConstRange = bindings->layout().getPushConstantRange(independentSets);
|
||||
|
||||
if (!pushConstRange.size)
|
||||
return;
|
||||
|
||||
// Push constants should be compatible between complete and
|
||||
// independent layouts, so always ask for the complete one
|
||||
m_cmd->cmdPushConstants(
|
||||
bindings->getPipelineLayout(false),
|
||||
bindings->getPipelineLayout(independentSets),
|
||||
pushConstRange.stageFlags,
|
||||
pushConstRange.offset,
|
||||
pushConstRange.size,
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace dxvk {
|
|||
// memory bloat. This may be necessary for off-screen
|
||||
// rendering applications, or in situations where games
|
||||
// pre-render a lot of images without presenting in between.
|
||||
return m_descriptorPools.size() >= 8;
|
||||
return m_descriptorPools.size() > MaxDesiredPoolCount;
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,29 +100,25 @@ namespace dxvk {
|
|||
|
||||
|
||||
void DxvkDescriptorPool::reset() {
|
||||
// As a heuristic to save memory, check how many descriptors
|
||||
// have actively been used in the past couple of submissions.
|
||||
bool isLowUsageFrame = false;
|
||||
|
||||
// As a heuristic to save memory, check how many descriptor
|
||||
// sets were actually being used in past submissions.
|
||||
size_t poolCount = m_descriptorPools.size();
|
||||
bool needsReset = poolCount > MaxDesiredPoolCount;
|
||||
|
||||
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
|
||||
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
|
||||
isLowUsageFrame = double(m_setsUsed) * factor < double(m_setsAllocated);
|
||||
needsReset = double(m_setsUsed) * factor < double(m_setsAllocated);
|
||||
}
|
||||
|
||||
m_lowUsageFrames = isLowUsageFrame
|
||||
? m_lowUsageFrames + 1
|
||||
: 0;
|
||||
m_setsUsed = 0;
|
||||
|
||||
if (m_lowUsageFrames < 16) {
|
||||
if (!needsReset) {
|
||||
for (auto& entry : m_setLists)
|
||||
entry.second.reset();
|
||||
} else {
|
||||
// If most sets are no longer being used, reset and destroy
|
||||
// descriptor pools and reset all lookup tables in order to
|
||||
// accomodate more descriptors of different layouts.
|
||||
// If most sets are no longer needed, reset and destroy
|
||||
// descriptor pools and reset all lookup tables in order
|
||||
// to accomodate more descriptors of different layouts.
|
||||
for (auto pool : m_descriptorPools)
|
||||
m_manager->recycleVulkanDescriptorPool(pool);
|
||||
|
||||
|
@ -131,7 +127,6 @@ namespace dxvk {
|
|||
m_setMaps.clear();
|
||||
|
||||
m_setsAllocated = 0;
|
||||
m_lowUsageFrames = 0;
|
||||
}
|
||||
|
||||
m_cachedEntry = { nullptr, nullptr };
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace dxvk {
|
|||
* to be updated.
|
||||
*/
|
||||
class DxvkDescriptorPool : public RcObject {
|
||||
|
||||
constexpr static uint32_t MaxDesiredPoolCount = 2;
|
||||
public:
|
||||
|
||||
DxvkDescriptorPool(
|
||||
|
@ -155,8 +155,6 @@ namespace dxvk {
|
|||
|
||||
uint32_t m_prevSetsAllocated = 0;
|
||||
|
||||
uint32_t m_lowUsageFrames = 0;
|
||||
|
||||
DxvkDescriptorSetMap* getSetMapCached(
|
||||
const DxvkBindingLayoutObjects* layout);
|
||||
|
||||
|
|
|
@ -1111,7 +1111,9 @@ namespace dxvk {
|
|||
|
||||
if (doCreateBasePipeline)
|
||||
baseHandle = this->getBasePipeline(state);
|
||||
else
|
||||
|
||||
// Fast-linking may fail in some situations
|
||||
if (!baseHandle)
|
||||
fastHandle = this->getOptimizedPipeline(state);
|
||||
|
||||
// Log pipeline state if requested, or on failure
|
||||
|
@ -1148,6 +1150,13 @@ namespace dxvk {
|
|||
|| (state.rs.lineMode() != VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT && isLineRendering))
|
||||
return false;
|
||||
|
||||
// Depth clip is assumed to be enabled. If the driver does not
|
||||
// support dynamic depth clip, we'd have to late-compile anyway
|
||||
// unless the pipeline is used multiple times.
|
||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable
|
||||
&& !state.rs.depthClipEnable())
|
||||
return false;
|
||||
|
||||
if (m_shaders.tcs != nullptr) {
|
||||
// If tessellation shaders are present, the input patch
|
||||
// vertex count must match the shader's definition.
|
||||
|
@ -1219,9 +1228,6 @@ namespace dxvk {
|
|||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
||||
|
||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable)
|
||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
||||
|
||||
auto entry = m_basePipelines.find(key);
|
||||
if (entry != m_basePipelines.end())
|
||||
return entry->second;
|
||||
|
@ -1236,10 +1242,11 @@ namespace dxvk {
|
|||
const DxvkGraphicsPipelineBaseInstanceKey& key) const {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle();
|
||||
DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle();
|
||||
|
||||
std::array<VkPipeline, 4> libraries = {{
|
||||
key.viLibrary->getHandle(),
|
||||
m_vsLibrary->acquirePipelineHandle(key.args),
|
||||
m_fsLibrary->acquirePipelineHandle(key.args),
|
||||
key.viLibrary->getHandle(), vs.handle, fs.handle,
|
||||
key.foLibrary->getHandle(),
|
||||
}};
|
||||
|
||||
|
@ -1248,13 +1255,14 @@ namespace dxvk {
|
|||
libInfo.pLibraries = libraries.data();
|
||||
|
||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
||||
info.flags = vs.linkFlags | fs.linkFlags;
|
||||
info.layout = m_bindings->getPipelineLayout(true);
|
||||
info.basePipelineIndex = -1;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
|
||||
Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr));
|
||||
|
||||
return pipeline;
|
||||
|
|
|
@ -381,19 +381,16 @@ namespace dxvk {
|
|||
struct DxvkGraphicsPipelineBaseInstanceKey {
|
||||
const DxvkGraphicsPipelineVertexInputLibrary* viLibrary = nullptr;
|
||||
const DxvkGraphicsPipelineFragmentOutputLibrary* foLibrary = nullptr;
|
||||
DxvkShaderPipelineLibraryCompileArgs args;
|
||||
|
||||
bool eq(const DxvkGraphicsPipelineBaseInstanceKey& other) const {
|
||||
return viLibrary == other.viLibrary
|
||||
&& foLibrary == other.foLibrary
|
||||
&& args == other.args;
|
||||
&& foLibrary == other.foLibrary;
|
||||
}
|
||||
|
||||
size_t hash() const {
|
||||
DxvkHashState hash;
|
||||
hash.add(size_t(viLibrary));
|
||||
hash.add(size_t(foLibrary));
|
||||
hash.add(args.hash());
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "dxvk_openvr.h"
|
||||
#include "dxvk_openxr.h"
|
||||
#include "dxvk_platform_exts.h"
|
||||
#include "../wsi/wsi_platform.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
@ -20,6 +21,8 @@ namespace dxvk {
|
|||
Logger::info(str::format("Game: ", env::getExeName()));
|
||||
Logger::info(str::format("DXVK: ", DXVK_VERSION));
|
||||
|
||||
wsi::init();
|
||||
|
||||
m_config = Config::getUserConfig();
|
||||
m_config.merge(Config::getAppConfig(env::getExePath()));
|
||||
m_config.logOptions();
|
||||
|
@ -64,6 +67,8 @@ namespace dxvk {
|
|||
DxvkInstance::~DxvkInstance() {
|
||||
if (m_messenger)
|
||||
m_vki->vkDestroyDebugUtilsMessengerEXT(m_vki->instance(), m_messenger, nullptr);
|
||||
|
||||
wsi::quit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,7 +182,7 @@ namespace dxvk {
|
|||
appInfo.pApplicationName = appName.c_str();
|
||||
appInfo.applicationVersion = flags.raw();
|
||||
appInfo.pEngineName = "DXVK";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(2, 3, 1);
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(2, 3, 2);
|
||||
appInfo.apiVersion = VK_MAKE_VERSION(1, 3, 0);
|
||||
|
||||
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
|
||||
|
|
|
@ -205,7 +205,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
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) {
|
||||
for (uint32_t i = 0; i < layout.m_bindings.size(); i++)
|
||||
m_bindings[i].merge(layout.m_bindings[i]);
|
||||
|
||||
addPushConstantRange(layout.m_pushConst);
|
||||
m_pushConstStages |= layout.m_pushConstStages;
|
||||
}
|
||||
|
||||
|
||||
|
@ -266,6 +272,9 @@ namespace dxvk {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_pushConstStages != other.m_pushConstStages)
|
||||
return false;
|
||||
|
||||
if (m_pushConst.stageFlags != other.m_pushConst.stageFlags
|
||||
|| m_pushConst.offset != other.m_pushConst.offset
|
||||
|| m_pushConst.size != other.m_pushConst.size)
|
||||
|
@ -282,6 +291,7 @@ namespace dxvk {
|
|||
for (uint32_t i = 0; i < m_bindings.size(); i++)
|
||||
hash.add(m_bindings[i].hash());
|
||||
|
||||
hash.add(m_pushConstStages);
|
||||
hash.add(m_pushConst.stageFlags);
|
||||
hash.add(m_pushConst.offset);
|
||||
hash.add(m_pushConst.size);
|
||||
|
@ -334,15 +344,16 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
// 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 };
|
||||
pipelineLayoutInfo.setLayoutCount = setCount;
|
||||
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
|
||||
|
||||
if (pushConst.stageFlags && pushConst.size) {
|
||||
if (pushConstComplete.stageFlags && pushConstComplete.size) {
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConst;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstComplete;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
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))
|
||||
throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout");
|
||||
}
|
||||
|
|
|
@ -292,8 +292,19 @@ namespace dxvk {
|
|||
* \brief Retrieves push constant range
|
||||
* \returns Push constant range
|
||||
*/
|
||||
VkPushConstantRange getPushConstantRange() const {
|
||||
return m_pushConst;
|
||||
VkPushConstantRange getPushConstantRange(bool independent) const {
|
||||
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);
|
||||
|
||||
/**
|
||||
* \brief Adds a stage that actively uses push constants
|
||||
* \param [in] stage Shader stage
|
||||
*/
|
||||
void addPushConstantStage(VkShaderStageFlagBits stage);
|
||||
|
||||
/**
|
||||
* \brief Merges binding layouts
|
||||
*
|
||||
|
@ -353,6 +370,7 @@ namespace dxvk {
|
|||
|
||||
std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings;
|
||||
VkPushConstantRange m_pushConst;
|
||||
VkShaderStageFlags m_pushConstStages;
|
||||
VkShaderStageFlags m_stages;
|
||||
|
||||
};
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
#include "../dxvk_platform_exts.h"
|
||||
#include "dxvk_platform_exts.h"
|
||||
#include "../wsi/wsi_platform.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkPlatformExts DxvkPlatformExts::s_instance;
|
||||
|
||||
std::string_view DxvkPlatformExts::getName() {
|
||||
return "Win32 WSI";
|
||||
return "Platform WSI";
|
||||
}
|
||||
|
||||
|
||||
DxvkNameSet DxvkPlatformExts::getInstanceExtensions() {
|
||||
std::vector<const char *> extensionNames = wsi::getInstanceExtensions();
|
||||
|
||||
DxvkNameSet names;
|
||||
names.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
for (const char* name : extensionNames)
|
||||
names.add(name);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
@ -33,4 +37,4 @@ namespace dxvk {
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -382,6 +382,9 @@ namespace dxvk {
|
|||
|
||||
|
||||
bool Presenter::supportsColorSpace(VkColorSpaceKHR colorspace) {
|
||||
if (!m_surface)
|
||||
return false;
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> surfaceFormats;
|
||||
getSupportedFormats(surfaceFormats, VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT);
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace dxvk {
|
|||
|
||||
if (info.pushConstSize) {
|
||||
VkPushConstantRange pushConst;
|
||||
pushConst.stageFlags = info.stage;
|
||||
pushConst.offset = info.pushConstOffset;
|
||||
pushConst.stageFlags = info.pushConstStages;
|
||||
pushConst.offset = 0;
|
||||
pushConst.size = info.pushConstSize;
|
||||
|
||||
m_bindings.addPushConstantRange(pushConst);
|
||||
|
@ -75,6 +75,8 @@ namespace dxvk {
|
|||
|
||||
// Run an analysis pass over the SPIR-V code to gather some
|
||||
// info that we may need during pipeline compilation.
|
||||
bool usesPushConstants = false;
|
||||
|
||||
std::vector<BindingOffsets> bindingOffsets;
|
||||
std::vector<uint32_t> varIds;
|
||||
std::vector<uint32_t> sampleMaskIds;
|
||||
|
@ -154,6 +156,9 @@ namespace dxvk {
|
|||
if (std::find(sampleMaskIds.begin(), sampleMaskIds.end(), ins.arg(2)) != sampleMaskIds.end())
|
||||
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.
|
||||
|
@ -169,6 +174,11 @@ namespace dxvk {
|
|||
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
|
||||
// doesn't actually support pipeline libraries
|
||||
m_needsLibraryCompile = canUsePipelineLibrary(true);
|
||||
|
@ -1012,7 +1022,7 @@ namespace dxvk {
|
|||
|
||||
|
||||
DxvkShaderPipelineLibrary::~DxvkShaderPipelineLibrary() {
|
||||
this->destroyShaderPipelinesLocked();
|
||||
this->destroyShaderPipelineLocked();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1032,22 +1042,17 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
VkPipeline DxvkShaderPipelineLibrary::acquirePipelineHandle(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args) {
|
||||
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::acquirePipelineHandle() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_device->mustTrackPipelineLifetime())
|
||||
m_useCount += 1;
|
||||
|
||||
VkPipeline& pipeline = (m_shaders.vs && !args.depthClipEnable)
|
||||
? m_pipelineNoDepthClip
|
||||
: m_pipeline;
|
||||
if (m_pipeline.handle)
|
||||
return m_pipeline;
|
||||
|
||||
if (pipeline)
|
||||
return pipeline;
|
||||
|
||||
pipeline = compileShaderPipelineLocked(args);
|
||||
return pipeline;
|
||||
m_pipeline = compileShaderPipelineLocked();
|
||||
return m_pipeline;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1056,7 +1061,7 @@ namespace dxvk {
|
|||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (!(--m_useCount))
|
||||
this->destroyShaderPipelinesLocked();
|
||||
this->destroyShaderPipelineLocked();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1069,17 +1074,16 @@ namespace dxvk {
|
|||
return;
|
||||
|
||||
// Compile the pipeline with default args
|
||||
VkPipeline pipeline = compileShaderPipelineLocked(
|
||||
DxvkShaderPipelineLibraryCompileArgs());
|
||||
DxvkShaderPipelineLibraryHandle pipeline = compileShaderPipelineLocked();
|
||||
|
||||
// On 32-bit, destroy the pipeline immediately in order to
|
||||
// save memory. We should hit the driver's disk cache once
|
||||
// we need to recreate the pipeline.
|
||||
if (m_device->mustTrackPipelineLifetime()) {
|
||||
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
|
||||
|
@ -1087,37 +1091,32 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
void DxvkShaderPipelineLibrary::destroyShaderPipelinesLocked() {
|
||||
void DxvkShaderPipelineLibrary::destroyShaderPipelineLocked() {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
vk->vkDestroyPipeline(vk->device(), m_pipeline, nullptr);
|
||||
vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip, nullptr);
|
||||
vk->vkDestroyPipeline(vk->device(), m_pipeline.handle, nullptr);
|
||||
|
||||
m_pipeline = VK_NULL_HANDLE;
|
||||
m_pipelineNoDepthClip = VK_NULL_HANDLE;
|
||||
m_pipeline.handle = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipelineLocked(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args) {
|
||||
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipelineLocked() {
|
||||
this->notifyLibraryCompile();
|
||||
|
||||
// If this is not the first time we're compiling the pipeline,
|
||||
// try to get a cache hit using the shader module identifier
|
||||
// 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()) {
|
||||
pipeline = this->compileShaderPipeline(args,
|
||||
VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
|
||||
}
|
||||
if (m_compiledOnce && canUsePipelineCacheControl())
|
||||
pipeline = this->compileShaderPipeline(VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
|
||||
|
||||
if (!pipeline)
|
||||
pipeline = this->compileShaderPipeline(args, 0);
|
||||
if (!pipeline.handle)
|
||||
pipeline = this->compileShaderPipeline(0);
|
||||
|
||||
// Well that didn't work
|
||||
if (!pipeline)
|
||||
return VK_NULL_HANDLE;
|
||||
if (!pipeline.handle)
|
||||
return { VK_NULL_HANDLE, 0 };
|
||||
|
||||
// Increment stat counter the first time this
|
||||
// shader pipeline gets compiled successfully
|
||||
|
@ -1134,8 +1133,7 @@ namespace dxvk {
|
|||
}
|
||||
|
||||
|
||||
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipeline(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||
DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipeline(
|
||||
VkPipelineCreateFlags flags) {
|
||||
DxvkShaderStageInfo stageInfo(m_device);
|
||||
VkShaderStageFlags stageMask = getShaderStages();
|
||||
|
@ -1151,7 +1149,7 @@ namespace dxvk {
|
|||
// Fail if we have no idenfitier for whatever reason, caller
|
||||
// should fall back to the slow path if this happens
|
||||
if (!identifier->identifierSize)
|
||||
return VK_NULL_HANDLE;
|
||||
return { VK_NULL_HANDLE, 0 };
|
||||
|
||||
stageInfo.addStage(stage, *identifier, nullptr);
|
||||
} else {
|
||||
|
@ -1168,22 +1166,21 @@ namespace dxvk {
|
|||
}
|
||||
}
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
|
||||
if (stageMask & VK_SHADER_STAGE_VERTEX_BIT)
|
||||
return compileVertexShaderPipeline(args, stageInfo, flags);
|
||||
|
||||
if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
return compileFragmentShaderPipeline(stageInfo, flags);
|
||||
|
||||
if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
return compileComputeShaderPipeline(stageInfo, flags);
|
||||
pipeline = compileVertexShaderPipeline(stageInfo, flags);
|
||||
else if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
pipeline = compileFragmentShaderPipeline(stageInfo, flags);
|
||||
else if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
pipeline = compileComputeShaderPipeline(stageInfo, flags);
|
||||
|
||||
// Should be unreachable
|
||||
return VK_NULL_HANDLE;
|
||||
return { pipeline, flags };
|
||||
}
|
||||
|
||||
|
||||
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||
const DxvkShaderStageInfo& stageInfo,
|
||||
VkPipelineCreateFlags flags) {
|
||||
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
|
||||
if (!m_device->features().extExtendedDynamicState3.extendedDynamicState3DepthClipEnable) {
|
||||
rsDepthClipInfo.pNext = std::exchange(rsInfo.pNext, &rsDepthClipInfo);
|
||||
rsDepthClipInfo.depthClipEnable = args.depthClipEnable;
|
||||
rsDepthClipInfo.depthClipEnable = VK_TRUE;
|
||||
}
|
||||
} 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
|
||||
|
@ -1256,7 +1253,7 @@ namespace dxvk {
|
|||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
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));
|
||||
|
||||
return vr ? VK_NULL_HANDLE : pipeline;
|
||||
|
@ -1367,7 +1364,7 @@ namespace dxvk {
|
|||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
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));
|
||||
|
||||
return vr ? VK_NULL_HANDLE : pipeline;
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace dxvk {
|
|||
/// Flat shading input mask
|
||||
uint32_t flatShadingInputs = 0;
|
||||
/// Push constant range
|
||||
uint32_t pushConstOffset = 0;
|
||||
VkShaderStageFlags pushConstStages = 0;
|
||||
uint32_t pushConstSize = 0;
|
||||
/// Uniform buffer data
|
||||
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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -521,11 +512,9 @@ namespace dxvk {
|
|||
* Either returns an already compiled pipeline library object, or
|
||||
* performs the compilation step if that has not happened yet.
|
||||
* Increments the use count by one.
|
||||
* \param [in] args Compile arguments
|
||||
* \returns Vulkan pipeline handle
|
||||
*/
|
||||
VkPipeline acquirePipelineHandle(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
||||
DxvkShaderPipelineLibraryHandle acquirePipelineHandle();
|
||||
|
||||
/**
|
||||
* \brief Releases pipeline
|
||||
|
@ -552,26 +541,22 @@ namespace dxvk {
|
|||
DxvkShaderSet m_shaders;
|
||||
const DxvkBindingLayoutObjects* m_layout;
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
||||
VkPipeline m_pipelineNoDepthClip = VK_NULL_HANDLE;
|
||||
uint32_t m_useCount = 0u;
|
||||
bool m_compiledOnce = false;
|
||||
dxvk::mutex m_mutex;
|
||||
DxvkShaderPipelineLibraryHandle m_pipeline = { VK_NULL_HANDLE, 0 };
|
||||
uint32_t m_useCount = 0u;
|
||||
bool m_compiledOnce = false;
|
||||
|
||||
dxvk::mutex m_identifierMutex;
|
||||
DxvkShaderIdentifierSet m_identifiers;
|
||||
dxvk::mutex m_identifierMutex;
|
||||
DxvkShaderIdentifierSet m_identifiers;
|
||||
|
||||
void destroyShaderPipelinesLocked();
|
||||
void destroyShaderPipelineLocked();
|
||||
|
||||
VkPipeline compileShaderPipelineLocked(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
||||
DxvkShaderPipelineLibraryHandle compileShaderPipelineLocked();
|
||||
|
||||
VkPipeline compileShaderPipeline(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||
DxvkShaderPipelineLibraryHandle compileShaderPipeline(
|
||||
VkPipelineCreateFlags flags);
|
||||
|
||||
VkPipeline compileVertexShaderPipeline(
|
||||
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||
const DxvkShaderStageInfo& stageInfo,
|
||||
VkPipelineCreateFlags flags);
|
||||
|
||||
|
|
|
@ -329,6 +329,8 @@ namespace dxvk {
|
|||
|
||||
DxvkShaderCreateInfo vsInfo;
|
||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
vsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||
vsInfo.outputMask = 0x1;
|
||||
m_vs = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
|
@ -336,6 +338,7 @@ namespace dxvk {
|
|||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.bindingCount = fsBindings.size();
|
||||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.pushConstStages = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.pushConstSize = sizeof(PresenterArgs);
|
||||
fsInfo.inputMask = 0x1;
|
||||
fsInfo.outputMask = 0x1;
|
||||
|
|
|
@ -183,14 +183,17 @@ namespace dxvk::hud {
|
|||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.bindingCount = vsBindings.size();
|
||||
vsInfo.bindings = vsBindings.data();
|
||||
vsInfo.outputMask = 0x3;
|
||||
vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.pushConstSize = sizeof(HudTextPushConstants);
|
||||
vsInfo.outputMask = 0x3;
|
||||
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
DxvkShaderCreateInfo fsInfo;
|
||||
fsInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.bindingCount = fsBindings.size();
|
||||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
fsInfo.pushConstSize = sizeof(HudTextPushConstants);
|
||||
fsInfo.inputMask = 0x3;
|
||||
fsInfo.outputMask = 0x1;
|
||||
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
||||
|
@ -212,6 +215,7 @@ namespace dxvk::hud {
|
|||
DxvkShaderCreateInfo vsInfo;
|
||||
vsInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vsInfo.outputMask = 0x1;
|
||||
vsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
vsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
||||
result.vert = new DxvkShader(vsInfo, std::move(vsCode));
|
||||
|
||||
|
@ -221,6 +225,7 @@ namespace dxvk::hud {
|
|||
fsInfo.bindings = fsBindings.data();
|
||||
fsInfo.inputMask = 0x1;
|
||||
fsInfo.outputMask = 0x1;
|
||||
fsInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fsInfo.pushConstSize = sizeof(HudGraphPushConstants);
|
||||
result.frag = new DxvkShader(fsInfo, std::move(fsCode));
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ dxvk_src = [
|
|||
'dxvk_options.cpp',
|
||||
'dxvk_pipelayout.cpp',
|
||||
'dxvk_pipemanager.cpp',
|
||||
'dxvk_platform_exts.cpp',
|
||||
'dxvk_presenter.cpp',
|
||||
'dxvk_queue.cpp',
|
||||
'dxvk_resource.cpp',
|
||||
|
@ -117,20 +118,6 @@ if platform == 'windows'
|
|||
]
|
||||
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') ]
|
||||
if platform == 'linux'
|
||||
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 {
|
||||
|
||||
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 */
|
||||
{ R"(\\ACS\.exe$)", {{
|
||||
{ "dxgi.customVendorId", "10de" },
|
||||
|
@ -122,8 +125,6 @@ namespace dxvk {
|
|||
}} },
|
||||
/* NieR Replicant */
|
||||
{ R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
|
||||
{ "dxgi.syncInterval", "1" },
|
||||
{ "dxgi.maxFrameRate", "60" },
|
||||
{ "d3d11.cachedDynamicResources", "vi" },
|
||||
}} },
|
||||
/* SteamVR performance test */
|
||||
|
@ -138,6 +139,10 @@ namespace dxvk {
|
|||
{ R"(\\h1(_[ms]p64_ship|-mod)\.exe$)", {{
|
||||
{ "dxgi.customVendorId", "10de" },
|
||||
}} },
|
||||
/* H2M-Mod - Modern Warfare Remastered */
|
||||
{ R"(\\h2m-mod\.exe$)", {{
|
||||
{ "dxgi.customVendorId", "10de" },
|
||||
}} },
|
||||
/* Modern Warfare 2 Campaign Remastered *
|
||||
* AMD AGS crash same as above */
|
||||
{ R"(\\MW2CR\.exe$)", {{
|
||||
|
@ -331,11 +336,6 @@ namespace dxvk {
|
|||
{ R"(\\SonicFrontiers\.exe$)", {{
|
||||
{ "dxgi.maxFrameLatency", "1" },
|
||||
}} },
|
||||
/* TRAHA Global *
|
||||
* Shadow issues when it sees AMD/Nvidia */
|
||||
{ R"(\\RapaNui-Win64-Shipping\.exe$)", {{
|
||||
{ "dxgi.customVendorId", "8086" },
|
||||
}} },
|
||||
/* SpellForce 3 Reforced & expansions *
|
||||
* Greatly improves CPU bound performance */
|
||||
{ R"(\\SF3ClientFinal\.exe$)", {{
|
||||
|
@ -411,11 +411,6 @@ namespace dxvk {
|
|||
{ R"(\\RidersRepublic(_BE)?\.exe$)", {{
|
||||
{ "dxgi.hideAmdGpu", "True" },
|
||||
}} },
|
||||
/* HoloCure - Save the Fans!
|
||||
Same as Cyberpunk 2077 */
|
||||
{ R"(\\HoloCure\.exe$)", {{
|
||||
{ "dxgi.useMonitorFallback", "True" },
|
||||
}} },
|
||||
/* Kenshi *
|
||||
* Helps CPU bound performance */
|
||||
{ R"(\\kenshi_x64\.exe$)", {{
|
||||
|
@ -429,6 +424,16 @@ namespace dxvk {
|
|||
{ "d3d11.exposeDriverCommandLists", "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 */
|
||||
|
@ -877,6 +882,27 @@ namespace dxvk {
|
|||
{ R"(\\ShippingPC-SkyGame\.exe$)", {{
|
||||
{ "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 +927,6 @@ namespace dxvk {
|
|||
{ R"(\\RiftApart\.exe$)", {{
|
||||
{ "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
|
||||
* by available VRAM, which causes issues on some
|
||||
* systems with integrated graphics. */
|
||||
|
@ -922,6 +941,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) {
|
||||
return ch == ' ' || ch == '\x9' || ch == '\r';
|
||||
}
|
||||
|
@ -1171,20 +1212,22 @@ namespace dxvk {
|
|||
|
||||
|
||||
Config Config::getAppConfig(const std::string& appName) {
|
||||
auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.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);
|
||||
});
|
||||
const Config* config = nullptr;
|
||||
|
||||
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
|
||||
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));
|
||||
|
||||
return appConfig->second;
|
||||
return *config;
|
||||
}
|
||||
|
||||
return Config();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#if defined(DXVK_WSI_GLFW)
|
||||
|
||||
#include "../wsi_monitor.h"
|
||||
|
||||
#include "wsi/native_wsi.h"
|
||||
|
@ -11,22 +13,22 @@
|
|||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
HMONITOR getDefaultMonitor() {
|
||||
HMONITOR GlfwWsiDriver::getDefaultMonitor() {
|
||||
return enumMonitors(0);
|
||||
}
|
||||
|
||||
|
||||
HMONITOR enumMonitors(uint32_t index) {
|
||||
HMONITOR GlfwWsiDriver::enumMonitors(uint32_t index) {
|
||||
return isDisplayValid(int32_t(index))
|
||||
? toHmonitor(index)
|
||||
: 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);
|
||||
}
|
||||
|
||||
bool getDisplayName(
|
||||
bool GlfwWsiDriver::getDisplayName(
|
||||
HMONITOR hMonitor,
|
||||
WCHAR (&Name)[32]) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -46,7 +48,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDesktopCoordinates(
|
||||
bool GlfwWsiDriver::getDesktopCoordinates(
|
||||
HMONITOR hMonitor,
|
||||
RECT* pRect) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -97,7 +99,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDisplayMode(
|
||||
bool GlfwWsiDriver::getDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
uint32_t ModeNumber,
|
||||
WsiMode* pMode) {
|
||||
|
@ -121,7 +123,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getCurrentDisplayMode(
|
||||
bool GlfwWsiDriver::getCurrentDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -141,7 +143,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDesktopDisplayMode(
|
||||
bool GlfwWsiDriver::getDesktopDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -159,9 +161,11 @@ namespace dxvk::wsi {
|
|||
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.");
|
||||
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 <GLFW/glfw3.h>
|
||||
|
||||
#include "../wsi_monitor.h"
|
||||
#include "../wsi_platform.h"
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
/**
|
||||
* \brief Impl-dependent state
|
||||
*/
|
||||
struct DxvkWindowState {
|
||||
class GlfwWsiDriver : public WsiDriver {
|
||||
private:
|
||||
HMODULE libglfw;
|
||||
#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 "native/wsi/native_wsi.h"
|
||||
#include "native/wsi/native_glfw.h"
|
||||
#include "wsi_platform_glfw.h"
|
||||
|
||||
#include "../../util/util_string.h"
|
||||
|
@ -12,7 +14,7 @@
|
|||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
void getWindowSize(
|
||||
void GlfwWsiDriver::getWindowSize(
|
||||
HWND hWindow,
|
||||
uint32_t* pWidth,
|
||||
uint32_t* pHeight) {
|
||||
|
@ -29,7 +31,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
void resizeWindow(
|
||||
void GlfwWsiDriver::resizeWindow(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
uint32_t Width,
|
||||
|
@ -40,7 +42,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool setWindowMode(
|
||||
bool GlfwWsiDriver::setWindowMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
const WsiMode& pMode) {
|
||||
|
@ -67,7 +69,7 @@ namespace dxvk::wsi {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool enterFullscreenMode(
|
||||
bool GlfwWsiDriver::enterFullscreenMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
|
@ -89,7 +91,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool leaveFullscreenMode(
|
||||
bool GlfwWsiDriver::leaveFullscreenMode(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
bool restoreCoordinates) {
|
||||
|
@ -103,13 +105,13 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool restoreDisplayMode() {
|
||||
bool GlfwWsiDriver::restoreDisplayMode() {
|
||||
// Don't need to do anything with GLFW here.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
||||
HMONITOR GlfwWsiDriver::getWindowMonitor(HWND hWindow) {
|
||||
// TODO: implement this with glfwGetWindowMonitor
|
||||
// (or maybe not? glfwGetWindowMonitor only seems to reference *fullscreen* windows)
|
||||
// GLFWwindow* window = fromHwnd(hWindow);
|
||||
|
@ -119,19 +121,19 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool isWindow(HWND hWindow) {
|
||||
bool GlfwWsiDriver::isWindow(HWND hWindow) {
|
||||
GLFWwindow* window = fromHwnd(hWindow);
|
||||
return window != nullptr;
|
||||
}
|
||||
|
||||
void updateFullscreenWindow(
|
||||
void GlfwWsiDriver::updateFullscreenWindow(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
bool forceTopmost) {
|
||||
// Don't need to do anything with GLFW here.
|
||||
}
|
||||
|
||||
VkResult createSurface(
|
||||
VkResult GlfwWsiDriver::createSurface(
|
||||
HWND hWindow,
|
||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||
VkInstance instance,
|
||||
|
@ -141,4 +143,6 @@ namespace dxvk::wsi {
|
|||
return glfwCreateWindowSurface(instance, window, nullptr, pSurface);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,33 +1,24 @@
|
|||
wsi_common_src = [
|
||||
wsi_src = [
|
||||
'wsi_edid.cpp',
|
||||
]
|
||||
|
||||
wsi_win32_src = [
|
||||
'wsi_platform.cpp',
|
||||
'win32/wsi_monitor_win32.cpp',
|
||||
'win32/wsi_platform_win32.cpp',
|
||||
'win32/wsi_window_win32.cpp',
|
||||
]
|
||||
|
||||
wsi_sdl2_src = [
|
||||
'sdl2/wsi_monitor_sdl2.cpp',
|
||||
'sdl2/wsi_platform_sdl2.cpp',
|
||||
'sdl2/wsi_window_sdl2.cpp',
|
||||
]
|
||||
|
||||
wsi_glfw_src = [
|
||||
'glfw/wsi_monitor_glfw.cpp',
|
||||
'glfw/wsi_platform_glfw.cpp',
|
||||
'glfw/wsi_window_glfw.cpp',
|
||||
]
|
||||
|
||||
if dxvk_wsi == 'win32'
|
||||
wsi_src = wsi_common_src + wsi_win32_src
|
||||
wsi_deps = [ dep_displayinfo ]
|
||||
elif dxvk_wsi == 'sdl2'
|
||||
wsi_src = wsi_common_src + wsi_sdl2_src
|
||||
wsi_deps = [ dep_displayinfo, lib_sdl2 ]
|
||||
elif dxvk_wsi == 'glfw'
|
||||
wsi_src = wsi_common_src + wsi_glfw_src
|
||||
wsi_deps = [ dep_displayinfo, lib_glfw ]
|
||||
else
|
||||
error('Unknown wsi')
|
||||
wsi_deps = [ dep_displayinfo ]
|
||||
|
||||
if platform != 'windows'
|
||||
wsi_deps += [
|
||||
lib_sdl2.partial_dependency(compile_args: true, includes: true),
|
||||
lib_glfw.partial_dependency(compile_args: true, includes: true),
|
||||
]
|
||||
endif
|
||||
|
||||
wsi_lib = static_library('wsi', wsi_src,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#if defined(DXVK_WSI_SDL2)
|
||||
|
||||
#include "../wsi_monitor.h"
|
||||
|
||||
#include "wsi/native_wsi.h"
|
||||
|
@ -12,22 +14,22 @@
|
|||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
HMONITOR getDefaultMonitor() {
|
||||
HMONITOR Sdl2WsiDriver::getDefaultMonitor() {
|
||||
return enumMonitors(0);
|
||||
}
|
||||
|
||||
|
||||
HMONITOR enumMonitors(uint32_t index) {
|
||||
HMONITOR Sdl2WsiDriver::enumMonitors(uint32_t index) {
|
||||
return isDisplayValid(int32_t(index))
|
||||
? toHmonitor(index)
|
||||
: 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);
|
||||
}
|
||||
|
||||
bool getDisplayName(
|
||||
bool Sdl2WsiDriver::getDisplayName(
|
||||
HMONITOR hMonitor,
|
||||
WCHAR (&Name)[32]) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -47,7 +49,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDesktopCoordinates(
|
||||
bool Sdl2WsiDriver::getDesktopCoordinates(
|
||||
HMONITOR hMonitor,
|
||||
RECT* pRect) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -90,7 +92,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDisplayMode(
|
||||
bool Sdl2WsiDriver::getDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
uint32_t ModeNumber,
|
||||
WsiMode* pMode) {
|
||||
|
@ -109,7 +111,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getCurrentDisplayMode(
|
||||
bool Sdl2WsiDriver::getCurrentDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -129,7 +131,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDesktopDisplayMode(
|
||||
bool Sdl2WsiDriver::getDesktopDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
const int32_t displayId = fromHmonitor(hMonitor);
|
||||
|
@ -148,9 +150,11 @@ namespace dxvk::wsi {
|
|||
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.");
|
||||
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
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "../wsi_monitor.h"
|
||||
#include "../wsi_platform.h"
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
/**
|
||||
* \brief Impl-dependent state
|
||||
*/
|
||||
struct DxvkWindowState {
|
||||
class Sdl2WsiDriver : public WsiDriver {
|
||||
private:
|
||||
HMODULE libsdl;
|
||||
#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 "native/wsi/native_wsi.h"
|
||||
#include "native/wsi/native_sdl2.h"
|
||||
#include "wsi_platform_sdl2.h"
|
||||
|
||||
#include "../../util/util_string.h"
|
||||
#include "../../util/log/log.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include <SDL_vulkan.h>
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
void getWindowSize(
|
||||
void Sdl2WsiDriver::getWindowSize(
|
||||
HWND hWindow,
|
||||
uint32_t* pWidth,
|
||||
uint32_t* pHeight) {
|
||||
|
@ -28,7 +30,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
void resizeWindow(
|
||||
void Sdl2WsiDriver::resizeWindow(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
uint32_t Width,
|
||||
|
@ -39,7 +41,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool setWindowMode(
|
||||
bool Sdl2WsiDriver::setWindowMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
const WsiMode& pMode) {
|
||||
|
@ -73,7 +75,7 @@ namespace dxvk::wsi {
|
|||
|
||||
|
||||
|
||||
bool enterFullscreenMode(
|
||||
bool Sdl2WsiDriver::enterFullscreenMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
|
@ -99,7 +101,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool leaveFullscreenMode(
|
||||
bool Sdl2WsiDriver::leaveFullscreenMode(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
bool restoreCoordinates) {
|
||||
|
@ -114,13 +116,13 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool restoreDisplayMode() {
|
||||
bool Sdl2WsiDriver::restoreDisplayMode() {
|
||||
// Don't need to do anything with SDL2 here.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
||||
HMONITOR Sdl2WsiDriver::getWindowMonitor(HWND hWindow) {
|
||||
SDL_Window* window = fromHwnd(hWindow);
|
||||
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);
|
||||
return window != nullptr;
|
||||
}
|
||||
|
||||
|
||||
void updateFullscreenWindow(
|
||||
void Sdl2WsiDriver::updateFullscreenWindow(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
bool forceTopmost) {
|
||||
|
@ -142,7 +144,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
VkResult createSurface(
|
||||
VkResult Sdl2WsiDriver::createSurface(
|
||||
HWND hWindow,
|
||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||
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/log/log.h"
|
||||
|
@ -13,7 +15,7 @@
|
|||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
HMONITOR getDefaultMonitor() {
|
||||
HMONITOR Win32WsiDriver::getDefaultMonitor() {
|
||||
return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
|
@ -45,7 +47,7 @@ namespace dxvk::wsi {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
HMONITOR enumMonitors(uint32_t index) {
|
||||
HMONITOR Win32WsiDriver::enumMonitors(uint32_t index) {
|
||||
MonitorEnumInfo info;
|
||||
info.iMonitorId = index;
|
||||
info.oMonitor = nullptr;
|
||||
|
@ -58,7 +60,7 @@ namespace dxvk::wsi {
|
|||
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)
|
||||
return enumMonitors(index);
|
||||
|
||||
|
@ -132,7 +134,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDisplayName(
|
||||
bool Win32WsiDriver::getDisplayName(
|
||||
HMONITOR hMonitor,
|
||||
WCHAR (&Name)[32]) {
|
||||
// Query monitor info to get the device name
|
||||
|
@ -150,7 +152,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDesktopCoordinates(
|
||||
bool Win32WsiDriver::getDesktopCoordinates(
|
||||
HMONITOR hMonitor,
|
||||
RECT* pRect) {
|
||||
::MONITORINFOEXW monInfo;
|
||||
|
@ -200,7 +202,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getDisplayMode(
|
||||
bool Win32WsiDriver::getDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
uint32_t modeNumber,
|
||||
WsiMode* pMode) {
|
||||
|
@ -208,14 +210,14 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool getCurrentDisplayMode(
|
||||
bool Win32WsiDriver::getCurrentDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode);
|
||||
}
|
||||
|
||||
|
||||
bool getDesktopDisplayMode(
|
||||
bool Win32WsiDriver::getDesktopDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
WsiMode* pMode) {
|
||||
return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode);
|
||||
|
@ -308,7 +310,7 @@ namespace dxvk::wsi {
|
|||
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 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"));
|
||||
|
@ -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 "../wsi_platform.h"
|
||||
|
||||
namespace dxvk::wsi {
|
||||
|
||||
/**
|
||||
* \brief Impl-dependent state
|
||||
*/
|
||||
struct DxvkWindowState {
|
||||
LONG style = 0;
|
||||
LONG exstyle = 0;
|
||||
RECT rect = { 0, 0, 0, 0 };
|
||||
class Win32WsiDriver : public WsiDriver {
|
||||
public:
|
||||
// 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);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../wsi_window.h"
|
||||
#include "../wsi_monitor.h"
|
||||
#if defined(DXVK_WSI_WIN32)
|
||||
|
||||
#include "wsi_platform_win32.h"
|
||||
|
||||
#include "../../util/util_string.h"
|
||||
#include "../../util/log/log.h"
|
||||
|
@ -94,7 +95,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
void getWindowSize(
|
||||
void Win32WsiDriver::getWindowSize(
|
||||
HWND hWindow,
|
||||
uint32_t* pWidth,
|
||||
uint32_t* pHeight) {
|
||||
|
@ -109,7 +110,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
void resizeWindow(
|
||||
void Win32WsiDriver::resizeWindow(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
uint32_t width,
|
||||
|
@ -130,7 +131,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool setWindowMode(
|
||||
bool Win32WsiDriver::setWindowMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
const WsiMode& mode) {
|
||||
|
@ -163,21 +164,21 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool enterFullscreenMode(
|
||||
bool Win32WsiDriver::enterFullscreenMode(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
[[maybe_unused]]
|
||||
bool modeSwitch) {
|
||||
// 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.
|
||||
LONG style = ::GetWindowLongW(hWindow, GWL_STYLE);
|
||||
LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE);
|
||||
|
||||
pState->style = style;
|
||||
pState->exstyle = exstyle;
|
||||
pState->win.style = style;
|
||||
pState->win.exstyle = exstyle;
|
||||
|
||||
style &= ~WS_OVERLAPPEDWINDOW;
|
||||
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
|
||||
|
@ -196,7 +197,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool leaveFullscreenMode(
|
||||
bool Win32WsiDriver::leaveFullscreenMode(
|
||||
HWND hWindow,
|
||||
DxvkWindowState* pState,
|
||||
bool restoreCoordinates) {
|
||||
|
@ -205,27 +206,27 @@ namespace dxvk::wsi {
|
|||
LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE;
|
||||
LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
|
||||
|
||||
if (curStyle == (pState->style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
||||
&& curExstyle == (pState->exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
||||
::SetWindowLongW(hWindow, GWL_STYLE, pState->style);
|
||||
::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->exstyle);
|
||||
if (curStyle == (pState->win.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
|
||||
&& curExstyle == (pState->win.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
|
||||
::SetWindowLongW(hWindow, GWL_STYLE, pState->win.style);
|
||||
::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->win.exstyle);
|
||||
}
|
||||
|
||||
// Restore window position and apply the style
|
||||
UINT flags = SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
||||
const RECT rect = pState->rect;
|
||||
const RECT rect = pState->win.rect;
|
||||
|
||||
if (!restoreCoordinates)
|
||||
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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool restoreDisplayMode() {
|
||||
bool Win32WsiDriver::restoreDisplayMode() {
|
||||
bool success = true;
|
||||
bool result = ::EnumDisplayMonitors(nullptr, nullptr,
|
||||
&restoreDisplayModeCallback,
|
||||
|
@ -235,7 +236,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
HMONITOR getWindowMonitor(HWND hWindow) {
|
||||
HMONITOR Win32WsiDriver::getWindowMonitor(HWND hWindow) {
|
||||
RECT windowRect = { 0, 0, 0, 0 };
|
||||
::GetWindowRect(hWindow, &windowRect);
|
||||
|
||||
|
@ -248,12 +249,12 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
bool isWindow(HWND hWindow) {
|
||||
bool Win32WsiDriver::isWindow(HWND hWindow) {
|
||||
return ::IsWindow(hWindow);
|
||||
}
|
||||
|
||||
|
||||
void updateFullscreenWindow(
|
||||
void Win32WsiDriver::updateFullscreenWindow(
|
||||
HMONITOR hMonitor,
|
||||
HWND hWindow,
|
||||
bool forceTopmost) {
|
||||
|
@ -274,7 +275,7 @@ namespace dxvk::wsi {
|
|||
}
|
||||
|
||||
|
||||
VkResult createSurface(
|
||||
VkResult Win32WsiDriver::createSurface(
|
||||
HWND hWindow,
|
||||
PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr,
|
||||
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
|
||||
|
||||
#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)
|
||||
#include "win32/wsi_platform_win32.h"
|
||||
#elif defined(DXVK_WSI_SDL2)
|
||||
#include "sdl2/wsi_platform_sdl2.h"
|
||||
#elif defined(DXVK_WSI_GLFW)
|
||||
#include "glfw/wsi_platform_glfw.h"
|
||||
extern WsiBootstrap Win32WSI;
|
||||
#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 "wsi_monitor.h"
|
||||
#include "wsi_platform.h"
|
||||
|
||||
#include "../vulkan/vulkan_loader.h"
|
||||
|
||||
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
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue