mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
[Screen Ruler] optimize d3d device & continuous capture mode (#20198)
* [Screen Ruler] Exclude overlay window from capture * [Screen ruler] Sync OverlayUI threads creation and don't recreate d3d device
This commit is contained in:
5
.github/actions/spell-check/expect.txt
vendored
5
.github/actions/spell-check/expect.txt
vendored
@@ -346,6 +346,7 @@ CSIDL
|
|||||||
csignal
|
csignal
|
||||||
cso
|
cso
|
||||||
CSRW
|
CSRW
|
||||||
|
cstddef
|
||||||
cstdint
|
cstdint
|
||||||
cstdlib
|
cstdlib
|
||||||
cstring
|
cstring
|
||||||
@@ -489,6 +490,7 @@ dreamsofameaningfullife
|
|||||||
drivedetectionwarning
|
drivedetectionwarning
|
||||||
dshow
|
dshow
|
||||||
dst
|
dst
|
||||||
|
DState
|
||||||
DTo
|
DTo
|
||||||
dutil
|
dutil
|
||||||
DVASPECT
|
DVASPECT
|
||||||
@@ -579,6 +581,7 @@ EWXREBOOT
|
|||||||
EWXSHUTDOWN
|
EWXSHUTDOWN
|
||||||
examplehandler
|
examplehandler
|
||||||
examplepowertoy
|
examplepowertoy
|
||||||
|
EXCLUDEFROMCAPTURE
|
||||||
exdisp
|
exdisp
|
||||||
Executables
|
Executables
|
||||||
executionpolicy
|
executionpolicy
|
||||||
@@ -1628,6 +1631,7 @@ ptd
|
|||||||
PTOKEN
|
PTOKEN
|
||||||
PToy
|
PToy
|
||||||
ptr
|
ptr
|
||||||
|
ptrdiff
|
||||||
ptstr
|
ptstr
|
||||||
PVOID
|
PVOID
|
||||||
pwa
|
pwa
|
||||||
@@ -2273,6 +2277,7 @@ wcscpy
|
|||||||
wcslen
|
wcslen
|
||||||
wcsncmp
|
wcsncmp
|
||||||
wcsnicmp
|
wcsnicmp
|
||||||
|
WDA
|
||||||
wdp
|
wdp
|
||||||
wdupenv
|
wdupenv
|
||||||
weakme
|
weakme
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ D2DState::D2DState(const HWND overlayWindow, std::vector<D2D1::ColorF> solidBrus
|
|||||||
winrt::check_bool(GetClientRect(overlayWindow, &clientRect));
|
winrt::check_bool(GetClientRect(overlayWindow, &clientRect));
|
||||||
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &d2dFactory));
|
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &d2dFactory));
|
||||||
|
|
||||||
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), writeFactory.put_unknown()));
|
|
||||||
|
|
||||||
// We should always use DPIAware::DEFAULT_DPI, since it's the correct thing to do in DPI-Aware mode
|
// We should always use DPIAware::DEFAULT_DPI, since it's the correct thing to do in DPI-Aware mode
|
||||||
auto renderTargetProperties = D2D1::RenderTargetProperties(
|
auto renderTargetProperties = D2D1::RenderTargetProperties(
|
||||||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||||||
@@ -49,6 +47,7 @@ D2DState::D2DState(const HWND overlayWindow, std::vector<D2D1::ColorF> solidBrus
|
|||||||
DPIAware::GetScreenDPIForWindow(overlayWindow, dpi);
|
DPIAware::GetScreenDPIForWindow(overlayWindow, dpi);
|
||||||
dpiScale = dpi / static_cast<float>(DPIAware::DEFAULT_DPI);
|
dpiScale = dpi / static_cast<float>(DPIAware::DEFAULT_DPI);
|
||||||
|
|
||||||
|
winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), writeFactory.put_unknown()));
|
||||||
winrt::check_hresult(writeFactory->CreateTextFormat(L"Segoe UI Variable Text",
|
winrt::check_hresult(writeFactory->CreateTextFormat(L"Segoe UI Variable Text",
|
||||||
nullptr,
|
nullptr,
|
||||||
DWRITE_FONT_WEIGHT_NORMAL,
|
DWRITE_FONT_WEIGHT_NORMAL,
|
||||||
|
|||||||
@@ -10,28 +10,10 @@ inline long FindEdge(const BGRATextureView& texture, const POINT centerPoint, co
|
|||||||
{
|
{
|
||||||
using namespace consts;
|
using namespace consts;
|
||||||
|
|
||||||
long xOffset = 0;
|
|
||||||
long yOffset = 0;
|
|
||||||
|
|
||||||
// For continuous capture, we'll be a bit off center from the cursor so the cross we draw won't interfere with the measurement.
|
|
||||||
if constexpr (ContinuousCapture)
|
|
||||||
{
|
|
||||||
if constexpr (IsX)
|
|
||||||
{
|
|
||||||
xOffset = Increment ? CURSOR_OFFSET_AMOUNT_X : -CURSOR_OFFSET_AMOUNT_X;
|
|
||||||
yOffset = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xOffset = 1;
|
|
||||||
yOffset = Increment ? CURSOR_OFFSET_AMOUNT_Y : -CURSOR_OFFSET_AMOUNT_Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t maxDim = IsX ? texture.width : texture.height;
|
const size_t maxDim = IsX ? texture.width : texture.height;
|
||||||
|
|
||||||
long x = std::clamp<long>(centerPoint.x + xOffset, 1, static_cast<long>(texture.width - 2));
|
long x = std::clamp<long>(centerPoint.x, 1, static_cast<long>(texture.width - 2));
|
||||||
long y = std::clamp<long>(centerPoint.y + yOffset, 1, static_cast<long>(texture.height - 2));
|
long y = std::clamp<long>(centerPoint.y, 1, static_cast<long>(texture.height - 2));
|
||||||
|
|
||||||
const uint32_t startPixel = texture.GetPixel(x, y);
|
const uint32_t startPixel = texture.GetPixel(x, y);
|
||||||
while (true)
|
while (true)
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ void DrawMeasureToolTick(const CommonState& commonState,
|
|||||||
D2D_POINT_2F hLineEnd{ .x = hLineStart.x + hMeasure, .y = hLineStart.y };
|
D2D_POINT_2F hLineEnd{ .x = hLineStart.x + hMeasure, .y = hLineStart.y };
|
||||||
d2dState.rt->DrawLine(hLineStart, hLineEnd, d2dState.solidBrushes[Brush::line].get());
|
d2dState.rt->DrawLine(hLineStart, hLineEnd, d2dState.solidBrushes[Brush::line].get());
|
||||||
|
|
||||||
if (drawFeetOnCross && !continuousCapture)
|
if (drawFeetOnCross)
|
||||||
{
|
{
|
||||||
// To fill all pixels which are close, we call DrawLine with end point one pixel too far, since
|
// To fill all pixels which are close, we call DrawLine with end point one pixel too far, since
|
||||||
// it doesn't get filled, i.e. end point of the range is excluded. However, we want to draw cross
|
// it doesn't get filled, i.e. end point of the range is excluded. However, we want to draw cross
|
||||||
@@ -236,7 +236,7 @@ void DrawMeasureToolTick(const CommonState& commonState,
|
|||||||
D2D_POINT_2F vLineEnd{ .x = vLineStart.x, .y = vLineStart.y + vMeasure };
|
D2D_POINT_2F vLineEnd{ .x = vLineStart.x, .y = vLineStart.y + vMeasure };
|
||||||
d2dState.rt->DrawLine(vLineStart, vLineEnd, d2dState.solidBrushes[Brush::line].get());
|
d2dState.rt->DrawLine(vLineStart, vLineEnd, d2dState.solidBrushes[Brush::line].get());
|
||||||
|
|
||||||
if (drawFeetOnCross && !continuousCapture)
|
if (drawFeetOnCross)
|
||||||
{
|
{
|
||||||
vLineEnd.y -= 1.f;
|
vLineEnd.y -= 1.f;
|
||||||
auto [top_start, top_end] = ComputeCrossFeetLine(vLineStart, true);
|
auto [top_start, top_end] = ComputeCrossFeetLine(vLineStart, true);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ HWND CreateOverlayUIWindow(const CommonState& commonState,
|
|||||||
};
|
};
|
||||||
winrt::check_bool(window);
|
winrt::check_bool(window);
|
||||||
ShowWindow(window, SW_SHOWNORMAL);
|
ShowWindow(window, SW_SHOWNORMAL);
|
||||||
|
SetWindowDisplayAffinity(window, WDA_EXCLUDEFROMCAPTURE);
|
||||||
#if !defined(DEBUG_OVERLAY)
|
#if !defined(DEBUG_OVERLAY)
|
||||||
SetWindowPos(window, HWND_TOPMOST, {}, {}, {}, {}, SWP_NOMOVE | SWP_NOSIZE);
|
SetWindowPos(window, HWND_TOPMOST, {}, {}, {}, {}, SWP_NOMOVE | SWP_NOSIZE);
|
||||||
#else
|
#else
|
||||||
@@ -136,12 +137,7 @@ void OverlayUIState::RunUILoop()
|
|||||||
else
|
else
|
||||||
_d2dState.rt->Clear();
|
_d2dState.rt->Clear();
|
||||||
|
|
||||||
{
|
_d2dState.rt->EndDraw();
|
||||||
// TODO: use latch to wait until all threads are created their corresponding d2d textures
|
|
||||||
// in the non-continuous mode
|
|
||||||
// std::lock_guard guard{ gpuAccessLock };
|
|
||||||
_d2dState.rt->EndDraw();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run_message_loop(true, 1);
|
run_message_loop(true, 1);
|
||||||
@@ -182,6 +178,7 @@ template<typename ToolT, typename TickFuncT>
|
|||||||
inline std::unique_ptr<OverlayUIState> OverlayUIState::CreateInternal(ToolT& toolState,
|
inline std::unique_ptr<OverlayUIState> OverlayUIState::CreateInternal(ToolT& toolState,
|
||||||
TickFuncT tickFunc,
|
TickFuncT tickFunc,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
|
Latch& creationLatch,
|
||||||
const wchar_t* toolWindowClassName,
|
const wchar_t* toolWindowClassName,
|
||||||
void* windowParam,
|
void* windowParam,
|
||||||
const MonitorInfo& monitor,
|
const MonitorInfo& monitor,
|
||||||
@@ -199,6 +196,9 @@ inline std::unique_ptr<OverlayUIState> OverlayUIState::CreateInternal(ToolT& too
|
|||||||
auto* state = uiState.get();
|
auto* state = uiState.get();
|
||||||
uiCreatedEvent.SetEvent();
|
uiCreatedEvent.SetEvent();
|
||||||
|
|
||||||
|
// Wait until all OverlayUI threads created their corresponding d2d devices
|
||||||
|
creationLatch.arrive_and_wait();
|
||||||
|
|
||||||
state->RunUILoop();
|
state->RunUILoop();
|
||||||
|
|
||||||
commonState.closeOnOtherMonitors = true;
|
commonState.closeOnOtherMonitors = true;
|
||||||
@@ -211,12 +211,14 @@ inline std::unique_ptr<OverlayUIState> OverlayUIState::CreateInternal(ToolT& too
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<OverlayUIState> OverlayUIState::Create(Serialized<MeasureToolState>& toolState,
|
std::unique_ptr<OverlayUIState> OverlayUIState::Create(Serialized<MeasureToolState>& toolState,
|
||||||
|
Latch& creationLatch,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
const MonitorInfo& monitor)
|
const MonitorInfo& monitor)
|
||||||
{
|
{
|
||||||
return OverlayUIState::CreateInternal(toolState,
|
return OverlayUIState::CreateInternal(toolState,
|
||||||
DrawMeasureToolTick,
|
DrawMeasureToolTick,
|
||||||
commonState,
|
commonState,
|
||||||
|
creationLatch,
|
||||||
NonLocalizable::MeasureToolOverlayWindowName,
|
NonLocalizable::MeasureToolOverlayWindowName,
|
||||||
&toolState,
|
&toolState,
|
||||||
monitor,
|
monitor,
|
||||||
@@ -224,12 +226,14 @@ std::unique_ptr<OverlayUIState> OverlayUIState::Create(Serialized<MeasureToolSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<OverlayUIState> OverlayUIState::Create(BoundsToolState& toolState,
|
std::unique_ptr<OverlayUIState> OverlayUIState::Create(BoundsToolState& toolState,
|
||||||
|
Latch& creationLatch,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
const MonitorInfo& monitor)
|
const MonitorInfo& monitor)
|
||||||
{
|
{
|
||||||
return OverlayUIState::CreateInternal(toolState,
|
return OverlayUIState::CreateInternal(toolState,
|
||||||
DrawBoundsToolTick,
|
DrawBoundsToolTick,
|
||||||
commonState,
|
commonState,
|
||||||
|
creationLatch,
|
||||||
NonLocalizable::BoundsToolOverlayWindowName,
|
NonLocalizable::BoundsToolOverlayWindowName,
|
||||||
&toolState,
|
&toolState,
|
||||||
monitor,
|
monitor,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "D2DState.h"
|
#include "D2DState.h"
|
||||||
|
#include "latch.h"
|
||||||
#include "ToolState.h"
|
#include "ToolState.h"
|
||||||
|
|
||||||
#include <common/display/monitors.h>
|
#include <common/display/monitors.h>
|
||||||
@@ -27,6 +28,7 @@ class OverlayUIState final
|
|||||||
static std::unique_ptr<OverlayUIState> CreateInternal(ToolT& toolState,
|
static std::unique_ptr<OverlayUIState> CreateInternal(ToolT& toolState,
|
||||||
TickFuncT tickFunc,
|
TickFuncT tickFunc,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
|
Latch& creationLatch,
|
||||||
const wchar_t* toolWindowClassName,
|
const wchar_t* toolWindowClassName,
|
||||||
void* windowParam,
|
void* windowParam,
|
||||||
const MonitorInfo& monitor,
|
const MonitorInfo& monitor,
|
||||||
@@ -37,9 +39,11 @@ public:
|
|||||||
~OverlayUIState();
|
~OverlayUIState();
|
||||||
|
|
||||||
static std::unique_ptr<OverlayUIState> Create(BoundsToolState& toolState,
|
static std::unique_ptr<OverlayUIState> Create(BoundsToolState& toolState,
|
||||||
|
Latch& creationLatch,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
const MonitorInfo& monitor);
|
const MonitorInfo& monitor);
|
||||||
static std::unique_ptr<OverlayUIState> Create(Serialized<MeasureToolState>& toolState,
|
static std::unique_ptr<OverlayUIState> Create(Serialized<MeasureToolState>& toolState,
|
||||||
|
Latch& creationLatch,
|
||||||
CommonState& commonState,
|
CommonState& commonState,
|
||||||
const MonitorInfo& monitor);
|
const MonitorInfo& monitor);
|
||||||
inline HWND overlayWindowHandle() const
|
inline HWND overlayWindowHandle() const
|
||||||
|
|||||||
@@ -79,11 +79,17 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
|||||||
|
|
||||||
#if defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
#if defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
||||||
const auto& monitorInfo = MonitorInfo::GetPrimaryMonitor();
|
const auto& monitorInfo = MonitorInfo::GetPrimaryMonitor();
|
||||||
|
Latch createOverlayUILatch{ 1 };
|
||||||
#else
|
#else
|
||||||
for (const auto& monitorInfo : MonitorInfo::GetMonitors(true))
|
const auto monitors = MonitorInfo::GetMonitors(true);
|
||||||
|
Latch createOverlayUILatch{ static_cast<ptrdiff_t>(monitors.size()) };
|
||||||
|
for (const auto& monitorInfo : monitors)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
auto overlayUI = OverlayUIState::Create(_boundsToolState, _commonState, monitorInfo);
|
auto overlayUI = OverlayUIState::Create(_boundsToolState,
|
||||||
|
createOverlayUILatch,
|
||||||
|
_commonState,
|
||||||
|
monitorInfo);
|
||||||
#if !defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
#if !defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
||||||
if (!overlayUI)
|
if (!overlayUI)
|
||||||
continue;
|
continue;
|
||||||
@@ -110,22 +116,37 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
|||||||
});
|
});
|
||||||
|
|
||||||
#if defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
#if defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
||||||
const auto& monitorInfo = MonitorInfo::GetPrimaryMonitor();
|
std::vector<MonitorInfo> monitors = { MonitorInfo::GetPrimaryMonitor() };
|
||||||
|
const auto& monitorInfo = monitors[0];
|
||||||
|
Latch createOverlayUILatch{ 1 };
|
||||||
#else
|
#else
|
||||||
for (const auto& monitorInfo : MonitorInfo::GetMonitors(true))
|
const auto monitors = MonitorInfo::GetMonitors(true);
|
||||||
|
Latch createOverlayUILatch{ static_cast<ptrdiff_t>(monitors.size()) };
|
||||||
|
for (const auto& monitorInfo : monitors)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
auto overlayUI = OverlayUIState::Create(_measureToolState, _commonState, monitorInfo);
|
auto overlayUI = OverlayUIState::Create(_measureToolState,
|
||||||
|
createOverlayUILatch,
|
||||||
|
_commonState,
|
||||||
|
monitorInfo);
|
||||||
#if !defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
#if !defined(DEBUG_PRIMARY_MONITOR_ONLY)
|
||||||
if (!overlayUI)
|
if (!overlayUI)
|
||||||
continue;
|
return;
|
||||||
#endif
|
#endif
|
||||||
_screenCaptureThreads.emplace_back(StartCapturingThread(_commonState,
|
|
||||||
_measureToolState,
|
|
||||||
overlayUI->overlayWindowHandle(),
|
|
||||||
monitorInfo));
|
|
||||||
_overlayUIStates.push_back(std::move(overlayUI));
|
_overlayUIStates.push_back(std::move(overlayUI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < monitors.size(); ++i)
|
||||||
|
{
|
||||||
|
auto thread = StartCapturingThread(
|
||||||
|
&_d3dState,
|
||||||
|
_commonState,
|
||||||
|
_measureToolState,
|
||||||
|
_overlayUIStates[i]->overlayWindowHandle(),
|
||||||
|
monitors[i]);
|
||||||
|
_screenCaptureThreads.emplace_back(std::move(thread));
|
||||||
|
}
|
||||||
|
|
||||||
Trace::MeasureToolActivated();
|
Trace::MeasureToolActivated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
|
||||||
#include <common/utils/serialized.h>
|
#include <common/utils/serialized.h>
|
||||||
|
#include "ScreenCapturing.h"
|
||||||
|
|
||||||
namespace winrt::PowerToys::MeasureToolCore::implementation
|
namespace winrt::PowerToys::MeasureToolCore::implementation
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,8 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
|||||||
float GetDPIScaleForWindow(uint64_t windowHandle);
|
float GetDPIScaleForWindow(uint64_t windowHandle);
|
||||||
void MouseCaptureThread();
|
void MouseCaptureThread();
|
||||||
|
|
||||||
|
D3DState _d3dState;
|
||||||
|
|
||||||
wil::shared_event _stopMouseCaptureThreadSignal;
|
wil::shared_event _stopMouseCaptureThreadSignal;
|
||||||
std::thread _mouseCaptureThread;
|
std::thread _mouseCaptureThread;
|
||||||
std::vector<std::thread> _screenCaptureThreads;
|
std::vector<std::thread> _screenCaptureThreads;
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
<ClInclude Include="BGRATextureView.h" />
|
<ClInclude Include="BGRATextureView.h" />
|
||||||
<ClInclude Include="EdgeDetection.h" />
|
<ClInclude Include="EdgeDetection.h" />
|
||||||
<ClInclude Include="ToolState.h" />
|
<ClInclude Include="ToolState.h" />
|
||||||
|
<ClInclude Include="latch.h" />
|
||||||
<ClInclude Include="OverlayUI.h" />
|
<ClInclude Include="OverlayUI.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="ScreenCapturing.h" />
|
<ClInclude Include="ScreenCapturing.h" />
|
||||||
|
|||||||
@@ -10,9 +10,45 @@
|
|||||||
|
|
||||||
//#define DEBUG_EDGES
|
//#define DEBUG_EDGES
|
||||||
|
|
||||||
|
D3DState::D3DState()
|
||||||
|
{
|
||||||
|
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||||
|
#endif
|
||||||
|
HRESULT hr =
|
||||||
|
D3D11CreateDevice(nullptr,
|
||||||
|
D3D_DRIVER_TYPE_HARDWARE,
|
||||||
|
nullptr,
|
||||||
|
flags,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
|
d3dDevice.put(),
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
if (hr == DXGI_ERROR_UNSUPPORTED)
|
||||||
|
{
|
||||||
|
hr = D3D11CreateDevice(nullptr,
|
||||||
|
D3D_DRIVER_TYPE_WARP,
|
||||||
|
nullptr,
|
||||||
|
flags,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
|
d3dDevice.put(),
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
winrt::check_hresult(hr);
|
||||||
|
|
||||||
|
dxgiDevice = d3dDevice.as<IDXGIDevice>();
|
||||||
|
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), d3dDeviceInspectable.put()));
|
||||||
|
}
|
||||||
|
|
||||||
class D3DCaptureState final
|
class D3DCaptureState final
|
||||||
{
|
{
|
||||||
winrt::com_ptr<ID3D11Device> d3dDevice;
|
D3DState* d3dState = nullptr;
|
||||||
winrt::IDirect3DDevice device;
|
winrt::IDirect3DDevice device;
|
||||||
winrt::com_ptr<IDXGISwapChain1> swapChain;
|
winrt::com_ptr<IDXGISwapChain1> swapChain;
|
||||||
winrt::com_ptr<ID3D11DeviceContext> context;
|
winrt::com_ptr<ID3D11DeviceContext> context;
|
||||||
@@ -26,8 +62,7 @@ class D3DCaptureState final
|
|||||||
Box monitorArea;
|
Box monitorArea;
|
||||||
bool captureOutsideOfMonitor = false;
|
bool captureOutsideOfMonitor = false;
|
||||||
|
|
||||||
D3DCaptureState(winrt::com_ptr<ID3D11Device> d3dDevice,
|
D3DCaptureState(D3DState* d3dState,
|
||||||
winrt::IDirect3DDevice _device,
|
|
||||||
winrt::com_ptr<IDXGISwapChain1> _swapChain,
|
winrt::com_ptr<IDXGISwapChain1> _swapChain,
|
||||||
winrt::com_ptr<ID3D11DeviceContext> _context,
|
winrt::com_ptr<ID3D11DeviceContext> _context,
|
||||||
const winrt::GraphicsCaptureItem& item,
|
const winrt::GraphicsCaptureItem& item,
|
||||||
@@ -44,7 +79,8 @@ class D3DCaptureState final
|
|||||||
std::mutex destructorMutex;
|
std::mutex destructorMutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<D3DCaptureState> Create(winrt::GraphicsCaptureItem item,
|
static std::unique_ptr<D3DCaptureState> Create(D3DState* d3dState,
|
||||||
|
winrt::GraphicsCaptureItem item,
|
||||||
const winrt::DirectXPixelFormat pixelFormat,
|
const winrt::DirectXPixelFormat pixelFormat,
|
||||||
Box monitorSize,
|
Box monitorSize,
|
||||||
const bool captureOutsideOfMonitor);
|
const bool captureOutsideOfMonitor);
|
||||||
@@ -57,21 +93,20 @@ public:
|
|||||||
void StopCapture();
|
void StopCapture();
|
||||||
};
|
};
|
||||||
|
|
||||||
D3DCaptureState::D3DCaptureState(winrt::com_ptr<ID3D11Device> _d3dDevice,
|
D3DCaptureState::D3DCaptureState(D3DState* _d3dState,
|
||||||
winrt::IDirect3DDevice _device,
|
|
||||||
winrt::com_ptr<IDXGISwapChain1> _swapChain,
|
winrt::com_ptr<IDXGISwapChain1> _swapChain,
|
||||||
winrt::com_ptr<ID3D11DeviceContext> _context,
|
winrt::com_ptr<ID3D11DeviceContext> _context,
|
||||||
const winrt::GraphicsCaptureItem& item,
|
const winrt::GraphicsCaptureItem& item,
|
||||||
winrt::DirectXPixelFormat _pixelFormat,
|
winrt::DirectXPixelFormat _pixelFormat,
|
||||||
Box _monitorArea,
|
Box _monitorArea,
|
||||||
const bool _captureOutsideOfMonitor) :
|
const bool _captureOutsideOfMonitor) :
|
||||||
d3dDevice{ std::move(_d3dDevice) },
|
d3dState{ _d3dState },
|
||||||
device{ std::move(_device) },
|
device{ _d3dState->d3dDeviceInspectable.as<winrt::IDirect3DDevice>() },
|
||||||
swapChain{ std::move(_swapChain) },
|
swapChain{ std::move(_swapChain) },
|
||||||
context{ std::move(_context) },
|
context{ std::move(_context) },
|
||||||
frameSize{ item.Size() },
|
frameSize{ item.Size() },
|
||||||
pixelFormat{ std::move(_pixelFormat) },
|
pixelFormat{ std::move(_pixelFormat) },
|
||||||
framePool{ winrt::Direct3D11CaptureFramePool::CreateFreeThreaded(device, pixelFormat, 2, item.Size()) },
|
framePool{ winrt::Direct3D11CaptureFramePool::CreateFreeThreaded(device, pixelFormat, 1, item.Size()) },
|
||||||
session{ framePool.CreateCaptureSession(item) },
|
session{ framePool.CreateCaptureSession(item) },
|
||||||
monitorArea{ _monitorArea },
|
monitorArea{ _monitorArea },
|
||||||
captureOutsideOfMonitor{ _captureOutsideOfMonitor }
|
captureOutsideOfMonitor{ _captureOutsideOfMonitor }
|
||||||
@@ -89,7 +124,7 @@ winrt::com_ptr<ID3D11Texture2D> D3DCaptureState::CopyFrameToCPU(const winrt::com
|
|||||||
desc.BindFlags = 0;
|
desc.BindFlags = 0;
|
||||||
|
|
||||||
winrt::com_ptr<ID3D11Texture2D> cpuTexture;
|
winrt::com_ptr<ID3D11Texture2D> cpuTexture;
|
||||||
winrt::check_hresult(d3dDevice->CreateTexture2D(&desc, nullptr, cpuTexture.put()));
|
winrt::check_hresult(d3dState->d3dDevice->CreateTexture2D(&desc, nullptr, cpuTexture.put()));
|
||||||
context->CopyResource(cpuTexture.get(), frameTexture.get());
|
context->CopyResource(cpuTexture.get(), frameTexture.get());
|
||||||
|
|
||||||
return cpuTexture;
|
return cpuTexture;
|
||||||
@@ -152,49 +187,14 @@ void D3DCaptureState::OnFrameArrived(const winrt::Direct3D11CaptureFramePool& se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<D3DCaptureState> D3DCaptureState::Create(winrt::GraphicsCaptureItem item,
|
std::unique_ptr<D3DCaptureState> D3DCaptureState::Create(D3DState* d3dState,
|
||||||
|
winrt::GraphicsCaptureItem item,
|
||||||
const winrt::DirectXPixelFormat pixelFormat,
|
const winrt::DirectXPixelFormat pixelFormat,
|
||||||
Box monitorArea,
|
Box monitorArea,
|
||||||
const bool captureOutsideOfMonitor)
|
const bool captureOutsideOfMonitor)
|
||||||
{
|
{
|
||||||
std::lock_guard guard{ gpuAccessLock };
|
std::lock_guard guard{ gpuAccessLock };
|
||||||
|
|
||||||
winrt::com_ptr<ID3D11Device> d3dDevice;
|
|
||||||
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
|
||||||
#ifndef NDEBUG
|
|
||||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
|
||||||
#endif
|
|
||||||
HRESULT hr =
|
|
||||||
D3D11CreateDevice(nullptr,
|
|
||||||
D3D_DRIVER_TYPE_HARDWARE,
|
|
||||||
nullptr,
|
|
||||||
flags,
|
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
D3D11_SDK_VERSION,
|
|
||||||
d3dDevice.put(),
|
|
||||||
nullptr,
|
|
||||||
nullptr);
|
|
||||||
if (hr == DXGI_ERROR_UNSUPPORTED)
|
|
||||||
{
|
|
||||||
hr = D3D11CreateDevice(nullptr,
|
|
||||||
D3D_DRIVER_TYPE_WARP,
|
|
||||||
nullptr,
|
|
||||||
flags,
|
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
D3D11_SDK_VERSION,
|
|
||||||
d3dDevice.put(),
|
|
||||||
nullptr,
|
|
||||||
nullptr);
|
|
||||||
}
|
|
||||||
winrt::check_hresult(hr);
|
|
||||||
|
|
||||||
|
|
||||||
auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
|
|
||||||
winrt::com_ptr<IInspectable> d3dDeviceInspectable;
|
|
||||||
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), d3dDeviceInspectable.put()));
|
|
||||||
|
|
||||||
const DXGI_SWAP_CHAIN_DESC1 desc = {
|
const DXGI_SWAP_CHAIN_DESC1 desc = {
|
||||||
.Width = static_cast<uint32_t>(item.Size().Width),
|
.Width = static_cast<uint32_t>(item.Size().Width),
|
||||||
.Height = static_cast<uint32_t>(item.Size().Height),
|
.Height = static_cast<uint32_t>(item.Size().Height),
|
||||||
@@ -207,20 +207,21 @@ std::unique_ptr<D3DCaptureState> D3DCaptureState::Create(winrt::GraphicsCaptureI
|
|||||||
.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED,
|
.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED,
|
||||||
};
|
};
|
||||||
winrt::com_ptr<IDXGIAdapter> adapter;
|
winrt::com_ptr<IDXGIAdapter> adapter;
|
||||||
winrt::check_hresult(dxgiDevice->GetParent(winrt::guid_of<IDXGIAdapter>(), adapter.put_void()));
|
winrt::check_hresult(d3dState->dxgiDevice->GetParent(winrt::guid_of<IDXGIAdapter>(), adapter.put_void()));
|
||||||
winrt::com_ptr<IDXGIFactory2> factory;
|
winrt::com_ptr<IDXGIFactory2> factory;
|
||||||
winrt::check_hresult(adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), factory.put_void()));
|
winrt::check_hresult(adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), factory.put_void()));
|
||||||
|
|
||||||
winrt::com_ptr<IDXGISwapChain1> swapChain;
|
winrt::com_ptr<IDXGISwapChain1> swapChain;
|
||||||
winrt::check_hresult(factory->CreateSwapChainForComposition(d3dDevice.get(), &desc, nullptr, swapChain.put()));
|
winrt::check_hresult(factory->CreateSwapChainForComposition(d3dState->d3dDevice.get(), &desc, nullptr, swapChain.put()));
|
||||||
|
|
||||||
winrt::com_ptr<ID3D11DeviceContext> context;
|
winrt::com_ptr<ID3D11DeviceContext> context;
|
||||||
d3dDevice->GetImmediateContext(context.put());
|
d3dState->d3dDevice->GetImmediateContext(context.put());
|
||||||
winrt::check_bool(context);
|
winrt::check_bool(context);
|
||||||
|
auto contextMultithread = context.as<ID3D11Multithread>();
|
||||||
|
contextMultithread->SetMultithreadProtected(true);
|
||||||
|
|
||||||
// We must create the object in a heap, since we need to pin it in memory to receive callbacks
|
// We must create the object in a heap, since we need to pin it in memory to receive callbacks
|
||||||
auto statePtr = new D3DCaptureState{ d3dDevice,
|
auto statePtr = new D3DCaptureState{ d3dState,
|
||||||
d3dDeviceInspectable.as<winrt::IDirect3DDevice>(),
|
|
||||||
std::move(swapChain),
|
std::move(swapChain),
|
||||||
std::move(context),
|
std::move(context),
|
||||||
item,
|
item,
|
||||||
@@ -236,7 +237,6 @@ D3DCaptureState::~D3DCaptureState()
|
|||||||
std::unique_lock callbackLock{ destructorMutex };
|
std::unique_lock callbackLock{ destructorMutex };
|
||||||
StopCapture();
|
StopCapture();
|
||||||
framePool.Close();
|
framePool.Close();
|
||||||
device.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3DCaptureState::StartSessionInPreferredMode()
|
void D3DCaptureState::StartSessionInPreferredMode()
|
||||||
@@ -332,12 +332,13 @@ void UpdateCaptureState(const CommonState& commonState,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread StartCapturingThread(const CommonState& commonState,
|
std::thread StartCapturingThread(D3DState* d3dState,
|
||||||
|
const CommonState& commonState,
|
||||||
Serialized<MeasureToolState>& state,
|
Serialized<MeasureToolState>& state,
|
||||||
HWND window,
|
HWND window,
|
||||||
MonitorInfo targetMonitor)
|
MonitorInfo monitor)
|
||||||
{
|
{
|
||||||
return SpawnLoggedThread(L"Screen Capture thread", [&state, &commonState, targetMonitor, window] {
|
return SpawnLoggedThread(L"Screen Capture thread", [&state, &commonState, monitor, window, d3dState] {
|
||||||
auto captureInterop = winrt::get_activation_factory<
|
auto captureInterop = winrt::get_activation_factory<
|
||||||
winrt::GraphicsCaptureItem,
|
winrt::GraphicsCaptureItem,
|
||||||
IGraphicsCaptureItemInterop>();
|
IGraphicsCaptureItemInterop>();
|
||||||
@@ -345,7 +346,7 @@ std::thread StartCapturingThread(const CommonState& commonState,
|
|||||||
winrt::GraphicsCaptureItem item = nullptr;
|
winrt::GraphicsCaptureItem item = nullptr;
|
||||||
|
|
||||||
winrt::check_hresult(captureInterop->CreateForMonitor(
|
winrt::check_hresult(captureInterop->CreateForMonitor(
|
||||||
targetMonitor.GetHandle(),
|
monitor.GetHandle(),
|
||||||
winrt::guid_of<winrt::GraphicsCaptureItem>(),
|
winrt::guid_of<winrt::GraphicsCaptureItem>(),
|
||||||
winrt::put_abi(item)));
|
winrt::put_abi(item)));
|
||||||
|
|
||||||
@@ -354,8 +355,9 @@ std::thread StartCapturingThread(const CommonState& commonState,
|
|||||||
continuousCapture = state.global.continuousCapture;
|
continuousCapture = state.global.continuousCapture;
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto monitorArea = targetMonitor.GetScreenSize(true);
|
const auto monitorArea = monitor.GetScreenSize(true);
|
||||||
auto captureState = D3DCaptureState::Create(item,
|
auto captureState = D3DCaptureState::Create(d3dState,
|
||||||
|
item,
|
||||||
winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
||||||
monitorArea,
|
monitorArea,
|
||||||
!continuousCapture);
|
!continuousCapture);
|
||||||
|
|||||||
@@ -4,7 +4,17 @@
|
|||||||
|
|
||||||
#include <common/utils/serialized.h>
|
#include <common/utils/serialized.h>
|
||||||
|
|
||||||
std::thread StartCapturingThread(const CommonState& commonState,
|
struct D3DState
|
||||||
|
{
|
||||||
|
winrt::com_ptr<ID3D11Device> d3dDevice;
|
||||||
|
winrt::com_ptr<IDXGIDevice> dxgiDevice;
|
||||||
|
winrt::com_ptr<IInspectable> d3dDeviceInspectable;
|
||||||
|
|
||||||
|
D3DState();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread StartCapturingThread(D3DState* d3dState,
|
||||||
|
const CommonState& commonState,
|
||||||
Serialized<MeasureToolState>& state,
|
Serialized<MeasureToolState>& state,
|
||||||
HWND targetWindow,
|
HWND targetWindow,
|
||||||
MonitorInfo targetMonitor);
|
MonitorInfo targetMonitor);
|
||||||
73
src/modules/MeasureTool/MeasureToolCore/latch.h
Normal file
73
src/modules/MeasureTool/MeasureToolCore/latch.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __has_include(<latch>)
|
||||||
|
#include <latch>
|
||||||
|
using Latch = std::latch;
|
||||||
|
#else
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
class Latch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static constexpr ptrdiff_t(max)() noexcept
|
||||||
|
{
|
||||||
|
return (1ULL << (sizeof(ptrdiff_t) * CHAR_BIT - 1)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr explicit Latch(const std::ptrdiff_t _Expected) noexcept :
|
||||||
|
_Counter{ _Expected }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Latch(const Latch&) = delete;
|
||||||
|
Latch& operator=(const Latch&) = delete;
|
||||||
|
|
||||||
|
void count_down(const ptrdiff_t _Update = 1) noexcept
|
||||||
|
{
|
||||||
|
const ptrdiff_t _Current = _Counter.fetch_sub(_Update) - _Update;
|
||||||
|
if (_Current == 0)
|
||||||
|
{
|
||||||
|
_Counter.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool try_wait() const noexcept
|
||||||
|
{
|
||||||
|
return _Counter.load() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait() const noexcept
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const ptrdiff_t _Current = _Counter.load();
|
||||||
|
if (_Current == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_Counter.wait(_Current, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void arrive_and_wait(const ptrdiff_t _Update = 1) noexcept
|
||||||
|
{
|
||||||
|
const ptrdiff_t _Current = _Counter.fetch_sub(_Update) - _Update;
|
||||||
|
if (_Current == 0)
|
||||||
|
{
|
||||||
|
_Counter.notify_all();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_Counter.wait(_Current, std::memory_order_relaxed);
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<std::ptrdiff_t> _Counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
<value>Draw feet on cross</value>
|
<value>Draw feet on cross</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MeasureTool_DrawFeetOnCross.Description" xml:space="preserve">
|
<data name="MeasureTool_DrawFeetOnCross.Description" xml:space="preserve">
|
||||||
<value>Adds feet to the end of cross lines. Always off for continuous capture.</value>
|
<value>Adds feet to the end of cross lines.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MeasureTool_EnableMeasureTool.Header" xml:space="preserve">
|
<data name="MeasureTool_EnableMeasureTool.Header" xml:space="preserve">
|
||||||
<value>Enable Screen Ruler</value>
|
<value>Enable Screen Ruler</value>
|
||||||
@@ -2374,7 +2374,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
|||||||
<value>Learn more about conflicting activation commands</value>
|
<value>Learn more about conflicting activation commands</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MeasureTool_ContinuousCapture_Information.Title" xml:space="preserve">
|
<data name="MeasureTool_ContinuousCapture_Information.Title" xml:space="preserve">
|
||||||
<value>The continuous capture mode will consume more resources when in use. In addition, the UI will be slightly offset from the pointer position.</value>
|
<value>The continuous capture mode will consume more resources when in use.</value>
|
||||||
<comment>pointer as in mouse pointer. resources refer to things like CPU, GPU, RAM</comment>
|
<comment>pointer as in mouse pointer. Resources refer to things like CPU, GPU, RAM</comment>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Reference in New Issue
Block a user