perf: 避免多余栅栏

This commit is contained in:
Xu 2025-12-08 12:51:59 +08:00
commit 4326dc627c
7 changed files with 60 additions and 45 deletions

View file

@ -126,7 +126,8 @@ void FrameProducer::_ThreadProc(
}
}
// 不能在缩放线程释放
_graphicsContext.WaitForGpu();
// 必须在创建线程释放
_frameSource.reset();
}
@ -157,7 +158,7 @@ bool FrameProducer::_Initialize(
}
const uint32_t maxInFlightFrameCount = ScalingWindow::Get().Options().maxProducerInFlightFrames;
if (!_graphicsContext.Initialize(device, maxInFlightFrameCount, D3D12_COMMAND_LIST_TYPE_COMPUTE)) {
if (!_graphicsContext.Initialize(device, maxInFlightFrameCount, D3D12_COMMAND_LIST_TYPE_COMPUTE, true)) {
Logger::Get().Error("初始化 GraphicsContext 失败");
return false;
}

View file

@ -3,14 +3,14 @@
#include "Logger.h"
#include "DirectXHelper.h"
#include "StrHelper.h"
#include <d3dkmthk.h>
namespace Magpie {
bool GraphicsContext::Initialize(
const GraphicsCardId& graphicsCardId,
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameFenceTracking
) noexcept {
HRESULT hr = _CreateDXGIFactory();
if (FAILED(hr)) {
@ -23,7 +23,7 @@ bool GraphicsContext::Initialize(
return false;
}
if (!_InitializeDeviceResources(maxInFlightFrameCount, commandListType)) {
if (!_InitializeDeviceResources(maxInFlightFrameCount, commandListType, disableFrameFenceTracking)) {
Logger::Get().Error("_InitializeDeviceResources 失败");
return false;
}
@ -34,7 +34,8 @@ bool GraphicsContext::Initialize(
bool GraphicsContext::Initialize(
ID3D12Device5* device,
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameFenceTracking
) noexcept {
_device.copy_from(device);
@ -49,7 +50,7 @@ bool GraphicsContext::Initialize(
return false;
}
if (!_InitializeDeviceResources(maxInFlightFrameCount, commandListType)) {
if (!_InitializeDeviceResources(maxInFlightFrameCount, commandListType, disableFrameFenceTracking)) {
Logger::Get().Error("_InitializeDeviceResources 失败");
return false;
}
@ -81,7 +82,7 @@ HRESULT GraphicsContext::WaitForFenceValue(uint64_t fenceValue) noexcept {
}
}
HRESULT GraphicsContext::WaitForGPU() noexcept {
HRESULT GraphicsContext::WaitForGpu() noexcept {
HRESULT hr = _commandQueue->Signal(_fence.get(), ++_curFenceValue);
if (FAILED(hr)) {
return hr;
@ -91,12 +92,14 @@ HRESULT GraphicsContext::WaitForGPU() noexcept {
}
HRESULT GraphicsContext::BeginFrame(uint32_t& curFrameIndex, ID3D12PipelineState* initialState) noexcept {
HRESULT hr = WaitForFenceValue(_frameFenceValues[_curFrameIndex]);
if (FAILED(hr)) {
return hr;
if (!_frameFenceValues.empty()) {
HRESULT hr = WaitForFenceValue(_frameFenceValues[_curFrameIndex]);
if (FAILED(hr)) {
return hr;
}
}
hr = _commandAllocators[_curFrameIndex]->Reset();
HRESULT hr = _commandAllocators[_curFrameIndex]->Reset();
if (FAILED(hr)) {
return hr;
}
@ -111,9 +114,11 @@ HRESULT GraphicsContext::BeginFrame(uint32_t& curFrameIndex, ID3D12PipelineState
}
HRESULT GraphicsContext::EndFrame() noexcept {
HRESULT hr = Signal(_frameFenceValues[_curFrameIndex]);
if (FAILED(hr)) {
return hr;
if (!_frameFenceValues.empty()) {
HRESULT hr = Signal(_frameFenceValues[_curFrameIndex]);
if (FAILED(hr)) {
return hr;
}
}
_curFrameIndex = (_curFrameIndex + 1) % (uint32_t)_commandAllocators.size();
@ -132,7 +137,11 @@ HRESULT GraphicsContext::_CreateDXGIFactory() noexcept {
return hr;
}
bool GraphicsContext::_InitializeDeviceResources(uint32_t maxInFlightFrameCount, D3D12_COMMAND_LIST_TYPE commandListType) noexcept {
bool GraphicsContext::_InitializeDeviceResources(
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameFenceTracking
) noexcept {
// 检查根签名版本
{
D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = { .HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1 };
@ -178,7 +187,10 @@ bool GraphicsContext::_InitializeDeviceResources(uint32_t maxInFlightFrameCount,
return false;
}
_frameFenceValues.resize(maxInFlightFrameCount);
// 如果已在外部同步则无需追踪每帧的栅栏值
if (!disableFrameFenceTracking) {
_frameFenceValues.resize(maxInFlightFrameCount);
}
return true;
}
@ -280,17 +292,6 @@ bool GraphicsContext::_CreateAdapterAndDevice(const GraphicsCardId& graphicsCard
return true;
}
static void SetGpuPriority() noexcept {
// 来自 https://github.com/obsproject/obs-studio/blob/16cb051a57bb357fe866252c1360ce2c38e2deec/libobs-d3d11/d3d11-subsystem.cpp#L429
// 不使用 REALTIME 优先级,它会造成系统不稳定,而且可能会导致源窗口卡顿。
// OBS 还调用了 SetGPUThreadPriority但这个接口似乎无用。
NTSTATUS status = D3DKMTSetProcessSchedulingPriorityClass(
GetCurrentProcess(), D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH);
if (status != STATUS_SUCCESS) {
Logger::Get().NTError("D3DKMTSetProcessSchedulingPriorityClass 失败", status);
}
}
bool GraphicsContext::_TryCreateD3DDevice(const winrt::com_ptr<IDXGIAdapter1>& adapter, const DXGI_ADAPTER_DESC1& adapterDesc) noexcept {
HRESULT hr = D3D12CreateDevice(adapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device));
if (FAILED(hr)) {
@ -348,9 +349,6 @@ bool GraphicsContext::_TryCreateD3DDevice(const winrt::com_ptr<IDXGIAdapter1>& a
Logger::Get().Info(fmt::format("当前图形适配器: \n\tVendorId: {:#x}\n\tDeviceId: {:#x}\n\tDescription: {}",
adapterDesc.VendorId, adapterDesc.DeviceId, StrHelper::UTF16ToUTF8(adapterDesc.Description)));
// 每次创建 D3D 设备后尝试提高 GPU 优先级OBS 也是这么做的
SetGpuPriority();
return true;
}

View file

@ -12,13 +12,15 @@ public:
bool Initialize(
const GraphicsCardId& graphicsCardId,
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameFenceTracking = false
) noexcept;
bool Initialize(
ID3D12Device5* device,
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameTracking = false
) noexcept;
IDXGIFactory7* GetDXGIFactory() const noexcept {
@ -55,7 +57,7 @@ public:
HRESULT WaitForFenceValue(uint64_t fenceValue) noexcept;
HRESULT WaitForGPU() noexcept;
HRESULT WaitForGpu() noexcept;
HRESULT BeginFrame(
uint32_t& curFrameIndex,
@ -67,7 +69,11 @@ public:
private:
HRESULT _CreateDXGIFactory() noexcept;
bool _InitializeDeviceResources(uint32_t maxInFlightFrameCount, D3D12_COMMAND_LIST_TYPE commandListType) noexcept;
bool _InitializeDeviceResources(
uint32_t maxInFlightFrameCount,
D3D12_COMMAND_LIST_TYPE commandListType,
bool disableFrameFenceTracking
) noexcept;
bool _CreateAdapterAndDevice(const GraphicsCardId& graphicsCardId) noexcept;

View file

@ -6,18 +6,28 @@
#include "ScalingWindow.h"
#include "SwapChainPresenter.h"
#include "GraphicsCaptureFrameSource2.h"
#include <d3dkmthk.h>
#include <windows.graphics.display.interop.h>
namespace Magpie {
static constexpr HRESULT S_RECOVERED = CommonSharedConstants::S_RECOVERED;
static constexpr float SCENE_REFERRED_SDR_WHITE_LEVEL = (float)CommonSharedConstants::SCENE_REFERRED_SDR_WHITE_LEVEL;
Renderer2::Renderer2() noexcept {}
Renderer2::~Renderer2() noexcept {
_graphicsContext.WaitForGPU();
_graphicsContext.WaitForGpu();
}
static void SetGpuPriority() noexcept {
// 来自 https://github.com/obsproject/obs-studio/blob/16cb051a57bb357fe866252c1360ce2c38e2deec/libobs-d3d11/d3d11-subsystem.cpp#L429
// 不使用 REALTIME 优先级,它会造成系统不稳定,而且可能会导致源窗口卡顿。
// OBS 还调用了 SetGPUThreadPriority但这个接口似乎无用。
NTSTATUS status = D3DKMTSetProcessSchedulingPriorityClass(
GetCurrentProcess(), D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH);
if (status != STATUS_SUCCESS) {
Logger::Get().NTError("D3DKMTSetProcessSchedulingPriorityClass 失败", status);
}
}
ScalingError Renderer2::Initialize(
@ -30,11 +40,14 @@ ScalingError Renderer2::Initialize(
_hCurMonitor = hMonitor;
const ScalingOptions& options = ScalingWindow::Get().Options();
if (FAILED(_graphicsContext.Initialize(options.graphicsCardId, options.Is3DGameMode() ? 4 : 8, D3D12_COMMAND_LIST_TYPE_DIRECT))) {
if (!_graphicsContext.Initialize(options.graphicsCardId, options.Is3DGameMode() ? 4 : 8, D3D12_COMMAND_LIST_TYPE_DIRECT)) {
Logger::Get().Error("初始化 GraphicsContext 失败");
return ScalingError::ScalingFailedGeneral;
}
// 每次创建 D3D 设备后尝试提高 GPU 优先级OBS 也是这么做的
SetGpuPriority();
// 失败则回落到使用传统方法获取颜色显示能力
_TryInitDisplayInfo();

View file

@ -1,6 +1,5 @@
#include "pch.h"
#include "SharedRingBuffer.h"
#include "GraphicsContext.h"
#include "Logger.h"
#include "ScalingWindow.h"

View file

@ -9,8 +9,6 @@
namespace Magpie {
static constexpr uint32_t BUFFER_COUNT_DURING_RESIZE = 2;
bool SwapChainPresenter::Initialize(
GraphicsContext& graphicContext,
HWND hwndAttach,
@ -204,7 +202,7 @@ HRESULT SwapChainPresenter::EndFrame() noexcept {
// 实用价值。
// 等待渲染完成
HRESULT hr = _graphicContext->WaitForGPU();
HRESULT hr = _graphicContext->WaitForGpu();
if (FAILED(hr)) {
Logger::Get().ComError("GraphicsContext::WaitForGPU", hr);
return hr;
@ -278,7 +276,7 @@ HRESULT SwapChainPresenter::OnColorInfoChanged(const ColorInfo& colorInfo) noexc
}
HRESULT SwapChainPresenter::_RecreateBuffers() noexcept {
HRESULT hr = _graphicContext->WaitForGPU();
HRESULT hr = _graphicContext->WaitForGpu();
if (FAILED(hr)) {
Logger::Get().ComError("GraphicsContext::WaitForGPU", hr);
return hr;

View file

@ -65,7 +65,7 @@ static void InitializeDirectX() noexcept {
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// 启用 GPU-based validation但会产生警告消息而且这个消息无法轻易禁用
debugController->SetEnableGPUBasedValidation(TRUE);
// debugController->SetEnableGPUBasedValidation(TRUE);
// Win11 开始支持生成默认名字,包含资源的基本属性
if (winrt::com_ptr<ID3D12Debug5> debugController5 = debugController.try_as<ID3D12Debug5>()) {