Skip to content

Commit

Permalink
feat: 优化 GPU 选择
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Dec 22, 2024
1 parent dfb9e62 commit 2bcfb5b
Show file tree
Hide file tree
Showing 18 changed files with 267 additions and 120 deletions.
67 changes: 50 additions & 17 deletions src/Magpie.Core/DeviceResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ bool DeviceResources::Initialize() noexcept {
Logger::Get().ComWarn("CheckFeatureSupport 失败", hr);
}

_isSupportTearing = supportTearing;
_isTearingSupported = supportTearing;
Logger::Get().Info(fmt::format("可变刷新率支持: {}", supportTearing ? "" : ""));

if (!_ObtainAdapterAndDevice(ScalingWindow::Get().Options().graphicsCard)) {
if (!_ObtainAdapterAndDevice(ScalingWindow::Get().Options().graphicsCardId)) {
Logger::Get().Error("找不到可用的图形适配器");
return false;
}
Expand Down Expand Up @@ -64,31 +64,55 @@ ID3D11SamplerState* DeviceResources::GetSampler(D3D11_FILTER filterMode, D3D11_T
return _samMap.emplace(key, std::move(sam)).first->second.get();
}

bool DeviceResources::_ObtainAdapterAndDevice(int adapterIdx) noexcept {
bool DeviceResources::_ObtainAdapterAndDevice(GraphicsCardId graphicsCardId) noexcept {
winrt::com_ptr<IDXGIAdapter1> adapter;

if (adapterIdx >= 0) {
HRESULT hr = _dxgiFactory->EnumAdapters1(adapterIdx, adapter.put());
if (graphicsCardId.idx >= 0) {
// 先使用索引
HRESULT hr = _dxgiFactory->EnumAdapters1(graphicsCardId.idx, adapter.put());
if (SUCCEEDED(hr)) {
DXGI_ADAPTER_DESC1 desc;
hr = adapter->GetDesc1(&desc);
if (SUCCEEDED(hr)) {
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
Logger::Get().Warn("用户指定的显示卡为 WARP,已忽略");
} else if (_TryCreateD3DDevice(adapter)) {
return true;
if (desc.VendorId == graphicsCardId.vendorId && desc.DeviceId == graphicsCardId.deviceId) {
if (_TryCreateD3DDevice(adapter)) {
return true;
} else {
Logger::Get().Warn("用户指定的显示卡不支持 FL 11");
}
} else {
Logger::Get().Warn("用户指定的显示卡不支持 FL 11");
Logger::Get().Warn("显卡配置已变化");
}
} else {
Logger::Get().Error("GetDesc1 失败");
}
} else {
Logger::Get().Warn("未找到用户指定的显示卡");
}

// 枚举查找 vendorId 和 deviceId 匹配的显卡
UINT adapterIndex = graphicsCardId.idx == 0 ? 1 : 0;
while (SUCCEEDED(_dxgiFactory->EnumAdapters1(adapterIndex, adapter.put()))) {
DXGI_ADAPTER_DESC1 desc;
hr = adapter->GetDesc1(&desc);
if (FAILED(hr)) {
continue;
}

if (desc.VendorId == graphicsCardId.vendorId && desc.DeviceId == graphicsCardId.deviceId) {
if (_TryCreateD3DDevice(adapter)) {
return true;
}

Logger::Get().Warn("用户指定的显示卡不支持 FL11");
break;
}

++adapterIndex;
if (adapterIndex == (UINT)graphicsCardId.idx) {
// 已经检查了 graphicsCardId.idx
++adapterIndex;
}
}
}

// 枚举查找第一个支持 D3D11 的图形适配器
// 枚举查找第一个支持 FL11 的显卡
for (UINT adapterIndex = 0;
SUCCEEDED(_dxgiFactory->EnumAdapters1(adapterIndex, adapter.put()));
++adapterIndex
Expand All @@ -109,7 +133,7 @@ bool DeviceResources::_ObtainAdapterAndDevice(int adapterIdx) noexcept {
}
}

// 作为最后手段,回落到 Basic Render Driver Adapter(WARP
// 作为最后手段,回落到 CPU 渲染 (WARP)
// https://docs.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp
HRESULT hr = _dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&adapter));
if (FAILED(hr)) {
Expand Down Expand Up @@ -187,10 +211,19 @@ bool DeviceResources::_TryCreateD3DDevice(const winrt::com_ptr<IDXGIAdapter1>& a

_graphicsAdapter = adapter.try_as<IDXGIAdapter4>();
if (!_graphicsAdapter) {
Logger::Get().ComError("获取 IDXGIAdapter4 失败", hr);
Logger::Get().Error("获取 IDXGIAdapter4 失败");
return false;
}

// 检查半精度浮点支持
D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT value;
hr = d3dDevice->CheckFeatureSupport(D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT, &value, sizeof(value));
if (SUCCEEDED(hr)) {
_isFP16Supported = value.AllOtherShaderStagesMinPrecision & D3D11_SHADER_MIN_PRECISION_16_BIT;
} else {
Logger::Get().ComError("CheckFeatureSupport 失败", hr);
}

return true;
}

Expand Down
10 changes: 6 additions & 4 deletions src/Magpie.Core/DeviceResources.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <parallel_hashmap/phmap.h>
#include "ScalingOptions.h"

namespace Magpie {

Expand All @@ -16,14 +17,14 @@ class DeviceResources {
ID3D11DeviceContext4* GetD3DDC() const noexcept { return _d3dDC.get(); }
IDXGIAdapter4* GetGraphicsAdapter() const noexcept { return _graphicsAdapter.get(); }

bool IsSupportTearing() const noexcept {
return _isSupportTearing;
bool IsTearingSupported() const noexcept {
return _isTearingSupported;
}

ID3D11SamplerState* GetSampler(D3D11_FILTER filterMode, D3D11_TEXTURE_ADDRESS_MODE addressMode) noexcept;

private:
bool _ObtainAdapterAndDevice(int adapterIdx) noexcept;
bool _ObtainAdapterAndDevice(GraphicsCardId graphicsCardId) noexcept;
bool _TryCreateD3DDevice(const winrt::com_ptr<IDXGIAdapter1>& adapter) noexcept;

winrt::com_ptr<IDXGIFactory7> _dxgiFactory;
Expand All @@ -36,7 +37,8 @@ class DeviceResources {
winrt::com_ptr<ID3D11SamplerState>
> _samMap;

bool _isSupportTearing = false;
bool _isTearingSupported = false;
bool _isFP16Supported = false;
};

}
3 changes: 1 addition & 2 deletions src/Magpie.Core/ImGuiImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ bool ImGuiImpl::Initialize(DeviceResources* deviceResources) noexcept {
Logger::Get().Error("ImGui 的头文件与链接库版本不同");
return false;
}
#endif // _DEBUG
#endif

ImGui::CreateContext();

// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformUserData = nullptr;
io.BackendPlatformName = "Magpie";
io.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard | ImGuiConfigFlags_NoMouseCursorChange;

Expand Down
2 changes: 1 addition & 1 deletion src/Magpie.Core/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ bool Renderer::_CreateSwapChain() noexcept {
.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED,
// 只要显卡支持始终启用 DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING 以支持可变刷新率
.Flags = UINT((_frontendResources.IsSupportTearing() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0)
.Flags = UINT((_frontendResources.IsTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0)
| DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
};

Expand Down
9 changes: 7 additions & 2 deletions src/Magpie.Core/ScalingOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ void ScalingOptions::Log() const noexcept {
IsStatisticsForDynamicDetectionEnabled: {}
IsTouchSupportEnabled: {}
cropping: {},{},{},{}
graphicsCard: {}
graphicsCardId:
idx: {}
venderId: {}
deviceId: {}
maxFrameRate: {}
cursorScaling: {}
captureMethod: {}
Expand All @@ -80,7 +83,9 @@ void ScalingOptions::Log() const noexcept {
IsStatisticsForDynamicDetectionEnabled(),
IsTouchSupportEnabled(),
cropping.Left, cropping.Top, cropping.Right, cropping.Bottom,
graphicsCard,
graphicsCardId.idx,
graphicsCardId.vendorId,
graphicsCardId.deviceId,
maxFrameRate.has_value() ? *maxFrameRate : 0.0f,
cursorScaling,
(int)captureMethod,
Expand Down
12 changes: 11 additions & 1 deletion src/Magpie.Core/include/ScalingOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ struct Cropping {
float Bottom;
};

// idx 为显卡索引,vendorId 和 deviceId 用于验证,如果不匹配则遍历显卡查找匹配。这可以处理显卡
// 改变的情况,比如某些笔记本电脑可以在混合架构和独显直连之间切换。
// idx 有两个作用,一是作为性能优化,二是用于区分同一型号的两个显卡。
// idx 为 -1 表示使用默认显卡。
struct GraphicsCardId {
int idx = -1;
uint32_t vendorId = 0;
uint32_t deviceId = 0;
};

struct ScalingFlags {
static constexpr uint32_t DisableWindowResizing = 1;
static constexpr uint32_t BreakpointMode = 1 << 1;
Expand Down Expand Up @@ -100,7 +110,7 @@ struct ScalingOptions {

Cropping cropping{};
uint32_t flags = ScalingFlags::AdjustCursorSpeed | ScalingFlags::DrawCursor; // ScalingFlags
int graphicsCard = -1;
GraphicsCardId graphicsCardId;
std::optional<float> maxFrameRate;
float cursorScaling = 1.0f;
CaptureMethod captureMethod = CaptureMethod::GraphicsCapture;
Expand Down
79 changes: 52 additions & 27 deletions src/Magpie/AdaptersService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,38 @@ using namespace winrt;
namespace Magpie {

bool AdaptersService::Initialize() noexcept {
com_ptr<IDXGIFactory7> dxgiFactory;

HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
if (FAILED(hr)) {
Logger::Get().ComError("CreateDXGIFactory1 失败", hr);
return false;
}

com_ptr<IDXGIAdapter1> curAdapter;
for (UINT adapterIdx = 0;
SUCCEEDED(dxgiFactory->EnumAdapters1(adapterIdx, curAdapter.put()));
++adapterIdx
) {
DXGI_ADAPTER_DESC1 desc;
hr = curAdapter->GetDesc1(&desc);
if (FAILED(hr)) {
continue;
}

// 不包含 WARP
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
continue;
}

_adapterInfos.push_back({
.idx = adapterIdx,
.vendorId = desc.VendorId,
.deviceId = desc.DeviceId,
.description = desc.Description
});
}

_monitorThread = std::thread(std::bind_front(&AdaptersService::_MonitorThreadProc, this));
return true;
}
Expand All @@ -35,7 +67,7 @@ void AdaptersService::Uninitialize() noexcept {
_monitorThread.join();
}

void AdaptersService::_GatherAdapterInfos(
bool AdaptersService::_GatherAdapterInfos(
com_ptr<IDXGIFactory7>& dxgiFactory,
wil::unique_event_nothrow& adaptersChangedEvent,
DWORD& adaptersChangedCookie
Expand All @@ -44,14 +76,14 @@ void AdaptersService::_GatherAdapterInfos(
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
if (FAILED(hr)) {
Logger::Get().ComError("CreateDXGIFactory1 失败", hr);
return;
return false;
}

hr = dxgiFactory->RegisterAdaptersChangedEvent(
adaptersChangedEvent.get(), &adaptersChangedCookie);
if (FAILED(hr)) {
Logger::Get().ComError("RegisterAdaptersChangedEvent 失败", hr);
return;
return false;
}

std::vector<AdapterInfo> adapterInfos;
Expand Down Expand Up @@ -83,33 +115,22 @@ void AdaptersService::_GatherAdapterInfos(
adapters.push_back(std::move(curAdapter));
}

wil::srwlock adapterInfosLock;
Win32Helper::RunParallel([&](uint32_t i) {
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
if (FAILED(D3D11CreateDevice(adapters[i].get(), D3D_DRIVER_TYPE_UNKNOWN,
NULL, 0, &fl, 1, D3D11_SDK_VERSION, nullptr, nullptr, nullptr))) {
auto lock = adapterInfosLock.lock_exclusive();
adapterInfos[i].isFL11Supported = false;
}
}, (uint32_t)adapters.size());

App::Get().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, adapterInfos(std::move(adapterInfos))]() {
_adapterInfos = std::move(adapterInfos);
AdaptersChanged.Invoke();
});

SmallVector<uint32_t> noFL11Adapters;
{
wil::srwlock writeLock;
Win32Helper::RunParallel([&](uint32_t i) {
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
if (FAILED(D3D11CreateDevice(adapters[i].get(), D3D_DRIVER_TYPE_UNKNOWN,
NULL, 0, &fl, 1, D3D11_SDK_VERSION, nullptr, nullptr, nullptr))) {
auto lock = writeLock.lock_exclusive();
noFL11Adapters.push_back(i);
}
}, (uint32_t)adapters.size());
}

App::Get().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, noFL11Adapters(std::move(noFL11Adapters))]() {
for (uint32_t i : noFL11Adapters) {
_adapterInfos[i].isFL11Supported = false;
}

if (!noFL11Adapters.empty()) {
AdaptersChanged.Invoke();
}
});
return true;
}

void AdaptersService::_MonitorThreadProc() noexcept {
Expand All @@ -128,7 +149,9 @@ void AdaptersService::_MonitorThreadProc() noexcept {

com_ptr<IDXGIFactory7> dxgiFactory;
DWORD adaptersChangedCookie = 0;
_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie);
if (!_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie)) {
return;
}

while (true) {
MSG msg;
Expand All @@ -150,7 +173,9 @@ void AdaptersService::_MonitorThreadProc() noexcept {
INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE) == WAIT_OBJECT_0) {
// WAIT_OBJECT_0 表示显卡变化
// WAIT_OBJECT_0 + 1 表示有新消息
_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie);
if (!_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie)) {
break;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Magpie/AdaptersService.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class AdaptersService {
private:
AdaptersService() = default;

void _GatherAdapterInfos(
bool _GatherAdapterInfos(
winrt::com_ptr<IDXGIFactory7>& dxgiFactory,
wil::unique_event_nothrow& adaptersChangedEvent,
DWORD& adaptersChangedCookie
Expand Down
Loading

0 comments on commit 2bcfb5b

Please sign in to comment.