From f3a224a1f19e9d67cb683a965d1fb88636eabf6c Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 29 Mar 2018 18:47:48 -0700 Subject: Implemented hardware adapter and display mode enumeration --- Graphics/GraphicsEngine/interface/GraphicsTypes.h | 87 +++++++++ Graphics/GraphicsEngineD3D11/CMakeLists.txt | 1 + Graphics/GraphicsEngineD3D11/include/pch.h | 2 +- .../interface/RenderDeviceFactoryD3D11.h | 9 + .../src/RenderDeviceFactoryD3D11.cpp | 4 +- .../interface/RenderDeviceFactoryD3D12.h | 9 + .../src/RenderDeviceFactoryD3D12.cpp | 15 +- Graphics/GraphicsEngineD3DBase/CMakeLists.txt | 4 + .../include/EngineFactoryD3DBase.h | 203 +++++++++++++++++++++ 9 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.h (limited to 'Graphics') diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index c8ee913a..2a223e43 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -909,6 +909,93 @@ namespace Diligent {} }; + /// Hardware adapter attributes + struct HardwareAdapterAttribs + { + /// A string that contains the adapter description + char Description[128]; + + /// Dedicated video memory, in bytes + size_t DedicatedVideoMemory; + + /// Dedicated system memory, in bytes + size_t DedicatedSystemMemory; + + /// Dedicated shared memory, in bytes + size_t SharedSystemMemory; + + /// The PCI ID of the hardware vendor + Uint32 VendorId; + + /// The PCI ID of the hardware device + Uint32 DeviceId; + + /// Number of outputs this device has + Uint32 NumOutputs; + }; + + + /// Display mode attributes + struct DisplayModeAttribs + { + /// Flags indicating how an image is stretched to fit a given monitor's resolution. + /// \sa DXGI_MODE_SCALING enumeration on MSDN, + enum SCALING + { + /// Unspecified scaling. + /// D3D Counterpart: DXGI_MODE_SCALING_UNSPECIFIED. + SCALING_UNSPECIFIED = 0, + + /// Specifies no scaling. The image is centered on the display. + /// This flag is typically used for a fixed-dot-pitch display (such as an LED display). + /// D3D Counterpart: DXGI_MODE_SCALING_CENTERED. + SCALING_CENTERED = 1, + + /// Specifies stretched scaling. + /// D3D Counterpart: DXGI_MODE_SCALING_STRETCHED. + SCALING_STRETCHED = 2 + }; + + /// Flags indicating the method the raster uses to create an image on a surface. + /// \sa DXGI_MODE_SCANLINE_ORDER enumeration on MSDN, + enum SCANLINE_ORDER + { + /// Scanline order is unspecified + /// D3D Counterpart: DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED. + SCANLINE_ORDER_UNSPECIFIED = 0, + + /// The image is created from the first scanline to the last without skipping any + /// D3D Counterpart: DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE. + SCANLINE_ORDER_PROGRESSIVE = 1, + + /// The image is created beginning with the upper field + /// D3D Counterpart: DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST. + SCANLINE_ORDER_UPPER_FIELD_FIRST = 2, + + /// The image is created beginning with the lower field + /// D3D Counterpart: DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST. + SCANLINE_ORDER_LOWER_FIELD_FIRST = 3 + }; + + /// Display resolution width + Uint32 Width = 0; + + /// Display resolution height + Uint32 Height = 0; + + /// Display format + TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN; + + /// Display refresh rate + double RefreshRate = 0.0; + + /// The scanline drawing mode. + SCALING Scaling = SCALING_UNSPECIFIED; + + /// The scaling mode. + SCANLINE_ORDER ScanlineOrder = SCANLINE_ORDER_UNSPECIFIED; + }; + /// Swap chain description struct SwapChainDesc { diff --git a/Graphics/GraphicsEngineD3D11/CMakeLists.txt b/Graphics/GraphicsEngineD3D11/CMakeLists.txt index 02178d07..d8d1759b 100644 --- a/Graphics/GraphicsEngineD3D11/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D11/CMakeLists.txt @@ -115,6 +115,7 @@ set(PRIVATE_DEPENDENCIES GraphicsEngineD3DBase TargetPlatform Common + dxgi.lib d3d11.lib d3dcompiler.lib ) diff --git a/Graphics/GraphicsEngineD3D11/include/pch.h b/Graphics/GraphicsEngineD3D11/include/pch.h index 91105ad7..7285fd95 100644 --- a/Graphics/GraphicsEngineD3D11/include/pch.h +++ b/Graphics/GraphicsEngineD3D11/include/pch.h @@ -52,4 +52,4 @@ #include "RenderDeviceBase.h" #include "D3D11TypeConversions.h" #include "ValidatedCast.h" -#include \ No newline at end of file +#include diff --git a/Graphics/GraphicsEngineD3D11/interface/RenderDeviceFactoryD3D11.h b/Graphics/GraphicsEngineD3D11/interface/RenderDeviceFactoryD3D11.h index 1f999e8a..84154472 100644 --- a/Graphics/GraphicsEngineD3D11/interface/RenderDeviceFactoryD3D11.h +++ b/Graphics/GraphicsEngineD3D11/interface/RenderDeviceFactoryD3D11.h @@ -61,6 +61,15 @@ public: IRenderDevice **ppDevice, IDeviceContext **ppContexts, Uint32 NumDeferredContexts) = 0; + + virtual void EnumerateHardwareAdapters(Uint32 &NumAdapters, + HardwareAdapterAttribs *Adapters) = 0; + + virtual void EnumerateDisplayModes(Uint32 AdapterId, + Uint32 OutputId, + TEXTURE_FORMAT Format, + Uint32 &NumDisplayModes, + DisplayModeAttribs *DisplayModes) = 0; }; #if ENGINE_DLL diff --git a/Graphics/GraphicsEngineD3D11/src/RenderDeviceFactoryD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/RenderDeviceFactoryD3D11.cpp index 9e5a5981..e6a1f711 100644 --- a/Graphics/GraphicsEngineD3D11/src/RenderDeviceFactoryD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/RenderDeviceFactoryD3D11.cpp @@ -31,13 +31,15 @@ #include "SwapChainD3D11Impl.h" #include "D3D11TypeConversions.h" #include "EngineMemory.h" +#include "EngineFactoryD3DBase.h" #include +#include namespace Diligent { /// Engine factory for D3D11 implementation -class EngineFactoryD3D11Impl : public IEngineFactoryD3D11 +class EngineFactoryD3D11Impl : public EngineFactoryD3DBase { public: static EngineFactoryD3D11Impl* GetInstance() diff --git a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h index bdc3d8a0..6a8c7e6e 100644 --- a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceFactoryD3D12.h @@ -60,6 +60,15 @@ 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; + }; diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp index 8c62382b..8e41f986 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp @@ -30,6 +30,7 @@ #include "DeviceContextD3D12Impl.h" #include "SwapChainD3D12Impl.h" #include "D3D12TypeConversions.h" +#include "EngineFactoryD3DBase.h" #include "StringTools.h" #include "EngineMemory.h" #include "CommandQueueD3D12Impl.h" @@ -40,7 +41,7 @@ namespace Diligent { /// Engine factory for D3D12 implementation -class EngineFactoryD3D12Impl : public IEngineFactoryD3D12 +class EngineFactoryD3D12Impl : public EngineFactoryD3DBase { public: static EngineFactoryD3D12Impl* GetInstance() @@ -62,11 +63,10 @@ public: Uint32 NumDeferredContexts)override final; void CreateSwapChainD3D12( IRenderDevice *pDevice, - IDeviceContext *pImmediateContext, - const SwapChainDesc& SwapChainDesc, - void* pNativeWndHandle, - ISwapChain **ppSwapChain )override final; - + IDeviceContext *pImmediateContext, + const SwapChainDesc& SwapChainDesc, + void* pNativeWndHandle, + ISwapChain **ppSwapChain )override final; }; void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter) @@ -81,8 +81,7 @@ void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter) if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { - // Don't select the Basic Render Driver adapter. - // If you want a software adapter, pass in "/warp" on the command line. + // Skip software devices continue; } diff --git a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt index ee5066ba..cb683b09 100644 --- a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt @@ -8,6 +8,7 @@ set(INCLUDE include/D3DTypeConversionImpl.h include/D3DViewDescConversionImpl.h include/DXGITypeConversions.h + include/EngineFactoryD3DBase.h include/HLSLDefinitions.fxh include/RenderDeviceD3DBase.h include/ShaderD3DBase.h @@ -58,6 +59,9 @@ PUBLIC BuildSettings GraphicsEngine ) +if(D3D12_SUPPORTED) + target_link_libraries(GraphicsEngineD3DBase PRIVATE D3D12.lib) +endif() set_common_target_properties(GraphicsEngineD3DBase) source_group("src" FILES ${SOURCE}) diff --git a/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.h b/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.h new file mode 100644 index 00000000..3e91851a --- /dev/null +++ b/Graphics/GraphicsEngineD3DBase/include/EngineFactoryD3DBase.h @@ -0,0 +1,203 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "DXGITypeConversions.h" + +/// \file +/// Implementation of the Diligent::EngineFactoryD3DBase template class + +namespace Diligent +{ + +template +class EngineFactoryD3DBase : public BaseInterface +{ +public: + /// Enumerates hardware adapters available on this machine + + /// \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(Uint32 &NumAdapters, + HardwareAdapterAttribs *Adapters)override final + { + auto DXGIAdapters = FindCompatibleAdapters(); + + if (Adapters == nullptr) + NumAdapters = static_cast(DXGIAdapters.size()); + else + { + NumAdapters = std::min(NumAdapters, static_cast(DXGIAdapters.size())); + for (Uint32 adapter = 0; adapter < NumAdapters; ++adapter) + { + IDXGIAdapter1 *pDXIAdapter = DXGIAdapters[adapter]; + DXGI_ADAPTER_DESC1 AdapterDesc; + pDXIAdapter->GetDesc1(&AdapterDesc); + + auto &Attribs = Adapters[adapter]; + WideCharToMultiByte(CP_ACP, 0, AdapterDesc.Description, -1, Attribs.Description, _countof(Attribs.Description), NULL, FALSE); + Attribs.DedicatedVideoMemory = AdapterDesc.DedicatedVideoMemory; + Attribs.DedicatedSystemMemory = AdapterDesc.DedicatedSystemMemory; + Attribs.SharedSystemMemory = AdapterDesc.SharedSystemMemory; + Attribs.VendorId = AdapterDesc.VendorId; + Attribs.DeviceId = AdapterDesc.DeviceId; + + Attribs.NumOutputs = 0; + CComPtr pOutput; + while (pDXIAdapter->EnumOutputs(Attribs.NumOutputs, &pOutput) != DXGI_ERROR_NOT_FOUND) + { + ++Attribs.NumOutputs; + pOutput.Release(); + }; + } + } + } + + /// Enumerates available display modes for the specified output of the specified adapter + + /// \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(Uint32 AdapterId, + Uint32 OutputId, + TEXTURE_FORMAT Format, + Uint32 &NumDisplayModes, + DisplayModeAttribs *DisplayModes)override final + { + auto DXGIAdapters = FindCompatibleAdapters(); + if(AdapterId >= DXGIAdapters.size()) + { + LOG_ERROR("Incorrect adapter id ", AdapterId); + return; + } + + IDXGIAdapter1 *pDXIAdapter = DXGIAdapters[AdapterId]; + + DXGI_FORMAT DXIGFormat = TexFormatToDXGI_Format(Format); + CComPtr pOutput; + if (pDXIAdapter->EnumOutputs(OutputId, &pOutput) == DXGI_ERROR_NOT_FOUND) + { + DXGI_ADAPTER_DESC1 AdapterDesc; + pDXIAdapter->GetDesc1(&AdapterDesc); + char DescriptionMB[_countof(AdapterDesc.Description)]; + WideCharToMultiByte(CP_ACP, 0, AdapterDesc.Description, -1, DescriptionMB, _countof(DescriptionMB), NULL, FALSE); + LOG_ERROR_MESSAGE("Failed to enumerate output ", OutputId, " for adapter ", AdapterId, " (", DescriptionMB, ')'); + return; + } + + UINT numModes = 0; + // Get the number of elements + auto hr = pOutput->GetDisplayModeList(DXIGFormat, 0, &numModes, NULL); + if (DisplayModes != nullptr) + { + // Get the list + std::vector DXIDisplayModes(numModes); + hr = pOutput->GetDisplayModeList(DXIGFormat, 0, &numModes, DXIDisplayModes.data()); + for (Uint32 m = 0; m < std::min(NumDisplayModes, numModes); ++m) + { + const auto &SrcMode = DXIDisplayModes[m]; + auto &DstMode = DisplayModes[m]; + DstMode.Width = SrcMode.Width; + DstMode.Height = SrcMode.Height; + DstMode.Format = DXGI_FormatToTexFormat(SrcMode.Format); + DstMode.RefreshRate = static_cast(SrcMode.RefreshRate.Numerator) / static_cast(SrcMode.RefreshRate.Denominator); + DstMode.Scaling = static_cast(SrcMode.Scaling); + DstMode.ScanlineOrder = static_cast(SrcMode.ScanlineOrdering); + } + NumDisplayModes = std::min(NumDisplayModes, numModes); + } + else + { + NumDisplayModes = numModes; + } + } + +private: + + template + bool CheckAdapterCompatibility(IDXGIAdapter1 *pDXGIAdapter); + + template<> + bool CheckAdapterCompatibility(IDXGIAdapter1 *pDXGIAdapter) + { + return true; + } + + template<> + bool CheckAdapterCompatibility(IDXGIAdapter1 *pDXGIAdapter) + { + auto hr = D3D12CreateDevice(pDXGIAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr); + return SUCCEEDED(hr); + } + + std::vector> FindCompatibleAdapters() + { + std::vector> DXGIAdapters; + + CComPtr pFactory; + if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)&pFactory))) + { + LOG_ERROR_MESSAGE("Failed to create DXGI Factory"); + return std::move(DXGIAdapters); + } + + CComPtr pDXIAdapter; + UINT adapter = 0; + for (; pFactory->EnumAdapters1(adapter, &pDXIAdapter) != DXGI_ERROR_NOT_FOUND; ++adapter, pDXIAdapter.Release()) + { + DXGI_ADAPTER_DESC1 AdapterDesc; + pDXIAdapter->GetDesc1(&AdapterDesc); + if (AdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) + { + // Skip software devices + continue; + } + + bool IsCompatibleAdapter = CheckAdapterCompatibility(pDXIAdapter); + + if (IsCompatibleAdapter) + { + DXGIAdapters.emplace_back(std::move(pDXIAdapter)); + } + } + + return std::move(DXGIAdapters); + } +}; + +} -- cgit v1.2.3