Skip to content

Commit 34bd6b9

Browse files
committed
feat: 实现绘制光标 (p6)
1 parent 79cfb58 commit 34bd6b9

File tree

12 files changed

+342
-113
lines changed

12 files changed

+342
-113
lines changed

src/Magpie.Core/CatmullRomDrawer.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,35 +80,35 @@ HRESULT CatmullRomDrawer::Draw(
8080
ID3D12GraphicsCommandList* commandList = _graphicsContext->GetCommandList();
8181

8282
if (outputSrgb) {
83-
if (!_srgbPipelineState) {
83+
if (!_srgbPSO) {
8484
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {
8585
.pRootSignature = _rootSignature.get(),
8686
.CS = CD3DX12_SHADER_BYTECODE(CatmullRomCS_sRGB, sizeof(CatmullRomCS_sRGB))
8787
};
8888
HRESULT hr = _graphicsContext->GetDevice()->CreateComputePipelineState(
89-
&psoDesc, IID_PPV_ARGS(&_srgbPipelineState));
89+
&psoDesc, IID_PPV_ARGS(&_srgbPSO));
9090
if (FAILED(hr)) {
9191
Logger::Get().ComError("CreateComputePipelineState 失败", hr);
9292
return hr;
9393
}
9494
}
9595

96-
commandList->SetPipelineState(_srgbPipelineState.get());
96+
commandList->SetPipelineState(_srgbPSO.get());
9797
} else {
98-
if (!_linearPipelineState) {
98+
if (!_linearPSO) {
9999
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {
100100
.pRootSignature = _rootSignature.get(),
101101
.CS = CD3DX12_SHADER_BYTECODE(CatmullRomCS, sizeof(CatmullRomCS))
102102
};
103103
HRESULT hr = _graphicsContext->GetDevice()->CreateComputePipelineState(
104-
&psoDesc, IID_PPV_ARGS(&_linearPipelineState));
104+
&psoDesc, IID_PPV_ARGS(&_linearPSO));
105105
if (FAILED(hr)) {
106106
Logger::Get().ComError("CreateComputePipelineState 失败", hr);
107107
return hr;
108108
}
109109
}
110110

111-
commandList->SetPipelineState(_linearPipelineState.get());
111+
commandList->SetPipelineState(_linearPSO.get());
112112
}
113113

114114
commandList->SetComputeRootSignature(_rootSignature.get());

src/Magpie.Core/CatmullRomDrawer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class CatmullRomDrawer {
2020
GraphicsContext* _graphicsContext = nullptr;
2121

2222
winrt::com_ptr<ID3D12RootSignature> _rootSignature;
23-
winrt::com_ptr<ID3D12PipelineState> _linearPipelineState;
24-
winrt::com_ptr<ID3D12PipelineState> _srgbPipelineState;
23+
winrt::com_ptr<ID3D12PipelineState> _linearPSO;
24+
winrt::com_ptr<ID3D12PipelineState> _srgbPSO;
2525
};
2626

2727
}

src/Magpie.Core/CursorDrawer2.cpp

Lines changed: 203 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#include "pch.h"
22
#include "CursorDrawer2.h"
3+
#include "ByteBuffer.h"
34
#include "CursorHelper.h"
5+
#include "DynamicDescriptorHeap.h"
6+
#include "GraphicsContext.h"
7+
#include "Logger.h"
48
#include "ScalingWindow.h"
9+
#include "shaders/CursorVS.h"
10+
#include "shaders/SimplePS.h"
511
#include "Win32Helper.h"
6-
#include "Logger.h"
7-
#include "ByteBuffer.h"
8-
#include "GraphicsContext.h"
912
#include <ShellScalingApi.h>
1013
#include <wil/registry.h>
1114

@@ -46,9 +49,25 @@ static DWORD GetCursorBaseSize() noexcept {
4649
return cursorBaseSize;
4750
}
4851

