mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
优化显卡选择并实现监听显卡变化 (#1037)
* fix: 优化初始化失败逻辑 * feat: 实现 AdapterService 功能 * feat: 优化 GPU 选择 * feat: 实现根据显卡改变更新配置文件 * feat: 支持检测运行时显卡变化 * feat: 排除不支持功能级别 11 的显卡 * perf: 延迟检查显卡的功能级别以加快主窗口显示 * fix: 确保检查显卡的功能级别在主窗口显示后执行
This commit is contained in:
parent
6d6bd791fb
commit
d8dd777053
33 changed files with 598 additions and 128 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -64,43 +64,63 @@ 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 匹配的显卡
|
||||
assert(graphicsCardId.vendorId != 0 && graphicsCardId.deviceId != 0);
|
||||
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
|
||||
) {
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
HRESULT hr = adapter->GetDesc1(&desc);
|
||||
if (FAILED(hr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 忽略 WARP
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
||||
if (FAILED(hr) || DirectXHelper::IsWARP(desc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +129,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)) {
|
||||
|
|
@ -187,10 +207,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <parallel_hashmap/phmap.h>
|
||||
#include "ScalingOptions.h"
|
||||
|
||||
namespace Magpie {
|
||||
|
||||
|
|
@ -16,14 +17,14 @@ public:
|
|||
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;
|
||||
|
|
@ -36,7 +37,8 @@ private:
|
|||
winrt::com_ptr<ID3D11SamplerState>
|
||||
> _samMap;
|
||||
|
||||
bool _isSupportTearing = false;
|
||||
bool _isTearingSupported = false;
|
||||
bool _isFP16Supported = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
<ClInclude Include="DDSLoderHelpers.h" />
|
||||
<ClInclude Include="DesktopDuplicationFrameSource.h" />
|
||||
<ClInclude Include="DeviceResources.h" />
|
||||
<ClInclude Include="DirectXHelper.h" />
|
||||
<ClInclude Include="DwmSharedSurfaceFrameSource.h" />
|
||||
<ClInclude Include="EffectCacheManager.h" />
|
||||
<ClInclude Include="EffectDrawer.h" />
|
||||
|
|
@ -71,6 +70,7 @@
|
|||
<ClInclude Include="ImGuiImpl.h" />
|
||||
<ClInclude Include="include\CommonDefines.h" />
|
||||
<ClInclude Include="include\CommonSharedConstants.h" />
|
||||
<ClInclude Include="include\DirectXHelper.h" />
|
||||
<ClInclude Include="include\EffectCompiler.h" />
|
||||
<ClInclude Include="include\EffectDesc.h" />
|
||||
<ClInclude Include="include\Logger.h" />
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@
|
|||
<ClInclude Include="DDSLoderHelpers.h">
|
||||
<Filter>TextureLoader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DirectXHelper.h">
|
||||
<Filter>Helpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EffectHelper.h">
|
||||
<Filter>Helpers</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -127,6 +124,9 @@
|
|||
<ClInclude Include="include\Logger.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\DirectXHelper.h">
|
||||
<Filter>Include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ScalingRuntime.cpp" />
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ void ScalingOptions::Log() const noexcept {
|
|||
IsStatisticsForDynamicDetectionEnabled: {}
|
||||
IsTouchSupportEnabled: {}
|
||||
cropping: {},{},{},{}
|
||||
graphicsCard: {}
|
||||
graphicsCardId:
|
||||
idx: {}
|
||||
venderId: {}
|
||||
deviceId: {}
|
||||
maxFrameRate: {}
|
||||
cursorScaling: {}
|
||||
captureMethod: {}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ struct CommonSharedConstants {
|
|||
static constexpr const wchar_t* OPTION_LAUNCH_WITHOUT_WINDOW = L"-t";
|
||||
|
||||
static constexpr UINT WM_NOTIFY_ICON = WM_USER;
|
||||
static constexpr UINT WM_TOAST_QUIT = WM_USER + 1;
|
||||
|
||||
static constexpr const wchar_t* WM_MAGPIE_SHOWME = L"WM_MAGPIE_SHOWME";
|
||||
static constexpr const wchar_t* WM_MAGPIE_QUIT = L"WM_MAGPIE_QUIT";
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
#pragma once
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3d11_4.h>
|
||||
|
||||
namespace Magpie {
|
||||
|
||||
struct DirectXHelper {
|
||||
static bool IsWARP(const DXGI_ADAPTER_DESC1& desc) noexcept {
|
||||
// 不要检查 DXGI_ADAPTER_FLAG_SOFTWARE 标志,如果系统没有安装任何显卡,WARP 没有这个标志。
|
||||
// 这两个值来自 https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/d3d10-graphics-programming-guide-dxgi#new-info-about-enumerating-adapters-for-windows-8
|
||||
return desc.VendorId == 0x1414 && desc.DeviceId == 0x8c;
|
||||
}
|
||||
|
||||
static bool CompileComputeShader(
|
||||
std::string_view hlsl,
|
||||
const char* entryPoint,
|
||||
|
|
@ -28,6 +28,17 @@ struct Cropping {
|
|||
float Bottom;
|
||||
};
|
||||
|
||||
struct GraphicsCardId {
|
||||
// idx 为显卡索引,vendorId 和 deviceId 用于验证,如果不匹配则遍历显卡查找匹配。这可以处理显卡
|
||||
// 改变的情况,比如某些笔记本电脑可以在混合架构和独显直连之间切换。
|
||||
// idx 有两个作用,一是作为性能优化,二是用于区分同一型号的两个显卡。
|
||||
// idx 为 -1 表示使用默认显卡,如果此时 vendorId 和 deviceId 有值表示由于目前不存在该显卡因此
|
||||
// 使用默认显卡,如果以后该显卡再次可用将自动使用。
|
||||
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;
|
||||
|
|
@ -100,7 +111,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;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ constexpr bool operator==(const POINT& l, const POINT& r) noexcept {
|
|||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
|
||||
// 避免和 d3d11.h 中的定义冲突
|
||||
// 避免和 d3d11.h 中的定义冲突,应在该头文件后包含
|
||||
#ifndef __d3d11_h__
|
||||
constexpr bool operator==(const RECT& l, const RECT& r) noexcept {
|
||||
return l.left == r.left && l.top == r.top && l.right == r.right && l.bottom == r.bottom;
|
||||
|
|
|
|||
255
src/Magpie/AdaptersService.cpp
Normal file
255
src/Magpie/AdaptersService.cpp
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
#include "pch.h"
|
||||
#include <d3d11_4.h>
|
||||
#include "AdaptersService.h"
|
||||
#include "Logger.h"
|
||||
#include "Win32Helper.h"
|
||||
#include "App.h"
|
||||
#include "DirectXHelper.h"
|
||||
|
||||
using namespace winrt::Magpie::implementation;
|
||||
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) || DirectXHelper::IsWARP(desc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 初始化时不检查是否支持 FL11,有些设备上 D3D11CreateDevice 相当慢
|
||||
_adapterInfos.push_back({
|
||||
.idx = adapterIdx,
|
||||
.vendorId = desc.VendorId,
|
||||
.deviceId = desc.DeviceId,
|
||||
.description = desc.Description
|
||||
});
|
||||
}
|
||||
|
||||
_UpdateProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdaptersService::Uninitialize() noexcept {
|
||||
if (!_monitorThread.joinable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const HANDLE hToastThread = _monitorThread.native_handle();
|
||||
if (!wil::handle_wait(hToastThread, 0)) {
|
||||
const DWORD threadId = GetThreadId(hToastThread);
|
||||
|
||||
// 持续尝试直到 _monitorThread 创建了消息队列
|
||||
while (!PostThreadMessage(threadId, WM_QUIT, 0, 0)) {
|
||||
if (wil::handle_wait(hToastThread, 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_monitorThread.join();
|
||||
}
|
||||
|
||||
void AdaptersService::StartMonitor() noexcept {
|
||||
_monitorThread = std::thread(std::bind_front(&AdaptersService::_MonitorThreadProc, this));
|
||||
}
|
||||
|
||||
bool AdaptersService::_GatherAdapterInfos(
|
||||
com_ptr<IDXGIFactory7>& dxgiFactory,
|
||||
wil::unique_event_nothrow& adaptersChangedEvent,
|
||||
DWORD& adaptersChangedCookie
|
||||
) noexcept {
|
||||
// 显卡变化后需要重新创建 DXGI 工厂
|
||||
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("CreateDXGIFactory1 失败", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = dxgiFactory->RegisterAdaptersChangedEvent(
|
||||
adaptersChangedEvent.get(), &adaptersChangedCookie);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("RegisterAdaptersChangedEvent 失败", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<AdapterInfo> adapterInfos;
|
||||
SmallVector<com_ptr<IDXGIAdapter1>> adapters;
|
||||
|
||||
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) || DirectXHelper::IsWARP(desc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
adapterInfos.push_back({
|
||||
.idx = adapterIdx,
|
||||
.vendorId = desc.VendorId,
|
||||
.deviceId = desc.DeviceId,
|
||||
.description = desc.Description
|
||||
});
|
||||
|
||||
adapters.push_back(std::move(curAdapter));
|
||||
}
|
||||
|
||||
// 删除不支持功能级别 11 的显卡
|
||||
std::vector<AdapterInfo> compatibleAdapterInfos;
|
||||
wil::srwlock writeLock;
|
||||
Win32Helper::RunParallel([&](uint32_t i) {
|
||||
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
|
||||
if (SUCCEEDED(D3D11CreateDevice(adapters[i].get(), D3D_DRIVER_TYPE_UNKNOWN,
|
||||
NULL, 0, &fl, 1, D3D11_SDK_VERSION, nullptr, nullptr, nullptr))) {
|
||||
auto lock = writeLock.lock_exclusive();
|
||||
compatibleAdapterInfos.push_back(std::move(adapterInfos[i]));
|
||||
}
|
||||
}, (uint32_t)adapters.size());
|
||||
|
||||
App::Get().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this, adapterInfos(std::move(compatibleAdapterInfos))]() {
|
||||
_adapterInfos = std::move(adapterInfos);
|
||||
_UpdateProfiles();
|
||||
AdaptersChanged.Invoke();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdaptersService::_MonitorThreadProc() noexcept {
|
||||
#ifdef _DEBUG
|
||||
SetThreadDescription(GetCurrentThread(), L"AdaptersService 线程");
|
||||
#endif
|
||||
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
wil::unique_event_nothrow adaptersChangedEvent;
|
||||
HRESULT hr = adaptersChangedEvent.create();
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("创建 event 失败", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
com_ptr<IDXGIFactory7> dxgiFactory;
|
||||
DWORD adaptersChangedCookie = 0;
|
||||
if (!_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
break;
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
if (msg.message == WM_QUIT) {
|
||||
break;
|
||||
}
|
||||
|
||||
HANDLE hAdaptersChangedEvent = adaptersChangedEvent.get();
|
||||
if (MsgWaitForMultipleObjectsEx(1, &hAdaptersChangedEvent,
|
||||
INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE) == WAIT_OBJECT_0) {
|
||||
// WAIT_OBJECT_0 表示显卡变化
|
||||
// WAIT_OBJECT_0 + 1 表示有新消息
|
||||
if (!_GatherAdapterInfos(dxgiFactory, adaptersChangedEvent, adaptersChangedCookie)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dxgiFactory->UnregisterAdaptersChangedEvent(adaptersChangedCookie);
|
||||
}
|
||||
|
||||
// 有更改返回 true
|
||||
bool AdaptersService::_UpdateProfileGraphicsCardId(Profile& profile) noexcept {
|
||||
GraphicsCardId& gcid = profile.graphicsCardId;
|
||||
|
||||
if (gcid.vendorId == 0 && gcid.deviceId == 0) {
|
||||
if (gcid.idx < 0) {
|
||||
// 使用默认显卡
|
||||
return false;
|
||||
}
|
||||
|
||||
// 来自旧版本的配置文件不存在 vendorId 和 deviceId,更新为新版本
|
||||
auto it = std::find_if(_adapterInfos.begin(), _adapterInfos.end(),
|
||||
[&](const AdapterInfo& ai) { return (int)ai.idx == gcid.idx; });
|
||||
if (it == _adapterInfos.end()) {
|
||||
// 未找到序号则改为使用默认显卡,无论如何原始配置已经丢失
|
||||
gcid.idx = -1;
|
||||
} else {
|
||||
gcid.vendorId = it->vendorId;
|
||||
gcid.deviceId = it->deviceId;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto it = std::find_if(_adapterInfos.begin(), _adapterInfos.end(), [&](const AdapterInfo& ai) {
|
||||
return (int)ai.idx == gcid.idx && ai.vendorId == gcid.vendorId && ai.deviceId == gcid.deviceId;
|
||||
});
|
||||
if (it != _adapterInfos.end()) {
|
||||
// 全部匹配
|
||||
return false;
|
||||
}
|
||||
|
||||
// 序号指定的显卡不匹配则查找新序号
|
||||
it = std::find_if(_adapterInfos.begin(), _adapterInfos.end(), [&](const AdapterInfo& ai) {
|
||||
return ai.vendorId == gcid.vendorId && ai.deviceId == gcid.deviceId;
|
||||
});
|
||||
if (it == _adapterInfos.end()) {
|
||||
// 找不到则将 idx 置为 -1 表示使用默认显卡,不改变 vendorId 和 deviceId,
|
||||
// 这样当指定的显卡再次可用时将自动使用。
|
||||
if (gcid.idx == -1) {
|
||||
return false;
|
||||
} else {
|
||||
gcid.idx = -1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
gcid.idx = it->idx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AdaptersService::_UpdateProfiles() noexcept {
|
||||
bool needSave = false;
|
||||
|
||||
// 更新所有配置文件的显卡配置
|
||||
if (_UpdateProfileGraphicsCardId(AppSettings::Get().DefaultProfile())) {
|
||||
needSave = true;
|
||||
}
|
||||
|
||||
for (Profile& profile : AppSettings::Get().Profiles()) {
|
||||
if (_UpdateProfileGraphicsCardId(profile)) {
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needSave) {
|
||||
AppSettings::Get().SaveAsync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
58
src/Magpie/AdaptersService.h
Normal file
58
src/Magpie/AdaptersService.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include "SmallVector.h"
|
||||
#include <dxgi1_6.h>
|
||||
#include "Event.h"
|
||||
|
||||
namespace Magpie {
|
||||
|
||||
struct Profile;
|
||||
|
||||
struct AdapterInfo {
|
||||
uint32_t idx = 0;
|
||||
uint32_t vendorId = 0;
|
||||
uint32_t deviceId = 0;
|
||||
std::wstring description;
|
||||
};
|
||||
|
||||
class AdaptersService {
|
||||
public:
|
||||
static AdaptersService& Get() noexcept {
|
||||
static AdaptersService instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
AdaptersService(const AdaptersService&) = delete;
|
||||
AdaptersService(AdaptersService&&) = delete;
|
||||
|
||||
bool Initialize() noexcept;
|
||||
|
||||
void Uninitialize() noexcept;
|
||||
|
||||
void StartMonitor() noexcept;
|
||||
|
||||
const std::vector<AdapterInfo>& AdapterInfos() const noexcept {
|
||||
return _adapterInfos;
|
||||
}
|
||||
|
||||
Event<> AdaptersChanged;
|
||||
|
||||
private:
|
||||
AdaptersService() = default;
|
||||
|
||||
bool _GatherAdapterInfos(
|
||||
winrt::com_ptr<IDXGIFactory7>& dxgiFactory,
|
||||
wil::unique_event_nothrow& adaptersChangedEvent,
|
||||
DWORD& adaptersChangedCookie
|
||||
) noexcept;
|
||||
|
||||
void _MonitorThreadProc() noexcept;
|
||||
|
||||
bool _UpdateProfileGraphicsCardId(Profile& profile) noexcept;
|
||||
|
||||
void _UpdateProfiles() noexcept;
|
||||
|
||||
std::thread _monitorThread;
|
||||
std::vector<AdapterInfo> _adapterInfos;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "IsNullStateTrigger.h"
|
||||
#include "TextBlockHelper.h"
|
||||
#include "MainWindow.h"
|
||||
#include "AdaptersService.h"
|
||||
|
||||
using namespace ::Magpie;
|
||||
using namespace winrt;
|
||||
|
|
@ -146,6 +147,7 @@ bool App::Initialize(const wchar_t* arguments) {
|
|||
|
||||
if (settings.IsAlwaysRunAsAdmin() && !Win32Helper::IsProcessElevated()) {
|
||||
Restart(true, arguments);
|
||||
_Uninitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -164,6 +166,10 @@ bool App::Initialize(const wchar_t* arguments) {
|
|||
|
||||
LocalizationService::Get().Initialize();
|
||||
ToastService::Get().Initialize();
|
||||
if (!AdaptersService::Get().Initialize()) {
|
||||
_Uninitialize();
|
||||
return false;
|
||||
}
|
||||
ShortcutService::Get().Initialize();
|
||||
ScalingService::Get().Initialize();
|
||||
UpdateService::Get().Initialize();
|
||||
|
|
@ -178,9 +184,20 @@ bool App::Initialize(const wchar_t* arguments) {
|
|||
// 不显示托盘图标时忽略 -t 参数
|
||||
if (!notifyIconService.IsShow() || arguments != L"-t"sv) {
|
||||
if (!_mainWindow->Create()) {
|
||||
Quit();
|
||||
_Uninitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 有的设备上后台调用 D3D11CreateDevice 会拖累主窗口显示速度,因此应在主窗口显示后
|
||||
// 再检查显卡的功能级别。
|
||||
((RootPage::base_type&)*_mainWindow->Content()).Loaded([](const auto&, const auto&) {
|
||||
// 低优先级回调确保在初始化完毕后执行
|
||||
App::Get().Dispatcher().RunAsync(CoreDispatcherPriority::Low, []() {
|
||||
AdaptersService::Get().StartMonitor();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
AdaptersService::Get().StartMonitor();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -249,10 +266,11 @@ const com_ptr<RootPage>& App::RootPage() const noexcept {
|
|||
void App::_Uninitialize() {
|
||||
NotifyIconService::Get().Uninitialize();
|
||||
ScalingService::Get().Uninitialize();
|
||||
// 不显示托盘图标的情况下关闭主窗口仍会在后台驻留数秒,推测和 XAML Islands 有关。
|
||||
// 这里提前取消热键注册,这样关闭 Magpie 后立即重新打开不会注册热键失败。
|
||||
// 提前取消热键注册,这样关闭 Magpie 后立即重新打开不会注册热键失败
|
||||
ShortcutService::Get().Uninitialize();
|
||||
AdaptersService::Get().Uninitialize();
|
||||
ToastService::Get().Uninitialize();
|
||||
EffectsService::Get().Uninitialize();
|
||||
|
||||
_colorValuesChangedRevoker.revoke();
|
||||
_isShowNotifyIconChangedRevoker.Revoke();
|
||||
|
|
|
|||
|
|
@ -86,8 +86,15 @@ static void WriteProfile(rapidjson::PrettyWriter<rapidjson::StringBuffer>& write
|
|||
writer.Key("multiMonitorUsage");
|
||||
writer.Uint((uint32_t)profile.multiMonitorUsage);
|
||||
|
||||
writer.Key("graphicsCard");
|
||||
writer.Int(profile.graphicsCard);
|
||||
writer.Key("graphicsCardId");
|
||||
writer.StartObject();
|
||||
writer.Key("idx");
|
||||
writer.Int(profile.graphicsCardId.idx);
|
||||
writer.Key("vendorId");
|
||||
writer.Uint(profile.graphicsCardId.vendorId);
|
||||
writer.Key("deviceId");
|
||||
writer.Uint(profile.graphicsCardId.deviceId);
|
||||
writer.EndObject();
|
||||
writer.Key("frameRateLimiterEnabled");
|
||||
writer.Bool(profile.isFrameRateLimiterEnabled);
|
||||
writer.Key("maxFrameRate");
|
||||
|
|
@ -792,11 +799,38 @@ bool AppSettings::_LoadProfile(
|
|||
profile.multiMonitorUsage = (MultiMonitorUsage)multiMonitorUsage;
|
||||
}
|
||||
|
||||
if (!JsonHelper::ReadInt(profileObj, "graphicsCard", profile.graphicsCard, true)) {
|
||||
// v0.10.0-preview1 使用 graphicsAdapter
|
||||
uint32_t graphicsAdater = 0;
|
||||
JsonHelper::ReadUInt(profileObj, "graphicsAdapter", graphicsAdater);
|
||||
profile.graphicsCard = (int)graphicsAdater - 1;
|
||||
{
|
||||
auto graphicsCardIdNode = profileObj.FindMember("graphicsCardId");
|
||||
if (graphicsCardIdNode == profileObj.end()) {
|
||||
// v0.10 和 v0.11 只使用索引
|
||||
int graphicsCardIdx = -1;
|
||||
if (!JsonHelper::ReadInt(profileObj, "graphicsCard", graphicsCardIdx, true)) {
|
||||
// v0.10.0-preview1 使用 graphicsAdapter
|
||||
uint32_t graphicsAdater = 0;
|
||||
JsonHelper::ReadUInt(profileObj, "graphicsAdapter", graphicsAdater);
|
||||
graphicsCardIdx = (int)graphicsAdater - 1;
|
||||
}
|
||||
|
||||
// 稍后由 ProfileService 设置 vendorId 和 deviceId
|
||||
profile.graphicsCardId.idx = graphicsCardIdx;
|
||||
} else if (graphicsCardIdNode->value.IsObject()) {
|
||||
auto graphicsCardIdObj = graphicsCardIdNode->value.GetObj();
|
||||
|
||||
auto idxNode = graphicsCardIdObj.FindMember("idx");
|
||||
if (idxNode != graphicsCardIdObj.end() && idxNode->value.IsInt()) {
|
||||
profile.graphicsCardId.idx = idxNode->value.GetInt();
|
||||
}
|
||||
|
||||
auto vendorIdNode = graphicsCardIdObj.FindMember("vendorId");
|
||||
if (vendorIdNode != graphicsCardIdObj.end() && vendorIdNode->value.IsUint()) {
|
||||
profile.graphicsCardId.vendorId = vendorIdNode->value.GetUint();
|
||||
}
|
||||
|
||||
auto deviceIdNode = graphicsCardIdObj.FindMember("deviceId");
|
||||
if (deviceIdNode != graphicsCardIdObj.end() && deviceIdNode->value.IsUint()) {
|
||||
profile.graphicsCardId.deviceId = deviceIdNode->value.GetUint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JsonHelper::ReadBool(profileObj, "frameRateLimiterEnabled", profile.isFrameRateLimiterEnabled);
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ public:
|
|||
return _duplicateFrameDetectionMode;
|
||||
}
|
||||
|
||||
void DuplicateFrameDetectionMode(Magpie::DuplicateFrameDetectionMode value) noexcept {
|
||||
void DuplicateFrameDetectionMode(enum DuplicateFrameDetectionMode value) noexcept {
|
||||
_duplicateFrameDetectionMode = value;
|
||||
SaveAsync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,11 @@ fire_and_forget EffectsService::Initialize() {
|
|||
_initialized.notify_one();
|
||||
}
|
||||
|
||||
void EffectsService::Uninitialize() {
|
||||
// 等待解析完成,防止退出时崩溃
|
||||
_WaitForInitialize();
|
||||
}
|
||||
|
||||
const std::vector<EffectInfo>& EffectsService::Effects() noexcept {
|
||||
_WaitForInitialize();
|
||||
return _effects;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ public:
|
|||
|
||||
winrt::fire_and_forget Initialize();
|
||||
|
||||
void Uninitialize();
|
||||
|
||||
const std::vector<EffectInfo>& Effects() noexcept;
|
||||
|
||||
const EffectInfo* GetEffect(std::wstring_view name) noexcept;
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@
|
|||
<DependentUpon>AboutViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AdaptersService.h" />
|
||||
<ClInclude Include="AppSettings.h" />
|
||||
<ClInclude Include="AppXReader.h" />
|
||||
<ClInclude Include="AutoStartHelper.h" />
|
||||
|
|
@ -260,6 +261,7 @@
|
|||
<DependentUpon>AboutViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AdaptersService.cpp" />
|
||||
<ClCompile Include="AppSettings.cpp" />
|
||||
<ClCompile Include="AppXReader.cpp" />
|
||||
<ClCompile Include="AutoStartHelper.cpp" />
|
||||
|
|
|
|||
|
|
@ -73,6 +73,12 @@
|
|||
<ClCompile Include="XamlHelper.cpp">
|
||||
<Filter>Helpers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AdaptersService.cpp">
|
||||
<Filter>Services</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DirectXHelper.cpp">
|
||||
<Filter>Helpers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
|
@ -154,6 +160,12 @@
|
|||
<ClInclude Include="resource.h">
|
||||
<Filter>Resources</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AdaptersService.h">
|
||||
<Filter>Services</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DirectXHelper.h">
|
||||
<Filter>Helpers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Pages">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Magpie {
|
|||
|
||||
// 当任务栏被创建时会广播此消息。用于在资源管理器被重新启动时重新创建托盘图标
|
||||
// https://learn.microsoft.com/en-us/windows/win32/shell/taskbar#taskbar-creation-notification
|
||||
static UINT WM_TASKBARCREATED;
|
||||
static UINT WM_TASKBARCREATED = 0;
|
||||
|
||||
void NotifyIconService::Initialize() noexcept {
|
||||
WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
|
||||
|
|
@ -24,6 +24,10 @@ void NotifyIconService::Initialize() noexcept {
|
|||
}
|
||||
|
||||
void NotifyIconService::Uninitialize() noexcept {
|
||||
if (!WM_TASKBARCREATED) {
|
||||
return;
|
||||
}
|
||||
|
||||
IsShow(false);
|
||||
|
||||
if (_nid.hWnd) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public:
|
|||
void Uninitialize() noexcept;
|
||||
|
||||
void IsShow(bool value) noexcept;
|
||||
bool IsShow() noexcept {
|
||||
bool IsShow() const noexcept {
|
||||
// 返回 _shouldShow 而不是 _isShow,对外接口假设总是创建成功
|
||||
return _shouldShow;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ struct Profile {
|
|||
isCroppingEnabled = other.isCroppingEnabled;
|
||||
cropping = other.cropping;
|
||||
captureMethod = other.captureMethod;
|
||||
graphicsCard = other.graphicsCard;
|
||||
graphicsCardId = other.graphicsCardId;
|
||||
isFrameRateLimiterEnabled = other.isFrameRateLimiterEnabled;
|
||||
maxFrameRate = other.maxFrameRate;
|
||||
multiMonitorUsage = other.multiMonitorUsage;
|
||||
|
|
@ -33,13 +33,13 @@ struct Profile {
|
|||
scalingFlags = other.scalingFlags;
|
||||
}
|
||||
|
||||
DEFINE_FLAG_ACCESSOR(IsWindowResizingDisabled, ::Magpie::ScalingFlags::DisableWindowResizing, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(Is3DGameMode, ::Magpie::ScalingFlags::Is3DGameMode, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsShowFPS, ::Magpie::ScalingFlags::ShowFPS, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsCaptureTitleBar, ::Magpie::ScalingFlags::CaptureTitleBar, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsAdjustCursorSpeed, ::Magpie::ScalingFlags::AdjustCursorSpeed, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDrawCursor, ::Magpie::ScalingFlags::DrawCursor, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDirectFlipDisabled, ::Magpie::ScalingFlags::DisableDirectFlip, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsWindowResizingDisabled, ScalingFlags::DisableWindowResizing, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(Is3DGameMode, ScalingFlags::Is3DGameMode, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsShowFPS, ScalingFlags::ShowFPS, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsCaptureTitleBar, ScalingFlags::CaptureTitleBar, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsAdjustCursorSpeed, ScalingFlags::AdjustCursorSpeed, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDrawCursor, ScalingFlags::DrawCursor, scalingFlags)
|
||||
DEFINE_FLAG_ACCESSOR(IsDirectFlipDisabled, ScalingFlags::DisableDirectFlip, scalingFlags)
|
||||
|
||||
std::wstring name;
|
||||
|
||||
|
|
@ -54,21 +54,20 @@ struct Profile {
|
|||
CursorScaling cursorScaling = CursorScaling::NoScaling;
|
||||
float customCursorScaling = 1.0;
|
||||
|
||||
::Magpie::Cropping cropping{};
|
||||
Cropping cropping{};
|
||||
// -1 表示原样
|
||||
int scalingMode = -1;
|
||||
::Magpie::CaptureMethod captureMethod = ::Magpie::CaptureMethod::GraphicsCapture;
|
||||
// -1 表示默认,大于等于 0 为图形适配器的索引
|
||||
int graphicsCard = -1;
|
||||
::Magpie::MultiMonitorUsage multiMonitorUsage = ::Magpie::MultiMonitorUsage::Closest;
|
||||
::Magpie::CursorInterpolationMode cursorInterpolationMode = ::Magpie::CursorInterpolationMode::NearestNeighbor;
|
||||
CaptureMethod captureMethod = CaptureMethod::GraphicsCapture;
|
||||
GraphicsCardId graphicsCardId;
|
||||
MultiMonitorUsage multiMonitorUsage = MultiMonitorUsage::Closest;
|
||||
CursorInterpolationMode cursorInterpolationMode = CursorInterpolationMode::NearestNeighbor;
|
||||
|
||||
// 10~1000
|
||||
float maxFrameRate = 60.0f;
|
||||
|
||||
std::wstring launchParameters;
|
||||
|
||||
uint32_t scalingFlags = ::Magpie::ScalingFlags::AdjustCursorSpeed | ::Magpie::ScalingFlags::DrawCursor;
|
||||
uint32_t scalingFlags = ScalingFlags::AdjustCursorSpeed | ScalingFlags::DrawCursor;
|
||||
|
||||
bool isPackaged = false;
|
||||
bool isCroppingEnabled = false;
|
||||
|
|
|
|||
|
|
@ -214,15 +214,19 @@
|
|||
<local:SettingsGroup x:Uid="Profile_Performance">
|
||||
<local:SettingsCard x:Name="GraphicsCardSettingsCard"
|
||||
x:Uid="Profile_Performance_GraphicsCard"
|
||||
x:Load="{x:Bind ViewModel.IsShowGraphicsCardSettingsCard, Mode=OneTime}"
|
||||
x:Load="{x:Bind ViewModel.IsShowGraphicsCardSettingsCard, Mode=OneWay}"
|
||||
IsWrapEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
<ComboBox DropDownOpened="ComboBox_DropDownOpened"
|
||||
ItemsSource="{x:Bind ViewModel.GraphicsCards, Mode=OneTime}"
|
||||
ItemsSource="{x:Bind ViewModel.GraphicsCards, Mode=OneWay}"
|
||||
SelectedIndex="{x:Bind ViewModel.GraphicsCard, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
<muxc:InfoBar x:Uid="Profile_Performance_NoGraphicsCard"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsNoGraphicsCard, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
<local:SettingsCard x:Uid="Profile_Performance_ShowFPS">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "AppXReader.h"
|
||||
#include <regex>
|
||||
#include "StrHelper.h"
|
||||
#include "AdaptersService.h"
|
||||
|
||||
using namespace ::Magpie;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
#include "AppSettings.h"
|
||||
#include "Logger.h"
|
||||
#include "ScalingMode.h"
|
||||
#include <dxgi.h>
|
||||
#include "ScalingService.h"
|
||||
#include "FileDialogHelper.h"
|
||||
#include "CommonSharedConstants.h"
|
||||
#include "App.h"
|
||||
#include "MainWindow.h"
|
||||
#include "AdaptersService.h"
|
||||
|
||||
using namespace ::Magpie;
|
||||
using namespace winrt;
|
||||
|
|
@ -28,34 +28,6 @@ using namespace Windows::UI::Xaml::Media::Imaging;
|
|||
|
||||
namespace winrt::Magpie::implementation {
|
||||
|
||||
static SmallVector<std::wstring> GetAllGraphicsCards() {
|
||||
com_ptr<IDXGIFactory1> dxgiFactory;
|
||||
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
|
||||
if (FAILED(hr)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SmallVector<std::wstring> result;
|
||||
|
||||
com_ptr<IDXGIAdapter1> adapter;
|
||||
for (UINT adapterIndex = 0;
|
||||
SUCCEEDED(dxgiFactory->EnumAdapters1(adapterIndex, adapter.put()));
|
||||
++adapterIndex
|
||||
) {
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
hr = adapter->GetDesc1(&desc);
|
||||
|
||||
// 不包含 WARP
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.emplace_back(SUCCEEDED(hr) ? desc.Description : L"???");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ProfileViewModel::ProfileViewModel(int profileIdx) : _isDefaultProfile(profileIdx < 0) {
|
||||
if (_isDefaultProfile) {
|
||||
_data = &ProfileService::Get().DefaultProfile();
|
||||
|
|
@ -105,10 +77,8 @@ ProfileViewModel::ProfileViewModel(int profileIdx) : _isDefaultProfile(profileId
|
|||
_captureMethods = single_threaded_vector(std::move(captureMethods));
|
||||
}
|
||||
|
||||
_graphicsCards = GetAllGraphicsCards();
|
||||
if (_data->graphicsCard >= _graphicsCards.size()) {
|
||||
_data->graphicsCard = -1;
|
||||
}
|
||||
_adaptersChangedRevoker = AdaptersService::Get().AdaptersChanged(auto_revoke,
|
||||
std::bind_front(&ProfileViewModel::_AdaptersService_AdaptersChanged, this));
|
||||
}
|
||||
|
||||
ProfileViewModel::~ProfileViewModel() {}
|
||||
|
|
@ -440,42 +410,70 @@ void ProfileViewModel::MultiMonitorUsage(int value) {
|
|||
|
||||
IVector<IInspectable> ProfileViewModel::GraphicsCards() const noexcept {
|
||||
std::vector<IInspectable> graphicsCards;
|
||||
graphicsCards.reserve(_graphicsCards.size() + 1);
|
||||
|
||||
const std::vector<AdapterInfo>& adapterInfos = AdaptersService::Get().AdapterInfos();
|
||||
graphicsCards.reserve(adapterInfos.size() + 1);
|
||||
|
||||
ResourceLoader resourceLoader =
|
||||
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
|
||||
hstring defaultStr = resourceLoader.GetString(L"Profile_General_CaptureMethod_Default");
|
||||
graphicsCards.push_back(box_value(defaultStr));
|
||||
|
||||
for (const std::wstring& graphicsCard : _graphicsCards) {
|
||||
graphicsCards.push_back(box_value(graphicsCard));
|
||||
for (const AdapterInfo& adapterInfo : adapterInfos) {
|
||||
graphicsCards.push_back(box_value(adapterInfo.description));
|
||||
}
|
||||
|
||||
return single_threaded_vector(std::move(graphicsCards));
|
||||
}
|
||||
|
||||
int ProfileViewModel::GraphicsCard() const noexcept {
|
||||
return _data->graphicsCard + 1;
|
||||
if (_data->graphicsCardId.idx < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 不要把 graphicsCardId.idx 当作位序使用,AdaptersService 会过滤掉不支持 FL11 的显卡
|
||||
const std::vector<AdapterInfo>& adapterInfos = AdaptersService::Get().AdapterInfos();
|
||||
auto it = std::find_if(adapterInfos.begin(), adapterInfos.end(),
|
||||
[&](const AdapterInfo& ai) { return (int)ai.idx == _data->graphicsCardId.idx; });
|
||||
if (it == adapterInfos.end()) {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return int(it - adapterInfos.begin()) + 1;
|
||||
}
|
||||
|
||||
void ProfileViewModel::GraphicsCard(int value) {
|
||||
if (value < 0) {
|
||||
if (value < 0 || _isHandlingAdapterChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
--value;
|
||||
if (_data->graphicsCard == value) {
|
||||
return;
|
||||
}
|
||||
GraphicsCardId& gcid = _data->graphicsCardId;
|
||||
|
||||
_data->graphicsCard = value;
|
||||
const std::vector<AdapterInfo>& adapterInfos = AdaptersService::Get().AdapterInfos();
|
||||
if (value == 0 || value - 1 >= (int)adapterInfos.size()) {
|
||||
// 设为默认显卡,并清空 vendorId 和 deviceId
|
||||
gcid.idx = -1;
|
||||
gcid.vendorId = 0;
|
||||
gcid.deviceId = 0;
|
||||
} else {
|
||||
const AdapterInfo& ai = adapterInfos[size_t(value - 1)];
|
||||
gcid.idx = ai.idx;
|
||||
gcid.vendorId = ai.vendorId;
|
||||
gcid.deviceId = ai.deviceId;
|
||||
}
|
||||
|
||||
AppSettings::Get().SaveAsync();
|
||||
|
||||
RaisePropertyChanged(L"GraphicsCard");
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsShowGraphicsCardSettingsCard() const noexcept {
|
||||
return _graphicsCards.size() > 1;
|
||||
return AdaptersService::Get().AdapterInfos().size() > 1;
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsNoGraphicsCard() const noexcept {
|
||||
return AdaptersService::Get().AdapterInfos().empty();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::IsFrameRateLimiterEnabled() const noexcept {
|
||||
|
|
@ -810,4 +808,13 @@ fire_and_forget ProfileViewModel::_LoadIcon() {
|
|||
RaisePropertyChanged(L"Icon");
|
||||
}
|
||||
|
||||
void ProfileViewModel::_AdaptersService_AdaptersChanged() {
|
||||
_isHandlingAdapterChanged = true;
|
||||
RaisePropertyChanged(L"IsShowGraphicsCardSettingsCard");
|
||||
RaisePropertyChanged(L"IsNoGraphicsCard");
|
||||
RaisePropertyChanged(L"GraphicsCards");
|
||||
RaisePropertyChanged(L"GraphicsCard");
|
||||
_isHandlingAdapterChanged = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>,
|
|||
|
||||
bool IsShowGraphicsCardSettingsCard() const noexcept;
|
||||
|
||||
bool IsNoGraphicsCard() const noexcept;
|
||||
|
||||
bool IsFrameRateLimiterEnabled() const noexcept;
|
||||
void IsFrameRateLimiterEnabled(bool value);
|
||||
|
||||
|
|
@ -144,6 +146,8 @@ struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>,
|
|||
private:
|
||||
fire_and_forget _LoadIcon();
|
||||
|
||||
void _AdaptersService_AdaptersChanged();
|
||||
|
||||
bool _isProgramExist = true;
|
||||
|
||||
hstring _renameText;
|
||||
|
|
@ -151,7 +155,6 @@ private:
|
|||
|
||||
IVector<IInspectable> _scalingModes{ nullptr };
|
||||
IVector<IInspectable> _captureMethods{ nullptr };
|
||||
::Magpie::SmallVector<std::wstring> _graphicsCards;
|
||||
|
||||
uint32_t _index = 0;
|
||||
// 可以保存此指针的原因是: 用户停留在此页面时不会有缩放配置被创建或删除
|
||||
|
|
@ -159,11 +162,14 @@ private:
|
|||
|
||||
::Magpie::MultithreadEvent<bool>::EventRevoker _appThemeChangedRevoker;
|
||||
::Magpie::Event<uint32_t>::EventRevoker _dpiChangedRevoker;
|
||||
::Magpie::Event<>::EventRevoker _adaptersChangedRevoker;
|
||||
|
||||
Controls::IconElement _icon{ nullptr };
|
||||
|
||||
const bool _isDefaultProfile = true;
|
||||
bool _isRenameConfirmButtonEnabled = false;
|
||||
// 用于防止 ComboBox 可见性变化时错误修改 GraphicsCard 配置
|
||||
bool _isHandlingAdapterChanged = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ namespace Magpie {
|
|||
IVector<IInspectable> GraphicsCards { get; };
|
||||
Int32 GraphicsCard;
|
||||
Boolean IsShowGraphicsCardSettingsCard { get; };
|
||||
Boolean IsNoGraphicsCard { get; };
|
||||
|
||||
Boolean IsShowFPS;
|
||||
Boolean IsFrameRateLimiterEnabled;
|
||||
|
|
|
|||
|
|
@ -862,4 +862,7 @@
|
|||
<data name="Message_ScalingFailed" xml:space="preserve">
|
||||
<value>Scaling failed</value>
|
||||
</data>
|
||||
<data name="Profile_Performance_NoGraphicsCard.Title" xml:space="preserve">
|
||||
<value>No compatible graphics card was found, so CPU rendering will be used instead. Performance may not meet expectations.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -862,4 +862,7 @@
|
|||
<data name="Message_ScalingFailed" xml:space="preserve">
|
||||
<value>缩放时出错</value>
|
||||
</data>
|
||||
<data name="Profile_Performance_NoGraphicsCard.Title" xml:space="preserve">
|
||||
<value>由于找不到兼容的显卡,将使用 CPU 渲染。很可能达不到理想性能。</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -53,6 +53,10 @@ void ScalingService::Initialize() {
|
|||
}
|
||||
|
||||
void ScalingService::Uninitialize() {
|
||||
if (!_checkForegroundTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
_checkForegroundTimer.Cancel();
|
||||
_countDownTimer.Stop();
|
||||
_scalingRuntime.reset();
|
||||
|
|
@ -309,7 +313,7 @@ void ScalingService::_StartScale(HWND hWnd, const Profile& profile) {
|
|||
return;
|
||||
}
|
||||
|
||||
options.graphicsCard = profile.graphicsCard;
|
||||
options.graphicsCardId = profile.graphicsCardId;
|
||||
options.captureMethod = profile.captureMethod;
|
||||
if (profile.isFrameRateLimiterEnabled) {
|
||||
options.maxFrameRate = profile.maxFrameRate;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ void ShortcutService::Initialize() {
|
|||
}
|
||||
|
||||
void ShortcutService::Uninitialize() {
|
||||
if (!_hwndHotkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
_keyboardHook.reset();
|
||||
|
||||
for (int i = 0; i < (int)ShortcutAction::COUNT_OR_NONE; ++i) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ void ToastService::Uninitialize() noexcept {
|
|||
const DWORD threadId = GetThreadId(hToastThread);
|
||||
|
||||
// 持续尝试直到 _toastThread 创建了消息队列
|
||||
while (!PostThreadMessage(threadId, CommonSharedConstants::WM_TOAST_QUIT, 0, 0)) {
|
||||
while (!PostThreadMessage(threadId, WM_QUIT, 0, 0)) {
|
||||
if (wil::handle_wait(hToastThread, 1)) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ void ToastService::ShowMessageInApp(std::wstring_view title, std::wstring_view m
|
|||
|
||||
void ToastService::_ToastThreadProc() noexcept {
|
||||
#ifdef _DEBUG
|
||||
SetThreadDescription(GetCurrentThread(), L"Toast 线程");
|
||||
SetThreadDescription(GetCurrentThread(), L"ToastService 线程");
|
||||
#endif
|
||||
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
|
@ -108,23 +108,18 @@ void ToastService::_ToastThreadProc() noexcept {
|
|||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, nullptr, 0, 0)) {
|
||||
if (msg.message == CommonSharedConstants::WM_TOAST_QUIT) {
|
||||
DestroyWindow(_hwndToast);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
BOOL processed = FALSE;
|
||||
HRESULT hr = xamlSourceNative2->PreTranslateMessage(&msg, &processed);
|
||||
if (SUCCEEDED(hr) && processed) {
|
||||
continue;
|
||||
}
|
||||
BOOL processed = FALSE;
|
||||
HRESULT hr = xamlSourceNative2->PreTranslateMessage(&msg, &processed);
|
||||
if (SUCCEEDED(hr) && processed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
DestroyWindow(_hwndToast);
|
||||
|
||||
// 防止退出时崩溃
|
||||
_toastPage->Close();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue