Skip to content

Commit

Permalink
feat: 初步实现最小帧率
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Dec 29, 2024
1 parent 303b90a commit c17b998
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 102 deletions.
16 changes: 8 additions & 8 deletions src/Magpie.Core/DesktopDuplicationFrameSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ bool DesktopDuplicationFrameSource::_Initialize() noexcept {
return true;
}

FrameSourceBase::UpdateState DesktopDuplicationFrameSource::_Update() noexcept {
FrameSourceState DesktopDuplicationFrameSource::_Update() noexcept {
ID3D11DeviceContext4* d3dDC = _deviceResources->GetD3DDC();

if (_isFrameAcquired) {
Expand All @@ -139,12 +139,12 @@ FrameSourceBase::UpdateState DesktopDuplicationFrameSource::_Update() noexcept {
// 等待 1ms
HRESULT hr = _outputDup->AcquireNextFrame(1, &info, dxgiRes.put());
if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
return UpdateState::Waiting;
return FrameSourceState::Waiting;
}

if (FAILED(hr)) {
Logger::Get().ComError("AcquireNextFrame 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

_isFrameAcquired = true;
Expand All @@ -165,7 +165,7 @@ FrameSourceBase::UpdateState DesktopDuplicationFrameSource::_Update() noexcept {
bufSize, (DXGI_OUTDUPL_MOVE_RECT*)_dupMetaData.data(), &bufSize);
if (FAILED(hr)) {
Logger::Get().ComError("GetFrameMoveRects 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

uint32_t nRect = bufSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
Expand All @@ -186,7 +186,7 @@ FrameSourceBase::UpdateState DesktopDuplicationFrameSource::_Update() noexcept {
bufSize, (RECT*)_dupMetaData.data(), &bufSize);
if (FAILED(hr)) {
Logger::Get().ComError("GetFrameDirtyRects 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

nRect = bufSize / sizeof(RECT);
Expand All @@ -201,19 +201,19 @@ FrameSourceBase::UpdateState DesktopDuplicationFrameSource::_Update() noexcept {
}

if (noUpdate) {
return UpdateState::Waiting;
return FrameSourceState::Waiting;
}

winrt::com_ptr<ID3D11Texture2D> frameTexture = dxgiRes.try_as<ID3D11Texture2D>();
if (!frameTexture) {
Logger::Get().Error("从 IDXGIResource 检索 ID3D11Resource 失败");
return UpdateState::Error;
return FrameSourceState::Error;
}

d3dDC->CopySubresourceRegion(
_output.get(), 0, 0, 0, 0, frameTexture.get(), 0, &_frameInMonitor);

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}

}
4 changes: 2 additions & 2 deletions src/Magpie.Core/DesktopDuplicationFrameSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DesktopDuplicationFrameSource final : public FrameSourceBase {
}

FrameSourceWaitType WaitType() const noexcept override {
return WaitForFrame;
return FrameSourceWaitType::WaitForFrame;
}

const char* Name() const noexcept override {
Expand All @@ -30,7 +30,7 @@ class DesktopDuplicationFrameSource final : public FrameSourceBase {

bool _Initialize() noexcept override;

UpdateState _Update() noexcept override;
FrameSourceState _Update() noexcept override;

private:
winrt::com_ptr<IDXGIOutputDuplication> _outputDup;
Expand Down
8 changes: 4 additions & 4 deletions src/Magpie.Core/DwmSharedSurfaceFrameSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,28 +87,28 @@ bool DwmSharedSurfaceFrameSource::_Initialize() noexcept {
return true;
}

FrameSourceBase::UpdateState DwmSharedSurfaceFrameSource::_Update() noexcept {
FrameSourceState DwmSharedSurfaceFrameSource::_Update() noexcept {
HANDLE sharedTextureHandle = NULL;
if (!dwmGetDxSharedSurface(ScalingWindow::Get().HwndSrc(),
&sharedTextureHandle, nullptr, nullptr, nullptr, nullptr)
|| !sharedTextureHandle
) {
Logger::Get().Win32Error("DwmGetDxSharedSurface 失败");
return UpdateState::Error;
return FrameSourceState::Error;
}

winrt::com_ptr<ID3D11Texture2D> sharedTexture;
HRESULT hr = _deviceResources->GetD3DDevice()
->OpenSharedResource(sharedTextureHandle, IID_PPV_ARGS(&sharedTexture));
if (FAILED(hr)) {
Logger::Get().ComError("OpenSharedResource 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

_deviceResources->GetD3DDC()->CopySubresourceRegion(
_output.get(), 0, 0, 0, 0, sharedTexture.get(), 0, &_frameInWnd);

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}

}
4 changes: 2 additions & 2 deletions src/Magpie.Core/DwmSharedSurfaceFrameSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DwmSharedSurfaceFrameSource final : public FrameSourceBase {
}

FrameSourceWaitType WaitType() const noexcept override {
return NoWait;
return FrameSourceWaitType::NoWait;
}

const char* Name() const noexcept override {
Expand All @@ -22,7 +22,7 @@ class DwmSharedSurfaceFrameSource final : public FrameSourceBase {
protected:
bool _Initialize() noexcept override;

UpdateState _Update() noexcept override;
FrameSourceState _Update() noexcept override;

bool _HasRoundCornerInWin11() noexcept override {
return false;
Expand Down
22 changes: 13 additions & 9 deletions src/Magpie.Core/FrameSourceBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,16 @@ bool FrameSourceBase::Initialize(DeviceResources& deviceResources, BackendDescri
return true;
}

FrameSourceBase::UpdateState FrameSourceBase::Update() noexcept {
const UpdateState state = _Update();
FrameSourceState FrameSourceBase::Update(bool forceNewFrame) noexcept {
const FrameSourceState state = _Update();

if (forceNewFrame) {
return FrameSourceState::NewFrame;
}

const ScalingOptions& options = ScalingWindow::Get().Options();
const auto duplicateFrameDetectionMode = options.duplicateFrameDetectionMode;
if (state != UpdateState::NewFrame || options.Is3DGameMode() ||
if (state != FrameSourceState::NewFrame || options.Is3DGameMode() ||
duplicateFrameDetectionMode == DuplicateFrameDetectionMode::Never) {
return state;
}
Expand All @@ -131,16 +135,16 @@ FrameSourceBase::UpdateState FrameSourceBase::Update() noexcept {
_prevFrameSrv = nullptr;
}

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}

if (duplicateFrameDetectionMode == DuplicateFrameDetectionMode::Always) {
// 总是检查重复帧
if (_IsDuplicateFrame()) {
return UpdateState::Waiting;
return FrameSourceState::Waiting;
} else {
d3dDC->CopyResource(_prevFrame.get(), _output.get());
return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}
}

Expand All @@ -166,12 +170,12 @@ FrameSourceBase::UpdateState FrameSourceBase::Update() noexcept {
_isCheckingForDuplicateFrame = true;
_framesLeft = INITIAL_CHECK_COUNT;
_nextSkipCount = INITIAL_SKIP_COUNT;
return UpdateState::Waiting;
return FrameSourceState::Waiting;
} else {
if (_isCheckingForDuplicateFrame || isStatisticsEnabled) {
d3dDC->CopyResource(_prevFrame.get(), _output.get());
}
return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}
} else {
if (--_framesLeft == 0) {
Expand Down Expand Up @@ -201,7 +205,7 @@ FrameSourceBase::UpdateState FrameSourceBase::Update() noexcept {
_statistics.store(statistics, std::memory_order_relaxed);
}

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}
}

Expand Down
28 changes: 14 additions & 14 deletions src/Magpie.Core/FrameSourceBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ namespace Magpie {
class DeviceResources;
class BackendDescriptorStore;

enum class FrameSourceWaitType {
NoWait,
WaitForMessage,
WaitForFrame
};

enum class FrameSourceState {
NewFrame,
Waiting,
Error
};

class FrameSourceBase {
public:
FrameSourceBase() noexcept;
Expand All @@ -17,13 +29,7 @@ class FrameSourceBase {

bool Initialize(DeviceResources& deviceResources, BackendDescriptorStore& descriptorStore) noexcept;

enum class UpdateState {
NewFrame,
Waiting,
Error
};

UpdateState Update() noexcept;
FrameSourceState Update(bool forceNewFrame) noexcept;

ID3D11Texture2D* GetOutput() noexcept {
return _output.get();
Expand All @@ -39,20 +45,14 @@ class FrameSourceBase {

virtual bool IsScreenCapture() const noexcept = 0;

enum FrameSourceWaitType {
NoWait,
WaitForMessage,
WaitForFrame
};

virtual FrameSourceWaitType WaitType() const noexcept = 0;

virtual void OnCursorVisibilityChanged(bool /*isVisible*/, bool /*onDestory*/) noexcept {};

protected:
virtual bool _Initialize() noexcept = 0;

virtual UpdateState _Update() noexcept = 0;
virtual FrameSourceState _Update() noexcept = 0;

virtual bool _HasRoundCornerInWin11() noexcept = 0;

Expand Down
10 changes: 5 additions & 5 deletions src/Magpie.Core/GDIFrameSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ bool GDIFrameSource::_Initialize() noexcept {
return true;
}

FrameSourceBase::UpdateState GDIFrameSource::_Update() noexcept {
FrameSourceState GDIFrameSource::_Update() noexcept {
HDC hdcDest;
HRESULT hr = _dxgiSurface->GetDC(TRUE, &hdcDest);
if (FAILED(hr)) {
Logger::Get().ComError("从 Texture2D 获取 IDXGISurface1 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

auto se = wil::scope_exit([&]() {
Expand All @@ -79,17 +79,17 @@ FrameSourceBase::UpdateState GDIFrameSource::_Update() noexcept {
wil::unique_hdc_window hdcSrc(wil::window_dc(GetDCEx(hwndSrc, NULL, DCX_WINDOW), hwndSrc));
if (!hdcSrc) {
Logger::Get().Win32Error("GetDC 失败");
return UpdateState::Error;
return FrameSourceState::Error;
}

if (!BitBlt(hdcDest, 0, 0, _frameRect.right - _frameRect.left, _frameRect.bottom - _frameRect.top,
hdcSrc.get(), _frameRect.left, _frameRect.top, SRCCOPY)
) {
Logger::Get().Win32Error("BitBlt 失败");
return UpdateState::Error;
return FrameSourceState::Error;
}

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}

}
4 changes: 2 additions & 2 deletions src/Magpie.Core/GDIFrameSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class GDIFrameSource final : public FrameSourceBase {
}

FrameSourceWaitType WaitType() const noexcept override {
return NoWait;
return FrameSourceWaitType::NoWait;
}

const char* Name() const noexcept override {
Expand All @@ -22,7 +22,7 @@ class GDIFrameSource final : public FrameSourceBase {
protected:
bool _Initialize() noexcept override;

UpdateState _Update() noexcept override;
FrameSourceState _Update() noexcept override;

bool _HasRoundCornerInWin11() noexcept override {
return false;
Expand Down
10 changes: 5 additions & 5 deletions src/Magpie.Core/GraphicsCaptureFrameSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ bool GraphicsCaptureFrameSource::_Initialize() noexcept {
return true;
}

FrameSourceBase::UpdateState GraphicsCaptureFrameSource::_Update() noexcept {
FrameSourceState GraphicsCaptureFrameSource::_Update() noexcept {
if (!_captureSession) {
return UpdateState::Waiting;
return FrameSourceState::Waiting;
}

winrt::Direct3D11CaptureFrame frame = _captureFramePool.TryGetNextFrame();
if (!frame) {
// 因为已通过 FrameArrived 注册回调,所以每当有新帧时会有新消息到达
return UpdateState::Waiting;
return FrameSourceState::Waiting;
}

// 从帧获取 IDXGISurface
Expand All @@ -113,12 +113,12 @@ FrameSourceBase::UpdateState GraphicsCaptureFrameSource::_Update() noexcept {
HRESULT hr = dxgiInterfaceAccess->GetInterface(IID_PPV_ARGS(&withFrame));
if (FAILED(hr)) {
Logger::Get().ComError("从获取 IDirect3DSurface 获取 ID3D11Texture2D 失败", hr);
return UpdateState::Error;
return FrameSourceState::Error;
}

_deviceResources->GetD3DDC()->CopySubresourceRegion(_output.get(), 0, 0, 0, 0, withFrame.get(), 0, &_frameBox);

return UpdateState::NewFrame;
return FrameSourceState::NewFrame;
}

void GraphicsCaptureFrameSource::OnCursorVisibilityChanged(bool isVisible, bool onDestory) noexcept {
Expand Down
4 changes: 2 additions & 2 deletions src/Magpie.Core/GraphicsCaptureFrameSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GraphicsCaptureFrameSource final : public FrameSourceBase {
}

FrameSourceWaitType WaitType() const noexcept override {
return WaitForMessage;
return FrameSourceWaitType::WaitForMessage;
}

const char* Name() const noexcept override {
Expand All @@ -37,7 +37,7 @@ class GraphicsCaptureFrameSource final : public FrameSourceBase {

bool _Initialize() noexcept override;

UpdateState _Update() noexcept override;
FrameSourceState _Update() noexcept override;

private:
bool _StartCapture() noexcept;
Expand Down
Loading

0 comments on commit c17b998

Please sign in to comment.