49-
bool CursorDrawer2::Initialize(GraphicsContext& graphicsContext, const RECT& destRect) noexcept {
52+
CursorDrawer2::~CursorDrawer2() noexcept {
53+
#ifdef _DEBUG
54+
auto& dynamicDescriptorHeap = _graphicsContext->GetDynamicDescriptorHeap();
55+
for (const auto& pair : _cursorInfos) {
56+
dynamicDescriptorHeap.Free(pair.second._textureSrvIdx, 1);
57+
}
58+
#endif
59+
}
60+
61+
bool CursorDrawer2::Initialize(
62+
GraphicsContext& graphicsContext,
63+
const RECT& rendererRect,
64+
const RECT& destRect,
65+
const ColorInfo& colorInfo
66+
) noexcept {
5067
_graphicsContext = &graphicsContext;
68+
_rendererRect = rendererRect;
5169
_destRect = destRect;
70+
_colorInfo = colorInfo;
5271

5372
[[maybe_unused]] static Ignore _ = [] {
5473
GetCursorFrameInfo = Win32Helper::LoadFunction<FnGetCursorFrameInfo>(
@@ -95,6 +114,12 @@ bool CursorDrawer2::Initialize(GraphicsContext& graphicsContext, const RECT& des
95114

96115
_cursorBaseSize = GetCursorBaseSize();
97116

117+
HRESULT hr = _CreateRootSignature();
118+
if (FAILED(hr)) {
119+
Logger::Get().ComError("_CreateRootSignature 失败", hr);
120+
return false;
121+
}
122+
98123
return true;
99124
}
100125

@@ -130,17 +155,13 @@ bool CursorDrawer2::CheckForRedraw(HCURSOR hCursor, POINT cursorPos) noexcept {
130155
if (hCursor) {
131156
if (_isCursorVisible) {
132157
// 检查光标是否在视口内
133-
const _CursorInfo* cursorInfo = _ResolveCursor(hCursor, cursorPos, false);
134-
if (cursorInfo) {
135-
const POINT drawPos = {
136-
cursorPos.x - (LONG)cursorInfo->hotspot.x,
137-
cursorPos.y - (LONG)cursorInfo->hotspot.y
138-
};
158+
_curCursorInfo = _ResolveCursor(hCursor, cursorPos, false);
159+
if (_curCursorInfo) {
139160
const RECT cursorRect = {
140-
drawPos.x,
141-
drawPos.y,
142-
drawPos.x + (LONG)cursorInfo->size.width,
143-
drawPos.y + (LONG)cursorInfo->size.height
161+
cursorPos.x - (LONG)_curCursorInfo->hotspot.x,
162+
cursorPos.y - (LONG)_curCursorInfo->hotspot.y,
163+
cursorRect.left + (LONG)_curCursorInfo->size.width,
164+
cursorRect.top + (LONG)_curCursorInfo->size.height
144165
};
145166
if (!Win32Helper::IsRectOverlap(cursorRect, _destRect)) {
146167
hCursor = NULL;
@@ -165,24 +186,82 @@ bool CursorDrawer2::CheckForRedraw(HCURSOR hCursor, POINT cursorPos) noexcept {
165186
}
166187
}
167188

168-
HRESULT CursorDrawer2::Draw() noexcept {
169-
if (!_hCurCursor) {
189+
HRESULT CursorDrawer2::Draw(D3D12_GPU_DESCRIPTOR_HANDLE heapGpuHandle) noexcept {
190+
if (!_hCurCursor || !_curCursorInfo) {
170191
return S_OK;
171192
}
172193

173-
_CursorInfo* cursorInfo = _ResolveCursor(_hCurCursor, _curCursorPos, false);
174-
if (!cursorInfo) {
175-
assert(false);
176-
return S_OK;
194+
if (!_curCursorInfo->texture) {
195+
HRESULT hr = _InitializeCursorTexture(*_curCursorInfo);
196+
if (FAILED(hr)) {
197+
return hr;
198+
}
177199
}
178200

179-
if (!cursorInfo->texture) {
180-
HRESULT hr = _InitializeCursorTexture(*cursorInfo);
201+
const RECT cursorRect = {
202+
.left = _curCursorPos.x - (LONG)_curCursorInfo->hotspot.x,
203+
.top = _curCursorPos.y - (LONG)_curCursorInfo->hotspot.y,
204+
.right = cursorRect.left + (LONG)_curCursorInfo->size.width,
205+
.bottom = cursorRect.top + (LONG)_curCursorInfo->size.height
206+
};
207+
208+
ID3D12GraphicsCommandList* commandList = _graphicsContext->GetCommandList();
209+
210+
//if (_curCursorInfo->type == _CursorType::Color) {
211+
if (!_colorPSO) {
212+
HRESULT hr = _CreateColorPSO();
181213
if (FAILED(hr)) {
214+
Logger::Get().ComError("_CreateColorPSO 失败", hr);
182215
return hr;
183216
}
184217
}
185218

219+
commandList->SetPipelineState(_colorPSO.get());
220+
//}
221+
222+
commandList->SetGraphicsRootSignature(_rootSignature.get());
223+
224+
const RECT viewportRect = {
225+
_destRect.left - _rendererRect.left,
226+
_destRect.top - _rendererRect.top,
227+
_destRect.right - _rendererRect.left,
228+
_destRect.bottom - _rendererRect.top
229+
};
230+
const SIZE viewportSize = Win32Helper::GetSizeOfRect(viewportRect);
231+
232+
{
233+
// 转换到 NDC
234+
float constants[] = {
235+
(cursorRect.left - _destRect.left) * 2 / (float)viewportSize.cx - 1.0f, // left
236+
1.0f - (cursorRect.top - _destRect.top) * 2 / (float)viewportSize.cy, // top
237+
_curCursorInfo->size.width * 2 / (float)viewportSize.cx, // width
238+
_curCursorInfo->size.height * 2 / (float)-viewportSize.cy // height
239+
};
240+
commandList->SetGraphicsRoot32BitConstants(0, (UINT)std::size(constants), constants, 0);
241+
}
242+
243+
auto& dynamicDescriptorHeap = _graphicsContext->GetDynamicDescriptorHeap();
244+
const uint32_t descriptorSize = dynamicDescriptorHeap.GetDescriptorSize();
245+
246+
commandList->SetGraphicsRootDescriptorTable(
247+
1, CD3DX12_GPU_DESCRIPTOR_HANDLE(heapGpuHandle, _curCursorInfo->_textureSrvIdx, descriptorSize));
248+
249+
{
250+
CD3DX12_VIEWPORT viewport(
251+
(float)viewportRect.left,
252+
(float)viewportRect.top,
253+
(float)viewportSize.cx,
254+
(float)viewportSize.cy
255+
);
256+
commandList->RSSetViewports(1, &viewport);
257+
}
258+
{
259+
CD3DX12_RECT scissorRect(viewportRect.left, viewportRect.top, viewportRect.right, viewportRect.bottom);
260+
commandList->RSSetScissorRects(1, &scissorRect);
261+
}
262+
263+
commandList->DrawInstanced(4, 1, 0, 0);
264+
186265
return S_OK;
187266
}
188267

@@ -352,6 +431,12 @@ CursorDrawer2::_CursorInfo* CursorDrawer2::_ResolveCursor(
352431
return nullptr;
353432
}
354433

434+
HRESULT hr = _graphicsContext->GetDynamicDescriptorHeap().Alloc(1, cursorInfo._textureSrvIdx);
435+
if (FAILED(hr)) {
436+
Logger::Get().ComError("DynamicDescriptorHeap::Alloc 失败", hr);
437+
return nullptr;
438+
}
439+
355440
return &_cursorInfos.emplace(std::make_pair(hCursor, isCursorDpiAware ? monitorDpi : 0),
356441
std::move(cursorInfo)).first->second;
357442
}
@@ -677,12 +762,106 @@ HRESULT CursorDrawer2::_InitializeCursorTexture(_CursorInfo& cursorInfo) noexcep
677762
}
678763

679764
if (cursorInfo.type != _CursorType::Color) {
765+
// TODO: 必要时 Bicubic 缩放
766+
cursorInfo.texture = std::move(cursorInfo.originTexture);
767+
} else {
680768
// 单色光标和彩色掩码光标始终使用最近邻采样,无需缩放
681769
cursorInfo.texture = std::move(cursorInfo.originTexture);
682-
return S_OK;
683770
}
684771

685-
cursorInfo.texture = std::move(cursorInfo.originTexture);
772+
CD3DX12_SHADER_RESOURCE_VIEW_DESC srvDesc =
773+
CD3DX12_SHADER_RESOURCE_VIEW_DESC::Tex2D(texDesc.Format, 1);
774+
_graphicsContext->GetDynamicDescriptorHeap().CreateShaderResourceView(
775+
cursorInfo.texture.get(), &srvDesc, cursorInfo._textureSrvIdx);
776+
777+
return S_OK;
778+
}
779+
780+
HRESULT CursorDrawer2::_CreateRootSignature() noexcept {
781+
CD3DX12_DESCRIPTOR_RANGE1 srvRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0,
782+
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
783+
D3D12_ROOT_PARAMETER1 rootParams[] = {
784+
{
785+
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
786+
.Constants = {
787+
.Num32BitValues = 4
788+
},
789+
.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX
790+
},
791+
{
792+
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
793+
.DescriptorTable = {
794+
.NumDescriptorRanges = 1,
795+
.pDescriptorRanges = &srvRange
796+
},
797+
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
798+
}
799+
};
800+
D3D12_STATIC_SAMPLER_DESC samplerDesc = {
801+
.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT,
802+
.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
803+
.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
804+
.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
805+
.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER,
806+
.ShaderRegister = 0
807+
};
808+
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc(
809+
(UINT)std::size(rootParams), rootParams, 1, &samplerDesc, D3D12_ROOT_SIGNATURE_FLAG_NONE);
810+
811+
winrt::com_ptr<ID3DBlob> signature;
812+
HRESULT hr = D3DX12SerializeVersionedRootSignature(
813+
&rootSignatureDesc, _graphicsContext->GetRootSignatureVersion(), signature.put(), nullptr);
814+
if (FAILED(hr)) {
815+
Logger::Get().ComError("D3DX12SerializeVersionedRootSignature 失败", hr);
816+
return hr;
817+
}
818+
819+
hr = _graphicsContext->GetDevice()->CreateRootSignature(
820+
0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature));
821+
if (FAILED(hr)) {
822+
Logger::Get().ComError("CreateRootSignature 失败", hr);
823+
return hr;
824+
}
825+
826+
return S_OK;
827+
}
828+
829+
HRESULT CursorDrawer2::_CreateColorPSO() noexcept {
830+
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {
831+
.pRootSignature = _rootSignature.get(),
832+
.VS = CD3DX12_SHADER_BYTECODE(CursorVS, sizeof(CursorVS)),
833+
.PS = CD3DX12_SHADER_BYTECODE(SimplePS, sizeof(SimplePS)),
834+
.BlendState = {
835+
.RenderTarget = {{
836+
// FinalColor = ScreenColor * CursorColor.a + CursorColor.rgb
837+
.BlendEnable = TRUE,
838+
.SrcBlend = D3D12_BLEND_ONE,
839+
.DestBlend = D3D12_BLEND_SRC_ALPHA,
840+
.BlendOp = D3D12_BLEND_OP_ADD,
841+
.SrcBlendAlpha = D3D12_BLEND_ONE,
842+
.DestBlendAlpha = D3D12_BLEND_ZERO,
843+
.BlendOpAlpha = D3D12_BLEND_OP_ADD,
844+
.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL
845+
}}
846+
},
847+
.SampleMask = UINT_MAX,
848+
.RasterizerState = {
849+
.FillMode = D3D12_FILL_MODE_SOLID,
850+
.CullMode = D3D12_CULL_MODE_NONE
851+
},
852+
.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
853+
.NumRenderTargets = 1,
854+
.RTVFormats = { _colorInfo.kind == winrt::AdvancedColorKind::StandardDynamicRange ?
855+
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R16G16B16A16_FLOAT },
856+
.SampleDesc = {.Count = 1 }
857+
};
858+
HRESULT hr = _graphicsContext->GetDevice()->CreateGraphicsPipelineState(
859+
&psoDesc, IID_PPV_ARGS(&_colorPSO));
860+
if (FAILED(hr)) {
861+
Logger::Get().ComError("CreateGraphicsPipelineState 失败", hr);
862+
return hr;
863+
}
864+
686865
return S_OK;
687866
}
688867

0 commit comments

Comments
 (0)