From bc4a29a1fac0276e499bb37bb3c449ebdcacbe92 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Wed, 16 Oct 2019 21:06:08 -0700 Subject: A bunch of updates to specify minimum feature level for D3D11/D3D12 backends and to enable bindless mode (API version 240032) --- .../interface/EngineFactoryD3D11.h | 80 +++++++++- .../GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp | 163 +++++++++------------ .../src/RenderDeviceD3D11Impl.cpp | 20 ++- .../GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp | 28 +++- 4 files changed, 184 insertions(+), 107 deletions(-) (limited to 'Graphics/GraphicsEngineD3D11') diff --git a/Graphics/GraphicsEngineD3D11/interface/EngineFactoryD3D11.h b/Graphics/GraphicsEngineD3D11/interface/EngineFactoryD3D11.h index 656add65..fb658ebe 100644 --- a/Graphics/GraphicsEngineD3D11/interface/EngineFactoryD3D11.h +++ b/Graphics/GraphicsEngineD3D11/interface/EngineFactoryD3D11.h @@ -44,13 +44,38 @@ namespace Diligent static const INTERFACE_ID IID_EngineFactoryD3D11 = { 0x62663a30, 0xaaf0, 0x4a9a, { 0x97, 0x29, 0x9e, 0xac, 0x6b, 0xf7, 0x89, 0xf2 } }; +/// Engine factory for Direct3D11 rendering backend. class IEngineFactoryD3D11 : public IEngineFactory { public: + /// Creates a render device and device contexts for Direct3D11-based engine implementation. + + /// \param [in] EngineCI - Engine creation info. + /// \param [out] ppDevice - Address of the memory location where pointer to + /// the created device will be written. + /// \param [out] ppContexts - Address of the memory location where pointers to + /// the contexts will be written. Immediate context goes at + /// position 0. If EngineCI.NumDeferredContexts > 0, + /// pointers to deferred contexts are written afterwards. virtual void CreateDeviceAndContextsD3D11(const EngineD3D11CreateInfo& EngineCI, IRenderDevice** ppDevice, IDeviceContext** ppContexts) = 0; + + /// Creates a swap chain for Direct3D11-based engine implementation. + + /// \param [in] pDevice - Pointer to the render device. + /// \param [in] pImmediateContext - Pointer to the immediate device context. + /// \param [in] SCDesc - Swap chain description. + /// \param [in] FSDesc - Fullscreen mode description. + /// \param [in] pNativeWndHandle - Platform-specific native handle of the window + /// the swap chain will be associated with: + /// * On Win32 platform, this should be the window handle (HWND) + /// * On Universal Windows Platform, this should be the reference + /// to the core window (Windows::UI::Core::CoreWindow) + /// + /// \param [out] ppSwapChain - Address of the memory location where pointer to the new + /// swap chain will be written. virtual void CreateSwapChainD3D11( IRenderDevice* pDevice, IDeviceContext* pImmediateContext, const SwapChainDesc& SCDesc, @@ -58,20 +83,61 @@ public: void* pNativeWndHandle, ISwapChain** ppSwapChain) = 0; + + /// Attaches to existing Direct3D11 render device and immediate context. + + /// \param [in] pd3d11NativeDevice - pointer to the native Direct3D11 device. + /// \param [in] pd3d11ImmediateContext - pointer to the native Direct3D11 immediate context. + /// \param [in] EngineCI - Engine creation info. + /// \param [out] ppDevice - Address of the memory location where pointer to + /// the created device will be written. + /// \param [out] ppContexts - Address of the memory location where pointers to + /// the contexts will be written. Immediate context goes at + /// position 0. If EngineCI.NumDeferredContexts > 0, + /// pointers to the deferred contexts are written afterwards. virtual void AttachToD3D11Device(void* pd3d11NativeDevice, void* pd3d11ImmediateContext, const EngineD3D11CreateInfo& EngineCI, IRenderDevice** ppDevice, IDeviceContext** ppContexts) = 0; - virtual void EnumerateHardwareAdapters(Uint32& NumAdapters, - HardwareAdapterAttribs* Adapters) = 0; - virtual void EnumerateDisplayModes(Uint32 AdapterId, - Uint32 OutputId, - TEXTURE_FORMAT Format, - Uint32& NumDisplayModes, - DisplayModeAttribs* DisplayModes) = 0; + /// Enumerates hardware adapters available on this machine. + + /// \param [in] MinFeatureLevel - Minimum required feature level. + /// \param [in,out] NumAdapters - Number of adapters. If Adapters is null, this value + /// will be overwritten with the number of adapters available + /// on this system. If Adapters is not null, this value should + /// contain the maximum number of elements reserved in the array + /// pointed to by Adapters. In the latter case, this value + /// is overwritten with the actual number of elements written to + /// Adapters. + /// \param [out] Adapters - Pointer to the array conataining adapter information. If + /// null is provided, the number of available adapters is + /// written to NumAdapters. + virtual void EnumerateHardwareAdapters(DIRECT3D_FEATURE_LEVEL MinFeatureLevel, + Uint32& NumAdapters, + HardwareAdapterAttribs* Adapters) = 0; + + + /// Enumerates available display modes for the specified output of the specified adapter. + + /// \param [in] MinFeatureLevel - Minimum feature level of the adapter that was given to EnumerateHardwareAdapters(). + /// \param [in] AdapterId - Id of the adapter enumerated by EnumerateHardwareAdapters(). + /// \param [in] OutputId - Adapter output id. + /// \param [in] Format - Display mode format. + /// \param [in, out] NumDisplayModes - Number of display modes. If DisplayModes is null, this + /// value is overwritten with the number of display modes + /// available for this output. If DisplayModes is not null, + /// this value should contain the maximum number of elements + /// to be written to DisplayModes array. It is overwritten with + /// the actual number of display modes written. + virtual void EnumerateDisplayModes(DIRECT3D_FEATURE_LEVEL MinFeatureLevel, + Uint32 AdapterId, + Uint32 OutputId, + TEXTURE_FORMAT Format, + Uint32& NumDisplayModes, + DisplayModeAttribs* DisplayModes) = 0; }; #if ENGINE_DLL diff --git a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp index d763cb20..cab8ae25 100644 --- a/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/EngineFactoryD3D11.cpp @@ -54,9 +54,9 @@ public: TBase(IID_EngineFactoryD3D11) {} - void CreateDeviceAndContextsD3D11(const EngineD3D11CreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts)override final; + void CreateDeviceAndContextsD3D11(const EngineD3D11CreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts)override final; void CreateSwapChainD3D11(IRenderDevice* pDevice, IDeviceContext* pImmediateContext, @@ -94,18 +94,10 @@ inline bool SdkLayersAvailable() } #endif -/// Creates render device and device contexts for Direct3D11-based engine implementation - -/// \param [in] EngineCI - Engine creation attributes. -/// \param [out] ppDevice - Address of the memory location where pointer to -/// the created device will be written -/// \param [out] ppContexts - Address of the memory location where pointers to -/// the contexts will be written. Immediate context goes at -/// position 0. If EngineCI.NumDeferredContexts > 0, -/// pointers to the deferred contexts are written afterwards. -void EngineFactoryD3D11Impl::CreateDeviceAndContextsD3D11(const EngineD3D11CreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts) + +void EngineFactoryD3D11Impl::CreateDeviceAndContextsD3D11(const EngineD3D11CreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts) { if (EngineCI.DebugMessageCallback != nullptr) SetDebugMessageCallback(EngineCI.DebugMessageCallback); @@ -114,6 +106,9 @@ void EngineFactoryD3D11Impl::CreateDeviceAndContextsD3D11(const EngineD3D11Creat if( !ppDevice || !ppContexts ) return; + if (EngineCI.MinimumFeatureLevel >= DIRECT3D_FEATURE_LEVEL_12_0) + LOG_ERROR_AND_THROW("DIRECT3D_FEATURE_LEVEL_12_0 and above is not supported by Direct3D11 backend"); + *ppDevice = nullptr; memset(ppContexts, 0, sizeof(*ppContexts) * (1 + EngineCI.NumDeferredContexts)); @@ -130,89 +125,77 @@ void EngineFactoryD3D11Impl::CreateDeviceAndContextsD3D11(const EngineD3D11Creat } #endif - // This array defines the set of DirectX hardware feature levels this app will support. - // Note the ordering should be preserved. - // Don't forget to declare your application's minimum required feature level in its - // description. All applications are assumed to support 9.1 unless otherwise stated. - D3D_FEATURE_LEVEL featureLevels[] = - { -#if PLATFORM_UNIVERSAL_WINDOWS - D3D_FEATURE_LEVEL_11_1, -#endif - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1 - }; - - // Create the Direct3D 11 API device object and a corresponding context. - CComPtr pd3d11Device; - CComPtr pd3d11Context; - - CComPtr hardwareAdapter; + CComPtr SpecificAdapter; if (EngineCI.AdapterId != EngineD3D11CreateInfo::DefaultAdapterId) { - auto Adapters = FindCompatibleAdapters(); + auto Adapters = FindCompatibleAdapters(EngineCI.MinimumFeatureLevel); if (EngineCI.AdapterId < Adapters.size()) - hardwareAdapter = Adapters[EngineCI.AdapterId]; + SpecificAdapter = Adapters[EngineCI.AdapterId]; else { LOG_ERROR_AND_THROW(EngineCI.AdapterId, " is not a valid hardware adapter id. Total number of compatible adapters available on this system: ", Adapters.size()); } } - D3D_FEATURE_LEVEL d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0; - HRESULT hr = D3D11CreateDevice( - hardwareAdapter, // Specify nullptr to use the default adapter. - hardwareAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, // If no adapter specified, request hardware graphics driver. - 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. - creationFlags, // Set debug and Direct2D compatibility flags. - featureLevels, // List of feature levels this app can support. - ARRAYSIZE(featureLevels), // Size of the list above. - D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. - &pd3d11Device, // Returns the Direct3D device created. - &d3dFeatureLevel, // Returns feature level of device created. - &pd3d11Context // Returns the device immediate context. - ); + // Create the Direct3D 11 API device object and a corresponding context. + CComPtr pd3d11Device; + CComPtr pd3d11Context; - if (FAILED(hr)) - { - // If the initialization fails, fall back to the WARP device. - // For more information on WARP, see: - // http://go.microsoft.com/fwlink/?LinkId=286690 - hr = D3D11CreateDevice( - nullptr, - D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. - 0, - creationFlags, - featureLevels, - ARRAYSIZE(featureLevels), - D3D11_SDK_VERSION, - &pd3d11Device, - &d3dFeatureLevel, - &pd3d11Context - ); - LOG_ERROR("Failed to create D3D11 native device and immediate context"); - return; - } + for (int adapterType = 0; adapterType < 2 && !pd3d11Device; ++adapterType) + { + IDXGIAdapter* adapter = nullptr; + D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN; + switch(adapterType) + { + case 0: + adapter = SpecificAdapter; + driverType = SpecificAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE; + break; + + case 1: + driverType = D3D_DRIVER_TYPE_WARP; + break; + + default: + UNEXPECTED("Unexpected adapter type"); + } + + // This page https://docs.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice says the following: + // If you provide a D3D_FEATURE_LEVEL array that contains D3D_FEATURE_LEVEL_11_1 on a computer that doesn't have the Direct3D 11.1 + // runtime installed, this function immediately fails with E_INVALIDARG. + // To avoid failure in this case we will try one feature level at a time + constexpr auto MaxFeatureLevel = DIRECT3D_FEATURE_LEVEL_11_1; + for (auto FeatureLevel = MaxFeatureLevel; FeatureLevel >= EngineCI.MinimumFeatureLevel; FeatureLevel = static_cast(Uint8{FeatureLevel}-1)) + { + auto d3dFeatureLevel = GetD3DFeatureLevel(FeatureLevel); + auto hr = D3D11CreateDevice( + adapter, // Specify nullptr to use the default adapter. + driverType, // If no adapter specified, request hardware graphics driver. + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creationFlags, // Set debug and Direct2D compatibility flags. + &d3dFeatureLevel, // List of feature levels this app can support. + 1, // Size of the list above. + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + &pd3d11Device, // Returns the Direct3D device created. + nullptr, // Returns feature level of device created. + &pd3d11Context // Returns the device immediate context. + ); + + if (SUCCEEDED(hr)) + { + VERIFY_EXPR(pd3d11Device && pd3d11Context); + break; + } + } + } + + if (!pd3d11Device) + LOG_ERROR_AND_THROW("Failed to create d3d11 device and immediate context"); AttachToD3D11Device(pd3d11Device, pd3d11Context, EngineCI, ppDevice, ppContexts); } -/// Attaches to existing D3D11 render device and immediate context - -/// \param [in] pd3d11NativeDevice - pointer to native D3D11 device -/// \param [in] pd3d11ImmediateContext - pointer to native D3D11 immediate context -/// \param [in] EngineCI - Engine creation attributes. -/// \param [out] ppDevice - Address of the memory location where pointer to -/// the created device will be written -/// \param [out] ppContexts - Address of the memory location where pointers to -/// the contexts will be written. Immediate context goes at -/// position 0. If EngineCI.NumDeferredContexts > 0, -/// pointers to the deferred contexts are written afterwards. void EngineFactoryD3D11Impl::AttachToD3D11Device(void* pd3d11NativeDevice, void* pd3d11ImmediateContext, const EngineD3D11CreateInfo& EngineCI, @@ -279,20 +262,6 @@ void EngineFactoryD3D11Impl::AttachToD3D11Device(void* pd } -/// Creates a swap chain for Direct3D11-based engine implementation - -/// \param [in] pDevice - Pointer to the render device -/// \param [in] pImmediateContext - Pointer to the immediate device context -/// \param [in] SCDesc - Swap chain description -/// \param [in] FSDesc - Fullscreen mode description -/// \param [in] pNativeWndHandle - Platform-specific native handle of the window -/// the swap chain will be associated with: -/// * On Win32 platform, this should be window handle (HWND) -/// * On Universal Windows Platform, this should be reference to the -/// core window (Windows::UI::Core::CoreWindow) -/// -/// \param [out] ppSwapChain - Address of the memory location where pointer to the new -/// swap chain will be written void EngineFactoryD3D11Impl::CreateSwapChainD3D11(IRenderDevice* pDevice, IDeviceContext* pImmediateContext, const SwapChainDesc& SCDesc, diff --git a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp index f04162c5..3a845241 100644 --- a/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/RenderDeviceD3D11Impl.cpp @@ -69,8 +69,24 @@ RenderDeviceD3D11Impl :: RenderDeviceD3D11Impl(IReferenceCounters* pRef m_pd3d11Device {pd3d11Device } { m_DeviceCaps.DevType = DeviceType::D3D11; - m_DeviceCaps.MajorVersion = 11; - m_DeviceCaps.MinorVersion = 0; + auto FeatureLevel = m_pd3d11Device->GetFeatureLevel(); + switch (FeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_11_1: + m_DeviceCaps.MajorVersion = 11; + m_DeviceCaps.MinorVersion = FeatureLevel == D3D_FEATURE_LEVEL_11_1 ? 1 : 0; + break; + + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + m_DeviceCaps.MajorVersion = 10; + m_DeviceCaps.MinorVersion = FeatureLevel == D3D_FEATURE_LEVEL_10_1 ? 1 : 0; + break; + + default: + UNEXPECTED("Unexpected D3D feature level"); + } m_DeviceCaps.bSeparableProgramSupported = True; m_DeviceCaps.bMultithreadedResourceCreationSupported = True; } diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp index 9454cf21..46adc289 100644 --- a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp @@ -30,6 +30,32 @@ namespace Diligent { +static const char* GetD3D11ShaderModel(ID3D11Device* pd3d11Device) +{ + auto d3dDeviceFeatureLevel = pd3d11Device->GetFeatureLevel(); + switch(d3dDeviceFeatureLevel) + { + // ID3D11Device::Create*Shader methods support DXBC only up to 5.0 version +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >=_WIN32_WINNT_WIN10) + case D3D_FEATURE_LEVEL_12_1: + case D3D_FEATURE_LEVEL_12_0: +#endif + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return "5_0"; + + case D3D_FEATURE_LEVEL_10_1: + return "4_1"; + + case D3D_FEATURE_LEVEL_10_0: + return "4_0"; + + default: + UNEXPECTED("Unexpected D3D feature level ", static_cast(d3dDeviceFeatureLevel)); + return "4_0"; + } +} + ShaderD3D11Impl::ShaderD3D11Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D11Impl* pRenderDeviceD3D11, const ShaderCreateInfo& ShaderCI) : @@ -39,7 +65,7 @@ ShaderD3D11Impl::ShaderD3D11Impl(IReferenceCounters* pRefCounters, pRenderDeviceD3D11, ShaderCI.Desc }, - ShaderD3DBase{ShaderCI} + ShaderD3DBase{ShaderCI, GetD3D11ShaderModel(pRenderDeviceD3D11->GetD3D11Device())} { auto *pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device(); switch (ShaderCI.Desc.ShaderType) -- cgit v1.2.3