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) --- .../include/RenderDeviceD3D12Impl.h | 2 + .../interface/EngineFactoryD3D12.h | 82 +++++++++++++++++++--- .../GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp | 78 +++++++++----------- .../src/RenderDeviceD3D12Impl.cpp | 46 +++++++++++- .../GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp | 27 ++++++- 5 files changed, 178 insertions(+), 57 deletions(-) (limited to 'Graphics/GraphicsEngineD3D12') diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h index 0756f454..b10ba472 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h @@ -104,6 +104,8 @@ public: const GenerateMipsHelper& GetMipsGenerator()const {return m_MipsGenerator;} + D3D_FEATURE_LEVEL GetD3DFeatureLevel()const; + private: virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat )override final; void FreeCommandContext(PooledCommandContext&& Ctx); diff --git a/Graphics/GraphicsEngineD3D12/interface/EngineFactoryD3D12.h b/Graphics/GraphicsEngineD3D12/interface/EngineFactoryD3D12.h index 8b1022d1..5e9f9cba 100644 --- a/Graphics/GraphicsEngineD3D12/interface/EngineFactoryD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/EngineFactoryD3D12.h @@ -44,13 +44,36 @@ namespace Diligent static const INTERFACE_ID IID_EngineFactoryD3D12 = { 0x72bd38b0, 0x684a, 0x4889, { 0x9c, 0x68, 0xa, 0x80, 0xec, 0x80, 0x2d, 0xde } }; +/// Engine factory for Direct3D12 rendering backend class IEngineFactoryD3D12 : public IEngineFactory { public: + /// Creates a render device and device contexts for Direct3D12-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 the deferred contexts are written afterwards. virtual void CreateDeviceAndContextsD3D12(const EngineD3D12CreateInfo& EngineCI, IRenderDevice** ppDevice, IDeviceContext** ppContexts) = 0; + + /// Attaches to existing Direct3D12 device. + + /// \param [in] pd3d12NativeDevice - Pointer to the native Direct3D12 device. + /// \param [in] CommandQueueCount - Number of command queues. + /// \param [in] ppCommandQueues - Pointer to the array of command queues. + /// \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 AttachToD3D12Device(void* pd3d12NativeDevice, size_t CommandQueueCount, class ICommandQueueD3D12** ppCommandQueues, @@ -58,6 +81,21 @@ public: IRenderDevice** ppDevice, IDeviceContext** ppContexts) = 0; + + /// Creates a swap chain for Direct3D12-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 CreateSwapChainD3D12( IRenderDevice* pDevice, IDeviceContext* pImmediateContext, const SwapChainDesc& SwapChainDesc, @@ -65,15 +103,43 @@ public: void* pNativeWndHandle, ISwapChain** ppSwapChain ) = 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 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; }; diff --git a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp index 6ccfc25e..0c91b8c9 100644 --- a/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/EngineFactoryD3D12.cpp @@ -57,9 +57,9 @@ public: TBase{IID_EngineFactoryD3D12} {} - void CreateDeviceAndContextsD3D12(const EngineD3D12CreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts)override final; + void CreateDeviceAndContextsD3D12(const EngineD3D12CreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts)override final; void AttachToD3D12Device(void* pd3d12NativeDevice, size_t CommandQueueCount, @@ -76,7 +76,7 @@ public: ISwapChain** ppSwapChain )override final; }; -static void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter) +static void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter, D3D_FEATURE_LEVEL FeatureLevel) { CComPtr adapter; *ppAdapter = nullptr; @@ -94,7 +94,7 @@ static void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapte // Check to see if the adapter supports Direct3D 12, but don't create the // actual device yet. - if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) + if (SUCCEEDED(D3D12CreateDevice(adapter, FeatureLevel, _uuidof(ID3D12Device), nullptr))) { break; } @@ -103,17 +103,8 @@ static void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapte *ppAdapter = adapter.Detach(); } -/// Creates render device and device contexts for Direct3D12-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 EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12CreateInfo& EngineCI, - IRenderDevice** ppDevice, +void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12CreateInfo& EngineCI, + IRenderDevice** ppDevice, IDeviceContext** ppContexts) { if (EngineCI.DebugMessageCallback != nullptr) @@ -123,7 +114,7 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat if( !ppDevice || !ppContexts ) return; - for(Uint32 Type=D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++Type) + for (Uint32 Type=D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++Type) { auto CPUHeapAllocSize = EngineCI.CPUDescriptorHeapAllocationSize[Type]; Uint32 MaxSize = 1 << 20; @@ -165,13 +156,13 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat CComPtr hardwareAdapter; if(EngineCI.AdapterId == EngineD3D12CreateInfo::DefaultAdapterId) { - GetHardwareAdapter(factory, &hardwareAdapter); + GetHardwareAdapter(factory, &hardwareAdapter, GetD3DFeatureLevel(EngineCI.MinimumFeatureLevel)); if(hardwareAdapter == nullptr) LOG_ERROR_AND_THROW("No suitable hardware adapter found"); } else { - auto Adapters = FindCompatibleAdapters(); + auto Adapters = FindCompatibleAdapters(EngineCI.MinimumFeatureLevel); if(EngineCI.AdapterId < Adapters.size()) hardwareAdapter = Adapters[EngineCI.AdapterId]; else @@ -186,7 +177,17 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat LOG_INFO_MESSAGE("D3D12-capabale hardware found: ", NarrowString(desc.Description), " (", desc.DedicatedVideoMemory >> 20, " MB)"); } - hr = D3D12CreateDevice(hardwareAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(d3d12Device), reinterpret_cast(static_cast(&d3d12Device)) ); + constexpr auto MaxFeatureLevel = DIRECT3D_FEATURE_LEVEL_12_1; + for (auto FeatureLevel = MaxFeatureLevel; FeatureLevel >= EngineCI.MinimumFeatureLevel; FeatureLevel = static_cast(Uint8{FeatureLevel}-1)) + { + auto d3dFeatureLevel = GetD3DFeatureLevel(FeatureLevel); + hr = D3D12CreateDevice(hardwareAdapter, d3dFeatureLevel, __uuidof(d3d12Device), reinterpret_cast(static_cast(&d3d12Device)) ); + if (SUCCEEDED(hr)) + { + VERIFY_EXPR(d3d12Device); + break; + } + } if( FAILED(hr)) { LOG_WARNING_MESSAGE("Failed to create hardware device. Attempting to create WARP device"); @@ -195,7 +196,16 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat hr = factory->EnumWarpAdapter( __uuidof(warpAdapter), reinterpret_cast(static_cast(&warpAdapter)) ); CHECK_D3D_RESULT_THROW(hr, "Failed to enum warp adapter"); - hr = D3D12CreateDevice( warpAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(d3d12Device), reinterpret_cast(static_cast(&d3d12Device)) ); + for (auto FeatureLevel = MaxFeatureLevel; FeatureLevel >= EngineCI.MinimumFeatureLevel; FeatureLevel = static_cast(Uint8{FeatureLevel}-1)) + { + auto d3dFeatureLevel = GetD3DFeatureLevel(FeatureLevel); + hr = D3D12CreateDevice( warpAdapter, d3dFeatureLevel, __uuidof(d3d12Device), reinterpret_cast(static_cast(&d3d12Device)) ); + if (SUCCEEDED(hr)) + { + VERIFY_EXPR(d3d12Device); + break; + } + } CHECK_D3D_RESULT_THROW(hr, "Failed to crate warp device"); } @@ -277,18 +287,7 @@ void EngineFactoryD3D12Impl::CreateDeviceAndContextsD3D12(const EngineD3D12Creat } -/// Attaches to existing D3D12 device -/// \param [in] pd3d12NativeDevice - pointer to native D3D12 device -/// \param [in] CommandQueueCount - Number of command queues -/// \param [in] ppCommandQueues - pointer to the array of command queues -/// \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 EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd3d12NativeDevice, size_t CommandQueueCount, ICommandQueueD3D12** ppCommandQueues, @@ -349,20 +348,7 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd } } -/// Creates a swap chain for Direct3D12-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 EngineFactoryD3D12Impl::CreateSwapChainD3D12(IRenderDevice* pDevice, IDeviceContext* pImmediateContext, const SwapChainDesc& SCDesc, diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 3100da7b..27f37dc0 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -37,6 +37,24 @@ namespace Diligent { +D3D_FEATURE_LEVEL RenderDeviceD3D12Impl :: GetD3DFeatureLevel() const +{ + D3D_FEATURE_LEVEL FeatureLevels[] = + { + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0 + }; + D3D12_FEATURE_DATA_FEATURE_LEVELS FeatureLevelsData = {}; + FeatureLevelsData.pFeatureLevelsRequested = FeatureLevels; + FeatureLevelsData.NumFeatureLevels = _countof(FeatureLevels); + m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &FeatureLevelsData, sizeof(FeatureLevelsData)); + return FeatureLevelsData.MaxSupportedFeatureLevel; +} + RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IReferenceCounters* pRefCounters, IMemoryAllocator& RawMemAllocator, IEngineFactory* pEngineFactory, @@ -85,8 +103,32 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IReferenceCounters* pRe m_MipsGenerator {pd3d12Device} { m_DeviceCaps.DevType = DeviceType::D3D12; - m_DeviceCaps.MajorVersion = 12; - m_DeviceCaps.MinorVersion = 0; + auto FeatureLevel = GetD3DFeatureLevel(); + switch (FeatureLevel) + { + case D3D_FEATURE_LEVEL_12_0: + case D3D_FEATURE_LEVEL_12_1: + m_DeviceCaps.MajorVersion = 12; + m_DeviceCaps.MinorVersion = FeatureLevel == D3D_FEATURE_LEVEL_12_1 ? 1 : 0; + m_DeviceCaps.bBindlessSupported = true; + break; + + 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; + m_DeviceCaps.bBindlessSupported = FeatureLevel == D3D_FEATURE_LEVEL_11_1; + 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/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp index 509ef10b..c189bf3e 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp @@ -32,6 +32,31 @@ namespace Diligent { +static const char* GetD3D12ShaderModel(RenderDeviceD3D12Impl* pDevice) +{ + auto d3dDeviceFeatureLevel = pDevice->GetD3DFeatureLevel(); + switch(d3dDeviceFeatureLevel) + { + case D3D_FEATURE_LEVEL_12_1: + case D3D_FEATURE_LEVEL_12_0: + case D3D_FEATURE_LEVEL_11_1: + return "5_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"; + } +} + ShaderD3D12Impl::ShaderD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pRenderDeviceD3D12, const ShaderCreateInfo& ShaderCI) : @@ -41,7 +66,7 @@ ShaderD3D12Impl::ShaderD3D12Impl(IReferenceCounters* pRefCounters, pRenderDeviceD3D12, ShaderCI.Desc }, - ShaderD3DBase{ShaderCI} + ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12)} { // Load shader resources auto& Allocator = GetRawAllocator(); -- cgit v1.2.3