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