diff --git a/src/d3d11/d3d11_features.cpp b/src/d3d11/d3d11_features.cpp new file mode 100644 index 000000000..88ed7bd9e --- /dev/null +++ b/src/d3d11/d3d11_features.cpp @@ -0,0 +1,268 @@ +#include + +#include "d3d11_features.h" + +namespace dxvk { + + D3D11DeviceFeatures::D3D11DeviceFeatures() { + + } + + + D3D11DeviceFeatures::D3D11DeviceFeatures( + const Rc& Instance, + const Rc& Adapter, + D3D_FEATURE_LEVEL FeatureLevel) + : m_features (Adapter->features()), + m_properties (Adapter->devicePropertiesExt()) { + // Assume no TBDR. DXVK does not optimize for TBDR architectures + // anyway, and D3D11 does not really provide meaningful support. + m_architectureInfo.TileBasedDeferredRenderer = FALSE; + + // D3D9 options. We unconditionally support all of these. + m_d3d9Options.FullNonPow2TextureSupport = TRUE; + + m_d3d9Options1.FullNonPow2TextureSupported = TRUE; + m_d3d9Options1.DepthAsTextureWithLessEqualComparisonFilterSupported = TRUE; + m_d3d9Options1.SimpleInstancingSupported = TRUE; + m_d3d9Options1.TextureCubeFaceRenderTargetWithNonCubeDepthStencilSupported = TRUE; + + m_d3d9Shadow.SupportsDepthAsTextureWithLessEqualComparisonFilter = TRUE; + + m_d3d9SimpleInstancing.SimpleInstancingSupported = TRUE; + + // D3D10 options. We unconditionally support compute shaders. + m_d3d10Options.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = TRUE; + + // D3D11.1 options. All of these are required for Feature Level 11_1. + bool hasDoublePrecisionSupport = m_features.core.features.shaderFloat64 + && m_features.core.features.shaderInt64; + + m_d3d11Options.DiscardAPIsSeenByDriver = TRUE; + m_d3d11Options.FlagsForUpdateAndCopySeenByDriver = TRUE; + m_d3d11Options.ClearView = TRUE; + m_d3d11Options.CopyWithOverlap = TRUE; + m_d3d11Options.ConstantBufferPartialUpdate = TRUE; + m_d3d11Options.ConstantBufferOffsetting = TRUE; + m_d3d11Options.MapNoOverwriteOnDynamicConstantBuffer = TRUE; + m_d3d11Options.MapNoOverwriteOnDynamicBufferSRV = TRUE; + m_d3d11Options.ExtendedResourceSharing = TRUE; + + if (FeatureLevel >= D3D_FEATURE_LEVEL_10_0) { + m_d3d11Options.OutputMergerLogicOp = m_features.core.features.logicOp; + m_d3d11Options.MultisampleRTVWithForcedSampleCountOne = TRUE; // Not really + } + + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) { + m_d3d11Options.UAVOnlyRenderingForcedSampleCount = TRUE; + m_d3d11Options.SAD4ShaderInstructions = TRUE; + m_d3d11Options.ExtendedDoublesShaderInstructions = hasDoublePrecisionSupport; + } + + // D3D11.2 options. + auto tiledResourcesTier = DetermineTiledResourcesTier(FeatureLevel); + m_d3d11Options1.TiledResourcesTier = tiledResourcesTier; + m_d3d11Options1.MinMaxFiltering = tiledResourcesTier >= D3D11_TILED_RESOURCES_TIER_2; + m_d3d11Options1.ClearViewAlsoSupportsDepthOnlyFormats = TRUE; + + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + m_d3d11Options1.MapOnDefaultBuffers = TRUE; + + // D3D11.3 options + m_d3d11Options2.TypedUAVLoadAdditionalFormats = DetermineUavExtendedTypedLoadSupport(Adapter, FeatureLevel); + m_d3d11Options2.ConservativeRasterizationTier = DetermineConservativeRasterizationTier(FeatureLevel); + m_d3d11Options2.TiledResourcesTier = tiledResourcesTier; + m_d3d11Options2.StandardSwizzle = FALSE; + m_d3d11Options2.UnifiedMemoryArchitecture = FALSE; + + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + m_d3d11Options2.MapOnDefaultTextures = TRUE; + + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_1) { + m_d3d11Options2.ROVsSupported = FALSE; + m_d3d11Options2.PSSpecifiedStencilRefSupported = m_features.extShaderStencilExport; + } + + // More D3D11.3 options + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) { + m_d3d11Options3.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer = + m_features.vk12.shaderOutputViewportIndex && + m_features.vk12.shaderOutputLayer; + } + + // D3D11.4 options + m_d3d11Options4.ExtendedNV12SharedTextureSupported = TRUE; + + // More D3D11.4 options + m_d3d11Options5.SharedResourceTier = DetermineSharedResourceTier(FeatureLevel); + + // Double-precision support + if (FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + m_doubles.DoublePrecisionFloatShaderOps = hasDoublePrecisionSupport; + + // These numbers are not accurate, but we have no real way to query these + m_gpuVirtualAddress.MaxGPUVirtualAddressBitsPerResource = 32; + m_gpuVirtualAddress.MaxGPUVirtualAddressBitsPerProcess = 40; + + // Marker support only depends on the debug utils extension + m_marker.Profile = Instance->extensions().extDebugUtils; + + // DXVK will keep all shaders in memory once created, and all Vulkan + // drivers that we know of that can run DXVK have an on-disk cache. + m_shaderCache.SupportFlags = D3D11_SHADER_CACHE_SUPPORT_AUTOMATIC_INPROC_CACHE + | D3D11_SHADER_CACHE_SUPPORT_AUTOMATIC_DISK_CACHE; + + // DXVK does not support min precision + m_shaderMinPrecision.PixelShaderMinPrecision = 0; + m_shaderMinPrecision.AllOtherShaderStagesMinPrecision = 0; + + // Report native support for command lists here so that we do not actually have + // to re-implement the UpdateSubresource bug from the D3D11 runtime, see MSDN: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx) + m_threading.DriverConcurrentCreates = TRUE; + m_threading.DriverCommandLists = TRUE; + } + + + D3D11DeviceFeatures::~D3D11DeviceFeatures() { + + } + + + HRESULT D3D11DeviceFeatures::GetFeatureData( + D3D11_FEATURE Feature, + UINT FeatureDataSize, + void* pFeatureData) const { + switch (Feature) { + case D3D11_FEATURE_ARCHITECTURE_INFO: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_architectureInfo); + case D3D11_FEATURE_D3D9_OPTIONS: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d9Options); + case D3D11_FEATURE_D3D9_OPTIONS1: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d9Options1); + case D3D11_FEATURE_D3D9_SHADOW_SUPPORT: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d9Shadow); + case D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d9SimpleInstancing); + case D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d10Options); + case D3D11_FEATURE_D3D11_OPTIONS: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options); + case D3D11_FEATURE_D3D11_OPTIONS1: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options1); + case D3D11_FEATURE_D3D11_OPTIONS2: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options2); + case D3D11_FEATURE_D3D11_OPTIONS3: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options3); + case D3D11_FEATURE_D3D11_OPTIONS4: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options4); + case D3D11_FEATURE_D3D11_OPTIONS5: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_d3d11Options5); + case D3D11_FEATURE_DOUBLES: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_doubles); + case D3D11_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_gpuVirtualAddress); + case D3D11_FEATURE_MARKER_SUPPORT: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_marker); + case D3D11_FEATURE_SHADER_CACHE: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_shaderCache); + case D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_shaderMinPrecision); + case D3D11_FEATURE_THREADING: + return GetTypedFeatureData(FeatureDataSize, pFeatureData, &m_threading); + default: + Logger::err(str::format("D3D11: Unknown feature: ", Feature)); + return E_INVALIDARG; + } + } + + + D3D11_CONSERVATIVE_RASTERIZATION_TIER D3D11DeviceFeatures::DetermineConservativeRasterizationTier( + D3D_FEATURE_LEVEL FeatureLevel) { + if (FeatureLevel < D3D_FEATURE_LEVEL_11_1 + || !m_features.extConservativeRasterization) + return D3D11_CONSERVATIVE_RASTERIZATION_NOT_SUPPORTED; + + // We don't really have a way to query uncertainty regions, + // so just check degenerate triangle behaviour + if (!m_properties.extConservativeRasterization.degenerateTrianglesRasterized) + return D3D11_CONSERVATIVE_RASTERIZATION_TIER_1; + + return D3D11_CONSERVATIVE_RASTERIZATION_TIER_2; + } + + + D3D11_SHARED_RESOURCE_TIER D3D11DeviceFeatures::DetermineSharedResourceTier( + D3D_FEATURE_LEVEL FeatureLevel) { + // Shared resources are all sorts of wonky for obvious + // reasons, so don't over-promise things here for now + return D3D11_SHARED_RESOURCE_TIER_1; + } + + + D3D11_TILED_RESOURCES_TIER D3D11DeviceFeatures::DetermineTiledResourcesTier( + D3D_FEATURE_LEVEL FeatureLevel) { + if (FeatureLevel < D3D_FEATURE_LEVEL_11_0 + || !m_features.core.features.sparseBinding + || !m_features.core.features.sparseResidencyBuffer + || !m_features.core.features.sparseResidencyImage2D + || !m_features.core.features.sparseResidencyAliased + || !m_properties.core.properties.sparseProperties.residencyStandard2DBlockShape) + return D3D11_TILED_RESOURCES_NOT_SUPPORTED; + + if (FeatureLevel < D3D_FEATURE_LEVEL_11_1 + || !m_features.core.features.shaderResourceResidency + || !m_features.core.features.shaderResourceMinLod + || !m_features.vk12.samplerFilterMinmax + || !m_properties.vk12.filterMinmaxSingleComponentFormats + || !m_properties.core.properties.sparseProperties.residencyNonResidentStrict + || m_properties.core.properties.sparseProperties.residencyAlignedMipSize) + return D3D11_TILED_RESOURCES_TIER_1; + + if (!m_features.core.features.sparseResidencyImage3D + || !m_properties.core.properties.sparseProperties.residencyStandard3DBlockShape) + return D3D11_TILED_RESOURCES_TIER_2; + + return D3D11_TILED_RESOURCES_TIER_3; + } + + + BOOL D3D11DeviceFeatures::DetermineUavExtendedTypedLoadSupport( + const Rc& Adapter, + D3D_FEATURE_LEVEL FeatureLevel) { + static const std::array s_formats = {{ + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R32_UINT, + VK_FORMAT_R32_SINT, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R32G32B32A32_UINT, + VK_FORMAT_R32G32B32A32_SINT, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_FORMAT_R16G16B16A16_UINT, + VK_FORMAT_R16G16B16A16_SINT, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_UINT, + VK_FORMAT_R8G8B8A8_SINT, + VK_FORMAT_R16_SFLOAT, + VK_FORMAT_R16_UINT, + VK_FORMAT_R16_SINT, + VK_FORMAT_R8_UNORM, + VK_FORMAT_R8_UINT, + VK_FORMAT_R8_SINT, + }}; + + if (FeatureLevel < D3D_FEATURE_LEVEL_11_0) + return FALSE; + + for (auto f : s_formats) { + DxvkFormatFeatures features = Adapter->getFormatFeatures(f); + VkFormatFeatureFlags2 imgFeatures = features.optimal | features.linear; + + if (!(imgFeatures & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT)) + return FALSE; + } + + return TRUE; + } + +} diff --git a/src/d3d11/d3d11_features.h b/src/d3d11/d3d11_features.h new file mode 100644 index 000000000..51dab32bd --- /dev/null +++ b/src/d3d11/d3d11_features.h @@ -0,0 +1,89 @@ +#pragma once + +#include "d3d11_include.h" + +#include "../dxvk/dxvk_adapter.h" +#include "../dxvk/dxvk_instance.h" + +namespace dxvk { + + /** + * \brief Device features + * + * Stores D3D device feature structs. + */ + class D3D11DeviceFeatures { + + public: + + D3D11DeviceFeatures(); + + D3D11DeviceFeatures( + const Rc& Instance, + const Rc& Adapter, + D3D_FEATURE_LEVEL FeatureLevel); + + ~D3D11DeviceFeatures(); + + /** + * \brief Retrieves feature support data + * + * \param [in] Feature D3D feature to query + * \param [in] FeatureDataSize Data size, in bytes + * \param [out] pFeatureData Data + * \returns Status of the operation + */ + HRESULT GetFeatureData( + D3D11_FEATURE Feature, + UINT FeatureDataSize, + void* pFeatureData) const; + + private: + + DxvkDeviceFeatures m_features; + DxvkDeviceInfo m_properties; + + D3D11_FEATURE_DATA_ARCHITECTURE_INFO m_architectureInfo = { }; + D3D11_FEATURE_DATA_D3D9_OPTIONS m_d3d9Options = { }; + D3D11_FEATURE_DATA_D3D9_OPTIONS1 m_d3d9Options1 = { }; + D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT m_d3d9Shadow = { }; + D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT m_d3d9SimpleInstancing = { }; + D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS m_d3d10Options = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS m_d3d11Options = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS1 m_d3d11Options1 = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS2 m_d3d11Options2 = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS3 m_d3d11Options3 = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS4 m_d3d11Options4 = { }; + D3D11_FEATURE_DATA_D3D11_OPTIONS5 m_d3d11Options5 = { }; + D3D11_FEATURE_DATA_DOUBLES m_doubles = { }; + D3D11_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT m_gpuVirtualAddress = { }; + D3D11_FEATURE_DATA_MARKER_SUPPORT m_marker = { }; + D3D11_FEATURE_DATA_SHADER_CACHE m_shaderCache = { }; + D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT m_shaderMinPrecision = { }; + D3D11_FEATURE_DATA_THREADING m_threading = { }; + + template + static HRESULT GetTypedFeatureData(UINT Size, void* pDstData, const T* pSrcData) { + if (Size != sizeof(T)) + return E_INVALIDARG; + + *(reinterpret_cast(pDstData)) = *pSrcData; + return S_OK; + } + + D3D11_CONSERVATIVE_RASTERIZATION_TIER DetermineConservativeRasterizationTier( + D3D_FEATURE_LEVEL FeatureLevel); + + D3D11_SHARED_RESOURCE_TIER DetermineSharedResourceTier( + D3D_FEATURE_LEVEL FeatureLevel); + + D3D11_TILED_RESOURCES_TIER DetermineTiledResourcesTier( + D3D_FEATURE_LEVEL FeatureLevel); + + BOOL DetermineUavExtendedTypedLoadSupport( + const Rc& Adapter, + D3D_FEATURE_LEVEL FeatureLevel); + + }; + +} \ No newline at end of file diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 0b99f695f..7727387d6 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -37,6 +37,7 @@ d3d11_src = [ 'd3d11_depth_stencil.cpp', 'd3d11_device.cpp', 'd3d11_enums.cpp', + 'd3d11_features.cpp', 'd3d11_fence.cpp', 'd3d11_gdi.cpp', 'd3d11_initializer.cpp',