mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
[Screen Ruler] optimize d3d -> d2d texture copying + other fixes (#20138)
* [Screen Ruler] optimize d3d -> d2d texture copying + other fixes * [Screen Ruler] hide cursor when using the bounds tool
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#endif
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <d3d11.h>
|
||||
|
||||
|
||||
//#define DEBUG_TEXTURE
|
||||
|
||||
@@ -125,3 +127,43 @@ struct BGRATextureView
|
||||
void SaveAsBitmap(const char* filename) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
class MappedTextureView
|
||||
{
|
||||
winrt::com_ptr<ID3D11DeviceContext> context;
|
||||
winrt::com_ptr<ID3D11Texture2D> texture;
|
||||
|
||||
public:
|
||||
BGRATextureView view;
|
||||
MappedTextureView(winrt::com_ptr<ID3D11Texture2D> _texture,
|
||||
winrt::com_ptr<ID3D11DeviceContext> _context,
|
||||
const size_t textureWidth,
|
||||
const size_t textureHeight) :
|
||||
texture{ std::move(_texture) }, context{ std::move(_context) }
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE resource = {};
|
||||
winrt::check_hresult(context->Map(texture.get(), D3D11CalcSubresource(0, 0, 0), D3D11_MAP_READ, 0, &resource));
|
||||
|
||||
view.pixels = static_cast<const uint32_t*>(resource.pData);
|
||||
view.pitch = resource.RowPitch / 4;
|
||||
view.width = textureWidth;
|
||||
view.height = textureHeight;
|
||||
}
|
||||
|
||||
MappedTextureView(MappedTextureView&&) = default;
|
||||
MappedTextureView& operator=(MappedTextureView&&) = default;
|
||||
|
||||
inline winrt::com_ptr<ID3D11Texture2D> GetTexture() const
|
||||
{
|
||||
return texture;
|
||||
}
|
||||
|
||||
~MappedTextureView()
|
||||
{
|
||||
if (context && texture)
|
||||
context->Unmap(texture.get(), D3D11CalcSubresource(0, 0, 0));
|
||||
}
|
||||
};
|
||||
@@ -25,6 +25,8 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
for (; ShowCursor(false) >= 0;)
|
||||
;
|
||||
auto toolState = GetWindowParam<BoundsToolState*>(window);
|
||||
if (!toolState)
|
||||
break;
|
||||
@@ -36,6 +38,9 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA
|
||||
}
|
||||
case WM_CURSOR_LEFT_MONITOR:
|
||||
{
|
||||
for (; ShowCursor(true) < 0;)
|
||||
;
|
||||
|
||||
auto toolState = GetWindowParam<BoundsToolState*>(window);
|
||||
if (!toolState)
|
||||
break;
|
||||
@@ -44,6 +49,9 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
for (; ShowCursor(true) < 0;)
|
||||
;
|
||||
|
||||
auto toolState = GetWindowParam<BoundsToolState*>(window);
|
||||
if (!toolState || !toolState->perScreen[window].currentRegionStart)
|
||||
break;
|
||||
@@ -67,6 +75,9 @@ LRESULT CALLBACK BoundsToolWndProc(HWND window, UINT message, WPARAM wparam, LPA
|
||||
}
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
for (; ShowCursor(true) < 0;)
|
||||
;
|
||||
|
||||
auto toolState = GetWindowParam<BoundsToolState*>(window);
|
||||
if (!toolState)
|
||||
break;
|
||||
|
||||
@@ -36,33 +36,23 @@ namespace
|
||||
}
|
||||
|
||||
winrt::com_ptr<ID2D1Bitmap> ConvertID3D11Texture2DToD2D1Bitmap(wil::com_ptr<ID2D1HwndRenderTarget> rt,
|
||||
winrt::com_ptr<ID3D11Texture2D> texture)
|
||||
const MappedTextureView* capturedScreenTexture)
|
||||
{
|
||||
std::lock_guard guard{ gpuAccessLock };
|
||||
|
||||
auto dxgiSurface = texture.try_as<IDXGISurface>();
|
||||
if (!dxgiSurface)
|
||||
return nullptr;
|
||||
|
||||
DXGI_MAPPED_RECT bitmap2Dmap = {};
|
||||
HRESULT hr = dxgiSurface->Map(&bitmap2Dmap, DXGI_MAP_READ);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
capturedScreenTexture->view.pixels;
|
||||
|
||||
D2D1_BITMAP_PROPERTIES props = { .pixelFormat = rt->GetPixelFormat() };
|
||||
rt->GetDpi(&props.dpiX, &props.dpiY);
|
||||
const auto sizeF = rt->GetSize();
|
||||
winrt::com_ptr<ID2D1Bitmap> bitmap;
|
||||
if (FAILED(rt->CreateBitmap(D2D1::SizeU(static_cast<uint32_t>(sizeF.width),
|
||||
static_cast<uint32_t>(sizeF.height)),
|
||||
bitmap2Dmap.pBits,
|
||||
bitmap2Dmap.Pitch,
|
||||
auto hr = rt->CreateBitmap(D2D1::SizeU(static_cast<uint32_t>(capturedScreenTexture->view.width),
|
||||
static_cast<uint32_t>(capturedScreenTexture->view.height)),
|
||||
capturedScreenTexture->view.pixels,
|
||||
static_cast<uint32_t>(capturedScreenTexture->view.pitch * 4),
|
||||
props,
|
||||
bitmap.put())))
|
||||
return nullptr;
|
||||
if (FAILED(dxgiSurface->Unmap()))
|
||||
bitmap.put());
|
||||
if (FAILED(hr))
|
||||
return nullptr;
|
||||
|
||||
return bitmap;
|
||||
@@ -90,7 +80,7 @@ LRESULT CALLBACK MeasureToolWndProc(HWND window, UINT message, WPARAM wparam, LP
|
||||
StoreWindowParam(window, state);
|
||||
|
||||
#if !defined(DEBUG_OVERLAY)
|
||||
for (; ShowCursor(false) > 0;)
|
||||
for (; ShowCursor(false) >= 0;)
|
||||
;
|
||||
#endif
|
||||
break;
|
||||
@@ -142,7 +132,7 @@ void DrawMeasureToolTick(const CommonState& commonState,
|
||||
RECT measuredEdges{};
|
||||
MeasureToolState::Mode mode = {};
|
||||
winrt::com_ptr<ID2D1Bitmap> backgroundBitmap;
|
||||
winrt::com_ptr<ID3D11Texture2D> backgroundTextureToConvert;
|
||||
const MappedTextureView* backgroundTextureToConvert = nullptr;
|
||||
|
||||
toolState.Read([&](const MeasureToolState& state) {
|
||||
continuousCapture = state.global.continuousCapture;
|
||||
|
||||
@@ -39,7 +39,12 @@ HWND CreateOverlayUIWindow(const CommonState& commonState,
|
||||
std::call_once(windowClassesCreatedFlag, CreateOverlayWindowClasses);
|
||||
|
||||
const auto screenArea = monitor.GetScreenSize(true);
|
||||
HWND window{ CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
|
||||
DWORD windowStyle = WS_EX_TOOLWINDOW;
|
||||
#if !defined(DEBUG_OVERLAY)
|
||||
windowStyle |= WS_EX_TOPMOST;
|
||||
#endif
|
||||
HWND window{
|
||||
CreateWindowExW(windowStyle,
|
||||
windowClass,
|
||||
L"PowerToys.MeasureToolOverlay",
|
||||
WS_POPUP,
|
||||
@@ -50,7 +55,8 @@ HWND CreateOverlayUIWindow(const CommonState& commonState,
|
||||
HWND_DESKTOP,
|
||||
nullptr,
|
||||
GetModuleHandleW(nullptr),
|
||||
extraParam) };
|
||||
extraParam)
|
||||
};
|
||||
winrt::check_bool(window);
|
||||
ShowWindow(window, SW_SHOWNORMAL);
|
||||
#if !defined(DEBUG_OVERLAY)
|
||||
|
||||
@@ -6,9 +6,9 @@ PerGlyphOpacityTextRender::PerGlyphOpacityTextRender(
|
||||
wil::com_ptr<ID2D1Factory> pD2DFactory,
|
||||
wil::com_ptr<ID2D1HwndRenderTarget> rt,
|
||||
wil::com_ptr<ID2D1SolidColorBrush> baseBrush) :
|
||||
_pD2DFactory{ pD2DFactory },
|
||||
_rt{ rt },
|
||||
_baseBrush{ baseBrush }
|
||||
_pD2DFactory{ pD2DFactory.get() },
|
||||
_rt{ rt.get() },
|
||||
_baseBrush{ baseBrush.get() }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -18,20 +18,22 @@ HRESULT __stdcall PerGlyphOpacityTextRender::DrawGlyphRun(void* /*clientDrawingC
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
_In_ const DWRITE_GLYPH_RUN* glyphRun,
|
||||
_In_ const DWRITE_GLYPH_RUN_DESCRIPTION* /*glyphRunDescription*/,
|
||||
IUnknown* clientDrawingEffect) noexcept
|
||||
IUnknown* clientDrawingEffect_) noexcept
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (!clientDrawingEffect)
|
||||
if (!clientDrawingEffect_)
|
||||
{
|
||||
_rt->DrawGlyphRun(D2D1_POINT_2F{ .x = baselineOriginX, .y = baselineOriginY }, glyphRun, _baseBrush.get(), measuringMode);
|
||||
_rt->DrawGlyphRun(D2D1_POINT_2F{ .x = baselineOriginX, .y = baselineOriginY }, glyphRun, _baseBrush, measuringMode);
|
||||
return hr;
|
||||
}
|
||||
wil::com_ptr<IUnknown> clientDrawingEffect{ clientDrawingEffect_ };
|
||||
|
||||
// Create the path geometry.
|
||||
wil::com_ptr<ID2D1PathGeometry> pathGeometry;
|
||||
hr = _pD2DFactory->CreatePathGeometry(&pathGeometry);
|
||||
|
||||
// Write to the path geometry using the geometry sink.
|
||||
ID2D1GeometrySink* pSink = nullptr;
|
||||
wil::com_ptr<ID2D1GeometrySink> pSink;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pathGeometry->Open(&pSink);
|
||||
@@ -49,11 +51,10 @@ HRESULT __stdcall PerGlyphOpacityTextRender::DrawGlyphRun(void* /*clientDrawingC
|
||||
glyphRun->glyphCount,
|
||||
glyphRun->isSideways,
|
||||
glyphRun->bidiLevel % 2,
|
||||
pSink);
|
||||
pSink.get());
|
||||
}
|
||||
|
||||
// Close the geometry sink
|
||||
if (SUCCEEDED(hr))
|
||||
if (pSink)
|
||||
{
|
||||
hr = pSink->Close();
|
||||
}
|
||||
@@ -70,21 +71,15 @@ HRESULT __stdcall PerGlyphOpacityTextRender::DrawGlyphRun(void* /*clientDrawingC
|
||||
}
|
||||
|
||||
float prevOpacity = _baseBrush->GetOpacity();
|
||||
OpacityEffect* opacityEffect = nullptr;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = clientDrawingEffect->QueryInterface(__uuidof(IDrawingEffect), reinterpret_cast<void**>(&opacityEffect));
|
||||
}
|
||||
auto opacityEffect = clientDrawingEffect.try_query<IDrawingEffect>();
|
||||
|
||||
if (opacityEffect)
|
||||
_baseBrush->SetOpacity(static_cast<OpacityEffect*>(opacityEffect.get())->alpha);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_baseBrush->SetOpacity(opacityEffect->alpha);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_rt->DrawGeometry(pTransformedGeometry.get(), _baseBrush.get());
|
||||
_rt->FillGeometry(pTransformedGeometry.get(), _baseBrush.get());
|
||||
_rt->DrawGeometry(pTransformedGeometry.get(), _baseBrush);
|
||||
_rt->FillGeometry(pTransformedGeometry.get(), _baseBrush);
|
||||
_baseBrush->SetOpacity(prevOpacity);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ struct OpacityEffect : winrt::implements<OpacityEffect, IDrawingEffect>
|
||||
|
||||
struct PerGlyphOpacityTextRender : winrt::implements<PerGlyphOpacityTextRender, IDWriteTextRenderer>
|
||||
{
|
||||
wil::com_ptr<ID2D1Factory> _pD2DFactory;
|
||||
wil::com_ptr<ID2D1HwndRenderTarget> _rt;
|
||||
wil::com_ptr<ID2D1SolidColorBrush> _baseBrush;
|
||||
ID2D1Factory * _pD2DFactory = nullptr;
|
||||
ID2D1HwndRenderTarget* _rt = nullptr;
|
||||
ID2D1SolidColorBrush* _baseBrush = nullptr;
|
||||
|
||||
PerGlyphOpacityTextRender(
|
||||
wil::com_ptr<ID2D1Factory> pD2DFactory,
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
||||
}
|
||||
|
||||
Core::Core() :
|
||||
_mouseCaptureThread{ [this] { MouseCaptureThread(); } },
|
||||
_stopMouseCaptureThreadSignal{ wil::EventOptions::ManualReset }
|
||||
_stopMouseCaptureThreadSignal{ wil::EventOptions::ManualReset },
|
||||
_mouseCaptureThread{ [this] { MouseCaptureThread(); } }
|
||||
{
|
||||
Trace::RegisterProvider();
|
||||
LoggerHelpers::init_logger(L"Measure Tool", L"Core", "Measure Tool");
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
||||
float GetDPIScaleForWindow(uint64_t windowHandle);
|
||||
void MouseCaptureThread();
|
||||
|
||||
wil::shared_event _stopMouseCaptureThreadSignal;
|
||||
std::thread _mouseCaptureThread;
|
||||
std::vector<std::thread> _screenCaptureThreads;
|
||||
wil::shared_event _stopMouseCaptureThreadSignal;
|
||||
|
||||
std::vector<std::unique_ptr<OverlayUIState>> _overlayUIStates;
|
||||
Serialized<MeasureToolState> _measureToolState;
|
||||
|
||||
@@ -10,46 +10,6 @@
|
||||
|
||||
//#define DEBUG_EDGES
|
||||
|
||||
class MappedTextureView
|
||||
{
|
||||
winrt::com_ptr<ID3D11DeviceContext> context;
|
||||
winrt::com_ptr<ID3D11Texture2D> texture;
|
||||
|
||||
public:
|
||||
BGRATextureView view;
|
||||
MappedTextureView(winrt::com_ptr<ID3D11Texture2D> _texture,
|
||||
winrt::com_ptr<ID3D11DeviceContext> _context,
|
||||
const size_t textureWidth,
|
||||
const size_t textureHeight) :
|
||||
texture{ std::move(_texture) }, context{ std::move(_context) }
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE resource = {};
|
||||
winrt::check_hresult(context->Map(texture.get(), D3D11CalcSubresource(0, 0, 0), D3D11_MAP_READ, 0, &resource));
|
||||
|
||||
view.pixels = static_cast<const uint32_t*>(resource.pData);
|
||||
view.pitch = resource.RowPitch / 4;
|
||||
view.width = textureWidth;
|
||||
view.height = textureHeight;
|
||||
}
|
||||
|
||||
MappedTextureView(MappedTextureView&&) = default;
|
||||
MappedTextureView& operator=(MappedTextureView&&) = default;
|
||||
|
||||
inline winrt::com_ptr<ID3D11Texture2D> GetTexture() const
|
||||
{
|
||||
return texture;
|
||||
}
|
||||
|
||||
~MappedTextureView()
|
||||
{
|
||||
if (context && texture)
|
||||
context->Unmap(texture.get(), D3D11CalcSubresource(0, 0, 0));
|
||||
}
|
||||
};
|
||||
|
||||
class D3DCaptureState final
|
||||
{
|
||||
winrt::com_ptr<ID3D11Device> d3dDevice;
|
||||
@@ -171,8 +131,10 @@ void D3DCaptureState::OnFrameArrived(const winrt::Direct3D11CaptureFramePool& se
|
||||
}
|
||||
|
||||
winrt::check_hresult(swapChain->GetBuffer(0, winrt::guid_of<ID3D11Texture2D>(), texture.put_void()));
|
||||
auto gpuTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||
auto surface = frame.Surface();
|
||||
auto gpuTexture = GetDXGIInterfaceFromObject<ID3D11Texture2D>(surface);
|
||||
texture = CopyFrameToCPU(gpuTexture);
|
||||
surface.Close();
|
||||
MappedTextureView textureView{ texture, context, static_cast<size_t>(frameSize.Width), static_cast<size_t>(frameSize.Height) };
|
||||
|
||||
frameCallback(std::move(textureView));
|
||||
@@ -228,6 +190,7 @@ std::unique_ptr<D3DCaptureState> D3DCaptureState::Create(winrt::GraphicsCaptureI
|
||||
}
|
||||
winrt::check_hresult(hr);
|
||||
|
||||
|
||||
auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
|
||||
winrt::com_ptr<IInspectable> d3dDeviceInspectable;
|
||||
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), d3dDeviceInspectable.put()));
|
||||
@@ -413,7 +376,7 @@ std::thread StartCapturingThread(const CommonState& commonState,
|
||||
const auto textureView = captureState->CaptureSingleFrame();
|
||||
|
||||
state.Access([&](MeasureToolState& s) {
|
||||
s.perScreen[window].capturedScreenTexture = textureView.GetTexture();
|
||||
s.perScreen[window].capturedScreenTexture = &textureView;
|
||||
});
|
||||
|
||||
while (IsWindow(window) && !commonState.closeOnOtherMonitors)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <common/utils/serialized.h>
|
||||
|
||||
//#define DEBUG_OVERLAY
|
||||
#include "BGRATextureView.h"
|
||||
|
||||
struct OverlayBoxText
|
||||
{
|
||||
@@ -69,7 +70,7 @@ struct MeasureToolState
|
||||
RECT measuredEdges = {};
|
||||
// While not in a continuous capturing mode, we need to draw captured backgrounds. These are passed
|
||||
// directly from a capturing thread.
|
||||
winrt::com_ptr<ID3D11Texture2D> capturedScreenTexture;
|
||||
const MappedTextureView* capturedScreenTexture = nullptr;
|
||||
// After the drawing thread finds its capturedScreenTexture, it converts it to
|
||||
// a Direct2D compatible bitmap and caches it here
|
||||
winrt::com_ptr<ID2D1Bitmap> capturedScreenBitmap;
|
||||
|
||||
Reference in New Issue
Block a user