diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index ede8ad404..1f833933a 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -114,7 +114,15 @@ GPUDevice* GPUDeviceDX11::Create() // Create DXGI factory #if PLATFORM_WINDOWS IDXGIFactory1* dxgiFactory; - HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + IDXGIFactory6* dxgiFactory6; + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory6)); + if (hr == S_OK) + dxgiFactory = dxgiFactory6; + else + { + dxgiFactory6 = nullptr; + hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + } #else IDXGIFactory2* dxgiFactory; HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); @@ -126,16 +134,17 @@ GPUDevice* GPUDeviceDX11::Create() } // Enumerate the DXGIFactory's adapters + int32 selectedAdapterIndex = -1; Array adapters; - IDXGIAdapter* tmpAdapter; - for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tmpAdapter) != DXGI_ERROR_NOT_FOUND; index++) + IDXGIAdapter* tempAdapter; + for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tempAdapter) != DXGI_ERROR_NOT_FOUND; index++) { GPUAdapterDX adapter; - if (tmpAdapter && TryCreateDevice(tmpAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) + if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) { adapter.Index = index; - VALIDATE_DIRECTX_RESULT(tmpAdapter->GetDesc(&adapter.Description)); - uint32 outputs = RenderToolsDX::CountAdapterOutputs(tmpAdapter); + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&adapter.Description)); + uint32 outputs = RenderToolsDX::CountAdapterOutputs(tempAdapter); LOG(Info, "Adapter {1}: '{0}', DirectX {2}", adapter.Description.Description, index, RenderToolsDX::GetFeatureLevelString(adapter.MaxFeatureLevel)); LOG(Info, " Dedicated Video Memory: {0}, Dedicated System Memory: {1}, Shared System Memory: {2}, Output(s): {3}", Utilities::BytesToText(adapter.Description.DedicatedVideoMemory), Utilities::BytesToText(adapter.Description.DedicatedSystemMemory), Utilities::BytesToText(adapter.Description.SharedSystemMemory), outputs); @@ -143,9 +152,41 @@ GPUDevice* GPUDeviceDX11::Create() adapters.Add(adapter); } } +#if PLATFORM_WINDOWS + // Find the best performing adapter and prefer using it instead of the first device + const auto gpuPreference = DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE; + if (dxgiFactory6 != nullptr && selectedAdapterIndex == -1) + { + if (dxgiFactory6->EnumAdapterByGpuPreference(0, gpuPreference, IID_PPV_ARGS(&tempAdapter)) != DXGI_ERROR_NOT_FOUND) + { + GPUAdapterDX adapter; + if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) + { + DXGI_ADAPTER_DESC desc; + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc)); + for (int i = 0; i < adapters.Count(); i++) + { + if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart && + adapters[i].Description.AdapterLuid.HighPart == desc.AdapterLuid.HighPart) + { + selectedAdapterIndex = i; + break; + } + } + } + } + } +#endif // Select the adapter to use - GPUAdapterDX selectedAdapter = adapters[0]; + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) + { + LOG(Error, "Failed to find valid DirectX adapter!"); + return nullptr; + } + GPUAdapterDX selectedAdapter = adapters[selectedAdapterIndex]; uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; @@ -180,6 +221,15 @@ GPUDevice* GPUDeviceDX11::Create() Delete(device); return nullptr; } + +#if PLATFORM_WINDOWS + if (dxgiFactory6 != nullptr) + dxgiFactory6->Release(); + else +#endif + { + dxgiFactory->Release(); + } return device; } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index f12efeafc..456a793f1 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -89,7 +89,15 @@ GPUDevice* GPUDeviceDX12::Create() // Create DXGI factory (CreateDXGIFactory2 is supported on Windows 8.1 or newer) IDXGIFactory4* dxgiFactory; - HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + IDXGIFactory6* dxgiFactory6; + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory6)); + if (hr == S_OK) + dxgiFactory = dxgiFactory6; + else + { + dxgiFactory6 = nullptr; + hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + } if (hr != S_OK) { LOG(Error, "Cannot create DXGI adapter. Error code: {0:x}.", hr); @@ -97,6 +105,7 @@ GPUDevice* GPUDeviceDX12::Create() } // Enumerate the DXGIFactory's adapters + int32 selectedAdapterIndex = -1; Array adapters; IDXGIAdapter* tempAdapter; for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tempAdapter) != DXGI_ERROR_NOT_FOUND; index++) @@ -118,8 +127,39 @@ GPUDevice* GPUDeviceDX12::Create() } } + // Find the best performing adapter and prefer using it instead of the first device + const auto gpuPreference = DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE; + if (dxgiFactory6 != nullptr && selectedAdapterIndex == -1) + { + if (dxgiFactory6->EnumAdapterByGpuPreference(0, gpuPreference, IID_PPV_ARGS(&tempAdapter)) != DXGI_ERROR_NOT_FOUND) + { + GPUAdapterDX adapter; + if (tempAdapter && CheckDX12Support(tempAdapter)) + { + DXGI_ADAPTER_DESC desc; + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc)); + for (int i = 0; i < adapters.Count(); i++) + { + if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart && + adapters[i].Description.AdapterLuid.HighPart == desc.AdapterLuid.HighPart) + { + selectedAdapterIndex = i; + break; + } + } + } + } + } + // Select the adapter to use - GPUAdapterDX selectedAdapter = adapters[0]; + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) + { + LOG(Error, "Failed to find valid DirectX adapter!"); + return nullptr; + } + GPUAdapterDX selectedAdapter = adapters[selectedAdapterIndex]; uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; diff --git a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h index 79e8fb7bd..deb0168fb 100644 --- a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h +++ b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h @@ -40,9 +40,11 @@ typedef IGraphicsUnknown IDXGISwapChain3; #include #include #include +#include #endif #if GRAPHICS_API_DIRECTX12 #include +#include #endif #pragma comment(lib, "DXGI.lib") diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index d78155fc8..9c6d158ce 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1155,6 +1155,7 @@ GPUDevice* GPUDeviceVulkan::Create() #endif // Enumerate all GPU devices and pick one + int32 selectedAdapterIndex = -1; uint32 gpuCount = 0; VALIDATE_VULKAN_RESULT(vkEnumeratePhysicalDevices(Instance, &gpuCount, nullptr)); if (gpuCount <= 0) @@ -1187,6 +1188,9 @@ GPUDevice* GPUDeviceVulkan::Create() break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: type = TEXT("Discrete GPU"); + // Select the first discrete GPU device + if (selectedAdapterIndex == -1) + selectedAdapterIndex = gpuIndex; break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: type = TEXT("Virtual GPU"); @@ -1203,7 +1207,13 @@ GPUDevice* GPUDeviceVulkan::Create() } // Select the adapter to use - int32 selectedAdapter = 0; + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) + { + LOG(Error, "Failed to find valid Vulkan adapter!"); + return nullptr; + } uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; @@ -1217,15 +1227,15 @@ GPUDevice* GPUDeviceVulkan::Create() { if (adapters[i].GetVendorId() == vendorId) { - selectedAdapter = i; + selectedAdapterIndex = i; break; } } } - ASSERT(selectedAdapter != -1 && adapters[selectedAdapter].IsValid()); + ASSERT(adapters[selectedAdapterIndex].IsValid()); // Create device - auto device = New(ShaderProfile::Vulkan_SM5, New(adapters[selectedAdapter])); + auto device = New(ShaderProfile::Vulkan_SM5, New(adapters[selectedAdapterIndex])); if (device->Init()) { LOG(Warning, "Graphics Device init failed");