mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
feat: 实现绘制光标 (p11)
支持彩色掩码光标
This commit is contained in:
parent
c7bb28d0fb
commit
6f3394404c
4 changed files with 148 additions and 97 deletions
|
|
@ -10,6 +10,7 @@
|
|||
#include "ScalingWindow.h"
|
||||
#include "shaders/CursorVS.h"
|
||||
#include "shaders/SimplePS.h"
|
||||
#include "shaders/MaskedCursorPS.h"
|
||||
#include "shaders/MonochromeCursorPS.h"
|
||||
#include "Win32Helper.h"
|
||||
#include <DirectXPackedVector.h>
|
||||
|
|
@ -225,17 +226,28 @@ HRESULT CursorDrawer2::Draw(uint32_t curFrameSrvOffset) noexcept {
|
|||
|
||||
commandList->SetPipelineState(_colorPSO.get());
|
||||
commandList->SetGraphicsRootSignature(_colorRootSignature.get());
|
||||
} else {
|
||||
} else if (_curCursorInfo->type == _CursorType::Monochrome) {
|
||||
if (!_monochromePSO) {
|
||||
HRESULT hr = _CreateMonochromePSO();
|
||||
HRESULT hr = _CreateMaskPSO(true);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("_CreateColorPSO 失败", hr);
|
||||
Logger::Get().ComError("_CreateMaskPSO 失败", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
commandList->SetPipelineState(_monochromePSO.get());
|
||||
commandList->SetGraphicsRootSignature(_monochromeRootSignature.get());
|
||||
commandList->SetGraphicsRootSignature(_maskRootSignature.get());
|
||||
} else {
|
||||
if (!_maskedColorPSO) {
|
||||
HRESULT hr = _CreateMaskPSO(false);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("_CreateMaskPSO 失败", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
commandList->SetPipelineState(_maskedColorPSO.get());
|
||||
commandList->SetGraphicsRootSignature(_maskRootSignature.get());
|
||||
}
|
||||
|
||||
const RECT viewportRect = {
|
||||
|
|
@ -264,11 +276,12 @@ HRESULT CursorDrawer2::Draw(uint32_t curFrameSrvOffset) noexcept {
|
|||
DirectXHelper::Constant32 constants[] = {
|
||||
{.uintVal = _curCursorInfo->originSize.width},
|
||||
{.uintVal = _curCursorInfo->originSize.height},
|
||||
{.uintVal = _curCursorInfo->size.width},
|
||||
{.uintVal = _curCursorInfo->size.height},
|
||||
{.uintVal = uint32_t(cursorRect.left - _destRect.left)},
|
||||
{.uintVal = uint32_t(cursorRect.top - _destRect.top)},
|
||||
{.floatVal = _colorInfo.sdrWhiteLevel},
|
||||
{.uintVal = _colorInfo.kind == winrt::AdvancedColorKind::StandardDynamicRange},
|
||||
{.uintVal = 1}
|
||||
{.uintVal = _colorInfo.kind == winrt::AdvancedColorKind::StandardDynamicRange}
|
||||
};
|
||||
commandList->SetGraphicsRoot32BitConstants(1, (UINT)std::size(constants), constants, 0);
|
||||
|
||||
|
|
@ -968,73 +981,86 @@ HRESULT CursorDrawer2::_CreateColorPSO() noexcept {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CursorDrawer2::_CreateMonochromePSO() noexcept {
|
||||
winrt::com_ptr<ID3DBlob> signature;
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE1 srvRange1(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0,
|
||||
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
|
||||
CD3DX12_DESCRIPTOR_RANGE1 srvRange2(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1, 0,
|
||||
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
|
||||
D3D12_ROOT_PARAMETER1 rootParams[] = {
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
|
||||
.Constants = {
|
||||
.ShaderRegister = 0,
|
||||
.Num32BitValues = 4
|
||||
HRESULT CursorDrawer2::_CreateMaskPSO(bool isMonochrome) noexcept {
|
||||
if (!_maskRootSignature) {
|
||||
winrt::com_ptr<ID3DBlob> signature;
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE1 srvRange1(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0,
|
||||
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
|
||||
CD3DX12_DESCRIPTOR_RANGE1 srvRange2(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1, 0,
|
||||
D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE);
|
||||
D3D12_ROOT_PARAMETER1 rootParams[] = {
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
|
||||
.Constants = {
|
||||
.ShaderRegister = 0,
|
||||
.Num32BitValues = 4
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX
|
||||
},
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
|
||||
.Constants = {
|
||||
.ShaderRegister = 1,
|
||||
.Num32BitValues = 7
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS,
|
||||
.Constants = {
|
||||
.ShaderRegister = 1,
|
||||
.Num32BitValues = 8
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
},
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
.DescriptorTable = {
|
||||
.NumDescriptorRanges = 1,
|
||||
.pDescriptorRanges = &srvRange1
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
.DescriptorTable = {
|
||||
.NumDescriptorRanges = 1,
|
||||
.pDescriptorRanges = &srvRange1
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
},
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
.DescriptorTable = {
|
||||
.NumDescriptorRanges = 1,
|
||||
.pDescriptorRanges = &srvRange2
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
}
|
||||
};
|
||||
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc(
|
||||
(UINT)std::size(rootParams), rootParams, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
.DescriptorTable = {
|
||||
.NumDescriptorRanges = 1,
|
||||
.pDescriptorRanges = &srvRange2
|
||||
},
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL
|
||||
}
|
||||
};
|
||||
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc(
|
||||
(UINT)std::size(rootParams), rootParams, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE);
|
||||
|
||||
HRESULT hr = D3DX12SerializeVersionedRootSignature(
|
||||
&rootSignatureDesc, _graphicsContext->GetRootSignatureVersion(), signature.put(), nullptr);
|
||||
HRESULT hr = D3DX12SerializeVersionedRootSignature(
|
||||
&rootSignatureDesc,
|
||||
_graphicsContext->GetRootSignatureVersion(),
|
||||
signature.put(),
|
||||
nullptr
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("D3DX12SerializeVersionedRootSignature 失败", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = _graphicsContext->GetDevice()->CreateRootSignature(
|
||||
0,
|
||||
signature->GetBufferPointer(),
|
||||
signature->GetBufferSize(),
|
||||
IID_PPV_ARGS(&_maskRootSignature)
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("D3DX12SerializeVersionedRootSignature 失败", hr);
|
||||
Logger::Get().ComError("CreateRootSignature 失败", hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = _graphicsContext->GetDevice()->CreateRootSignature(
|
||||
0,
|
||||
signature->GetBufferPointer(),
|
||||
signature->GetBufferSize(),
|
||||
IID_PPV_ARGS(&_monochromeRootSignature)
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("CreateRootSignature 失败", hr);
|
||||
return hr;
|
||||
|
||||
D3D12_SHADER_BYTECODE psByteCode;
|
||||
if (isMonochrome) {
|
||||
psByteCode = CD3DX12_SHADER_BYTECODE(MonochromeCursorPS, sizeof(MonochromeCursorPS));
|
||||
} else {
|
||||
psByteCode = CD3DX12_SHADER_BYTECODE(MaskedCursorPS, sizeof(MaskedCursorPS));
|
||||
}
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {
|
||||
.pRootSignature = _monochromeRootSignature.get(),
|
||||
.pRootSignature = _maskRootSignature.get(),
|
||||
.VS = CD3DX12_SHADER_BYTECODE(CursorVS, sizeof(CursorVS)),
|
||||
.PS = CD3DX12_SHADER_BYTECODE(MonochromeCursorPS, sizeof(MonochromeCursorPS)),
|
||||
.PS = psByteCode,
|
||||
.BlendState = {
|
||||
.RenderTarget = {{ .RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL }}
|
||||
},
|
||||
|
|
@ -1049,8 +1075,11 @@ HRESULT CursorDrawer2::_CreateMonochromePSO() noexcept {
|
|||
DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R16G16B16A16_FLOAT },
|
||||
.SampleDesc = { .Count = 1 }
|
||||
};
|
||||
hr = _graphicsContext->GetDevice()->CreateGraphicsPipelineState(
|
||||
&psoDesc, IID_PPV_ARGS(&_monochromePSO));
|
||||
HRESULT hr = _graphicsContext->GetDevice()->CreateGraphicsPipelineState(
|
||||
&psoDesc,
|
||||
winrt::guid_of<ID3D12PipelineState>(),
|
||||
(isMonochrome ? _monochromePSO : _maskedColorPSO).put_void()
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
Logger::Get().ComError("CreateGraphicsPipelineState 失败", hr);
|
||||
return hr;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ private:
|
|||
|
||||
HRESULT _CreateColorPSO() noexcept;
|
||||
|
||||
HRESULT _CreateMonochromePSO() noexcept;
|
||||
HRESULT _CreateMaskPSO(bool isMonochrome) noexcept;
|
||||
|
||||
GraphicsContext* _graphicsContext = nullptr;
|
||||
Size _srcSize{};
|
||||
|
|
@ -145,8 +145,9 @@ private:
|
|||
|
||||
winrt::com_ptr<ID3D12RootSignature> _colorRootSignature;
|
||||
winrt::com_ptr<ID3D12PipelineState> _colorPSO;
|
||||
winrt::com_ptr<ID3D12RootSignature> _monochromeRootSignature;
|
||||
winrt::com_ptr<ID3D12RootSignature> _maskRootSignature;
|
||||
winrt::com_ptr<ID3D12PipelineState> _monochromePSO;
|
||||
winrt::com_ptr<ID3D12PipelineState> _maskedColorPSO;
|
||||
|
||||
bool _isCursorVisible = true;
|
||||
bool _isMoving = false;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,40 @@
|
|||
Texture2D originTex : register(t0);
|
||||
Texture2D cursorTex : register(t1);
|
||||
#include "Common.hlsli"
|
||||
|
||||
SamplerState pointSampler : register(s0);
|
||||
cbuffer RootConstants : register(b1) {
|
||||
uint2 cursorTexSize;
|
||||
uint2 cursorSize;
|
||||
uint2 originOffset;
|
||||
float sdrWhiteLevel;
|
||||
uint shouldEncodeSrgb;
|
||||
};
|
||||
|
||||
float4 main(noperspective float2 coord : TEXCOORD) : SV_TARGET {
|
||||
float4 mask = cursorTex.Sample(pointSampler, coord);
|
||||
Texture2D<float4> cursorTex : register(t0);
|
||||
Texture2D<float4> originTex : register(t1);
|
||||
|
||||
float4 main(noperspective float2 uv : TEXCOORD) : SV_TARGET {
|
||||
uint2 coord = uint2(uv * cursorTexSize);
|
||||
|
||||
// A 为 0 时用 RGB 通道取代屏幕颜色,为 1 时将 RGB 通道和屏幕颜色进行异或操作
|
||||
float4 mask = cursorTex[coord];
|
||||
|
||||
if (mask.a < 0.5f) {
|
||||
return float4(mask.rgb, 1);
|
||||
} else {
|
||||
float3 origin = originTex.Sample(pointSampler, coord).rgb;
|
||||
// 255.001953 的由来见 https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f
|
||||
return float4((uint3(origin * 255.001953f) ^ uint3(mask.rgb * 255.001953f)) / 255.0f, 1);
|
||||
}
|
||||
|
||||
float3 origin = originTex[uv * cursorSize + originOffset].rgb;
|
||||
|
||||
[branch]
|
||||
if (shouldEncodeSrgb) {
|
||||
origin = EncodeSrgb(saturate(origin));
|
||||
}
|
||||
|
||||
float white = max(max(max(origin.r, origin.g), origin.b), sdrWhiteLevel);
|
||||
origin = saturate(origin / white);
|
||||
|
||||
// 255.001953 来自
|
||||
// https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f
|
||||
origin = (uint3(origin * 255.001953f) ^ uint3(mask.rgb * 255.001953f)) / 255.0f;
|
||||
origin *= white;
|
||||
|
||||
return float4(origin, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#include "Common.hlsli"
|
||||
|
||||
cbuffer RootConstants : register(b1) {
|
||||
uint2 texSize;
|
||||
uint2 cursorTexSize;
|
||||
uint2 cursorSize;
|
||||
uint2 originOffset;
|
||||
float sdrWhiteLevel;
|
||||
uint isSdr;
|
||||
uint shouldEncodeSrgb;
|
||||
};
|
||||
|
||||
|
|
@ -12,34 +12,31 @@ Texture2D<uint> cursorTex : register(t0);
|
|||
Texture2D<float4> originTex : register(t1);
|
||||
|
||||
float4 main(noperspective float2 uv : TEXCOORD) : SV_TARGET {
|
||||
uint2 coord = uint2(uv * texSize);
|
||||
uint2 coord = uint2(uv * cursorTexSize);
|
||||
|
||||
// 高四位是 AND 掩码, 低四位是 XOR 掩码
|
||||
uint mask = cursorTex[coord];
|
||||
uint andMask = mask & 0xF0u;
|
||||
uint xorMask = mask & 0x0Fu;
|
||||
uint andMask = mask & 0xF0u;
|
||||
uint xorMask = mask & 0x0Fu;
|
||||
|
||||
if (!andMask) {
|
||||
float v = xorMask ? sdrWhiteLevel : 0.0f;
|
||||
return float4(v, v, v, 1.0f);
|
||||
}
|
||||
|
||||
float3 origin = originTex[coord + originOffset].rgb;
|
||||
|
||||
if (isSdr) {
|
||||
if (shouldEncodeSrgb) {
|
||||
origin = EncodeSrgb(saturate(origin));
|
||||
}
|
||||
|
||||
if (xorMask) {
|
||||
origin = 1.0f - origin;
|
||||
}
|
||||
} else {
|
||||
if (xorMask) {
|
||||
float white = max(max(origin.r, origin.g), max(origin.b, sdrWhiteLevel));
|
||||
origin = white - origin;
|
||||
}
|
||||
if (!andMask) {
|
||||
// 黑色或白色
|
||||
float c = xorMask ? sdrWhiteLevel : 0.0f;
|
||||
return float4(c, c, c, 1.0f);
|
||||
}
|
||||
|
||||
return float4(origin, 1.0f);
|
||||
float3 origin = originTex[uv * cursorSize + originOffset].rgb;
|
||||
|
||||
[branch]
|
||||
if (shouldEncodeSrgb) {
|
||||
origin = EncodeSrgb(saturate(origin));
|
||||
}
|
||||
|
||||
if (xorMask) {
|
||||
// 反色
|
||||
float white = max(max(max(origin.r, origin.g), origin.b), sdrWhiteLevel);
|
||||
origin = white - origin;
|
||||
}
|
||||
|
||||
return float4(origin, 1.0f);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue