[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:
Andrey Nekrasov
2022-08-31 17:43:32 +03:00
committed by GitHub
parent 76ebed0897
commit c7d1465946
13 changed files with 207 additions and 103 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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);

View File

@@ -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,13 +137,8 @@ void OverlayUIState::RunUILoop()
else else
_d2dState.rt->Clear(); _d2dState.rt->Clear();
{
// 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(); _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,

View File

@@ -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

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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);

View 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

View File

@@ -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>