feat: 新版 FX 解析器 (p4)

This commit is contained in:
Xu 2026-03-26 16:53:39 +08:00
commit 0279dca40c
43 changed files with 391 additions and 363 deletions

View file

@ -21,8 +21,8 @@ void CatmullRomDrawer::Initialize(D3D12Context& d3d12Context) noexcept {
HRESULT CatmullRomDrawer::Draw(
ComputeContext& computeContext,
Size inputSize,
Size outputSize,
SizeU inputSize,
SizeU outputSize,
uint32_t inputSrvOffset,
uint32_t outputUavOffset,
bool outputSrgb

View file

@ -11,8 +11,8 @@ public:
HRESULT Draw(
ComputeContext& computeContext,
Size inputSize,
Size outputSize,
SizeU inputSize,
SizeU outputSize,
uint32_t inputSrvOffset,
uint32_t outputUavOffset,
bool outputSrgb

View file

@ -519,7 +519,7 @@ void CursorDrawer::OnColorInfoChanged(const ColorInfo& colorInfo) noexcept {
_ClearCursorInfos();
}
static bool GetCursorSizeFromBmps(HBITMAP hColorBmp, HBITMAP hMaskBmp, Size& size) noexcept {
static bool GetCursorSizeFromBmps(HBITMAP hColorBmp, HBITMAP hMaskBmp, SizeU& size) noexcept {
BITMAP bmp{};
if (!GetObject(hColorBmp ? hColorBmp : hMaskBmp, sizeof(bmp), &bmp)) {
Logger::Get().Win32Error("GetObject 失败");
@ -532,7 +532,7 @@ static bool GetCursorSizeFromBmps(HBITMAP hColorBmp, HBITMAP hMaskBmp, Size& siz
return true;
}
static bool GetCursorSizeUnderDpi96(HCURSOR hCursor, Size& cursorSize) noexcept {
static bool GetCursorSizeUnderDpi96(HCURSOR hCursor, SizeU& cursorSize) noexcept {
ICONINFO iconInfo{};
{
DPI_AWARENESS_CONTEXT oldDpiContext =
@ -596,7 +596,7 @@ std::pair<const CursorDrawer::_CursorInfoKey, CursorDrawer::_CursorInfo>* Cursor
wil::unique_hbitmap hResColorBmp(cursorIconInfoEx.hbmColor);
wil::unique_hbitmap hResMaskBmp(cursorIconInfoEx.hbmMask);
Size cursorBmpSize;
SizeU cursorBmpSize;
if (!GetCursorSizeFromBmps(hResColorBmp.get(), hResMaskBmp.get(), cursorBmpSize)) {
Logger::Get().Error("GetCursorSizeFromBmps 失败");
return nullptr;
@ -609,7 +609,7 @@ std::pair<const CursorDrawer::_CursorInfoKey, CursorDrawer::_CursorInfo>* Cursor
// 如果不能确定光标是否随 DPI 缩放则假设为真,绝大多数时候是对的
cursorInfo.size = _CalcCursorSize(cursorBmpSize, SYSTEM_DPI, monitorDpi, true);
} else {
Size cursorSizeDpi96;
SizeU cursorSizeDpi96;
if (!GetCursorSizeUnderDpi96(hCursor, cursorSizeDpi96)) {
Logger::Get().Error("GetCursorSizeUnderDpi96 失败");
return nullptr;
@ -621,7 +621,7 @@ std::pair<const CursorDrawer::_CursorInfoKey, CursorDrawer::_CursorInfo>* Cursor
}
SmallVector<wil::unique_hcursor, 1> cursorFrameRes;
Point resHotspot = { cursorIconInfoEx.xHotspot, cursorIconInfoEx.yHotspot };
PointU resHotspot = { cursorIconInfoEx.xHotspot, cursorIconInfoEx.yHotspot };
// 尝试从光标原始来源加载指定尺寸的资源,如果失败旧只能使用 GetIconInfo 得到的位图,
// DPI 虚拟化机制可能导致图像质量严重下降。
@ -700,8 +700,8 @@ std::pair<const CursorDrawer::_CursorInfoKey, CursorDrawer::_CursorInfo>* Cursor
std::move(cursorInfo)).first;
}
Size CursorDrawer::_CalcCursorSize(
Size cursorBmpSize,
SizeU CursorDrawer::_CalcCursorSize(
SizeU cursorBmpSize,
uint32_t cursorDpi,
uint32_t monitorDpi,
bool isCursorDpiAware
@ -826,7 +826,7 @@ bool CursorDrawer::_ResolveCursorFramePixels(
HBITMAP hColorBmp,
HBITMAP hMaskBmp
) const noexcept {
const Size bmpSize = {
const SizeU bmpSize = {
cursorFrame.resSize.width,
hColorBmp ? cursorFrame.resSize.height : cursorFrame.resSize.height * 2
};

View file

@ -103,10 +103,10 @@ private:
struct _CursorFrame {
_CursorType type;
Point hotspot;
PointU hotspot;
winrt::com_ptr<ID3D12Resource> texture;
Size resSize;
SizeU resSize;
ByteBuffer resTextureData;
// 这两个资源使用完毕后在 _ClearRetiredResources 中释放
winrt::com_ptr<ID3D12Resource> uploadBuffer;
@ -119,7 +119,7 @@ private:
};
struct _CursorInfo {
Size size;
SizeU size;
SmallVector<_CursorFrame, 1> frames;
// 序列表 (帧索引值数组),使多帧可以复用同一个 _CursorFrame。为空表示顺序播放
SmallVector<std::pair<uint32_t, std::chrono::nanoseconds>, 0> frameSequence;
@ -144,8 +144,8 @@ private:
POINT cursorPos
) noexcept;
Size _CalcCursorSize(
Size cursorBmpSize,
SizeU _CalcCursorSize(
SizeU cursorBmpSize,
uint32_t cursorDpi,
uint32_t monitorDpi,
bool isCursorDpiAware
@ -190,7 +190,7 @@ private:
void _OnCursorsRegChanged(wil::RegistryChangeKind) noexcept;
D3D12Context* _d3d12Context = nullptr;
Size _srcSize{};
SizeU _srcSize{};
RECT _rendererRect{};
RECT _destRect{};
ColorInfo _colorInfo;
@ -222,7 +222,7 @@ private:
// 用于从渲染目标复制光标下区域
winrt::com_ptr<ID3D12Resource> _tempOriginTexture;
Size _tempOriginTextureSize{};
SizeU _tempOriginTextureSize{};
uint32_t _tempOriginTextureSrvOffset = std::numeric_limits<uint32_t>::max();
struct _RetiredTempOriginTexture {

View file

@ -5,20 +5,20 @@
namespace Magpie {
static bool IsCornerInRect(Point p, const Rect& r) noexcept {
static bool IsCornerInRect(PointU p, const RectU& r) noexcept {
return p.x >= r.left && p.x <= r.right && p.y >= r.top && p.y <= r.bottom;
}
static bool OptimizeDirtyRectPair(Rect& rect1, Rect& rect2, bool reversed = false) noexcept {
static bool OptimizeDirtyRectPair(RectU& rect1, RectU& rect2, bool reversed = false) noexcept {
if (RectHelper::IsEmpty(rect1) || RectHelper::IsEmpty(rect2)) {
return false;
}
// 计算 rect2 有几个角在 rect1 内
bool lt = IsCornerInRect(Point{ rect2.left, rect2.top }, rect1);
bool rt = IsCornerInRect(Point{ rect2.right, rect2.top }, rect1);
bool rb = IsCornerInRect(Point{ rect2.right, rect2.bottom }, rect1);
bool lb = IsCornerInRect(Point{ rect2.left, rect2.bottom }, rect1);
bool lt = IsCornerInRect(PointU{ rect2.left, rect2.top }, rect1);
bool rt = IsCornerInRect(PointU{ rect2.right, rect2.top }, rect1);
bool rb = IsCornerInRect(PointU{ rect2.right, rect2.bottom }, rect1);
bool lb = IsCornerInRect(PointU{ rect2.left, rect2.bottom }, rect1);
uint32_t count = (uint32_t)lt + (uint32_t)rt + (uint32_t)rb + (uint32_t)lb;
if (count <= 1) {
@ -124,7 +124,7 @@ static bool OptimizeDirtyRectPair(Rect& rect1, Rect& rect2, bool reversed = fals
return false;
}
static void BasicOptimize(SmallVectorImpl<Rect>& dirtyRects) noexcept {
static void BasicOptimize(SmallVectorImpl<RectU>& dirtyRects) noexcept {
// 持续循环直到不再能优化
while (true) {
const uint32_t count = (uint32_t)dirtyRects.size();
@ -145,7 +145,7 @@ static void BasicOptimize(SmallVectorImpl<Rect>& dirtyRects) noexcept {
// 从后向前删除空矩形
for (int i = int(count - 1); i >= 0; --i) {
const Rect& rect = dirtyRects[i];
const RectU& rect = dirtyRects[i];
if (RectHelper::IsEmpty(rect)) {
dirtyRects.erase(dirtyRects.begin() + i);
}
@ -153,9 +153,9 @@ static void BasicOptimize(SmallVectorImpl<Rect>& dirtyRects) noexcept {
}
}
static uint32_t CalcTotalPixels(const SmallVectorImpl<Rect>& rects) noexcept {
static uint32_t CalcTotalPixels(const SmallVectorImpl<RectU>& rects) noexcept {
uint32_t result = 0;
for (const Rect& rect : rects) {
for (const RectU& rect : rects) {
result += RectHelper::CalcArea(rect);
}
return result;
@ -163,16 +163,19 @@ static uint32_t CalcTotalPixels(const SmallVectorImpl<Rect>& rects) noexcept {
#ifdef MP_DEBUG_INFO
// 验证优化算法的正确性
static void ValidateOptimize(const SmallVectorImpl<Rect>& originRects, const SmallVectorImpl<Rect>& newRects) noexcept {
static void ValidateOptimize(
const SmallVectorImpl<RectU>& originRects,
const SmallVectorImpl<RectU>& newRects
) noexcept {
if (originRects.empty()) {
return;
}
std::vector<bool> pixels;
for (const Rect& originRect : originRects) {
for (const RectU& originRect : originRects) {
// 作为优化先检查有没有被优化后的某个矩形包含
bool contained = false;
for (const Rect& newRect : newRects) {
for (const RectU& newRect : newRects) {
if (RectHelper::Contains(newRect, originRect)) {
contained = true;
break;
@ -186,7 +189,7 @@ static void ValidateOptimize(const SmallVectorImpl<Rect>& originRects, const Sma
const uint32_t originWidth = originRect.right - originRect.left;
pixels.assign(size_t((originRect.bottom - originRect.top) * originWidth), false);
for (Rect newRect : newRects) {
for (RectU newRect : newRects) {
if (!RectHelper::Intersect(newRect, newRect, originRect)) {
continue;
}
@ -201,7 +204,7 @@ static void ValidateOptimize(const SmallVectorImpl<Rect>& originRects, const Sma
if (std::find(pixels.begin(), pixels.end(), false) != pixels.end()) {
OutputDebugString(L"优化脏矩形算法错误!\n");
// 打印脏矩形供调试
for (const Rect& rect : originRects) {
for (const RectU& rect : originRects) {
OutputDebugString(fmt::format(L"{},{},{},{}\n",
rect.left, rect.top, rect.right, rect.bottom).c_str());
}
@ -211,7 +214,7 @@ static void ValidateOptimize(const SmallVectorImpl<Rect>& originRects, const Sma
}
#endif
void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
void DirtyRectsOptimizer::Execute(SmallVectorImpl<RectU>& dirtyRects) noexcept {
uint32_t rectCount = (uint32_t)dirtyRects.size();
if (rectCount <= 1) {
return;
@ -219,7 +222,7 @@ void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
#ifdef MP_DEBUG_INFO
auto se = wil::scope_exit(std::bind_front(ValidateOptimize, DEBUG_INFO.validateDirtyRectsOptimizer ?
SmallVector<Rect>(dirtyRects.begin(), dirtyRects.end()) : SmallVector<Rect>(), std::ref(dirtyRects)));
SmallVector<RectU>(dirtyRects.begin(), dirtyRects.end()) : SmallVector<RectU>(), std::ref(dirtyRects)));
#endif
if (rectCount <= MAX_CAPTURE_DIRTY_RECT_COUNT * 4) {
@ -230,7 +233,7 @@ void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
// 深度优化的复杂度为 n^4输入矩形数量太多时应削减。花太多时间优化脏矩形是得不偿失的
constexpr uint32_t DEEP_OPTIMIZE_LIMIT = MAX_CAPTURE_DIRTY_RECT_COUNT * 2;
if (rectCount > DEEP_OPTIMIZE_LIMIT) {
Rect& lastRect = dirtyRects[DEEP_OPTIMIZE_LIMIT - 1];
RectU& lastRect = dirtyRects[DEEP_OPTIMIZE_LIMIT - 1];
for (auto it = dirtyRects.begin() + DEEP_OPTIMIZE_LIMIT; it != dirtyRects.end(); ++it) {
lastRect = RectHelper::Union(lastRect, *it);
}
@ -255,15 +258,15 @@ void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
// 遍历所有的两两合并找出总像素数最少的
for (uint32_t i = 0; i < rectCount; ++i) {
for (uint32_t j = i + 1; j < rectCount; ++j) {
const Rect& rect1 = dirtyRects[i];
const Rect& rect2 = dirtyRects[j];
const RectU& rect1 = dirtyRects[i];
const RectU& rect2 = dirtyRects[j];
// 两个矩形必须相交才有优化的可能,但脏矩形数量过多时需要强制合并
if (!RectHelper::IsOverlap(rect1, rect2) && rectCount <= MAX_CAPTURE_DIRTY_RECT_COUNT) {
continue;
}
Rect unionedRect = RectHelper::Union(rect1, rect2);
RectU unionedRect = RectHelper::Union(rect1, rect2);
uint32_t newTotalPixels = 0;
uint32_t newRectCount = 0;
bool optimized = false;
@ -274,7 +277,7 @@ void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
continue;
}
Rect curRect = dirtyRects[k];
RectU curRect = dirtyRects[k];
if (OptimizeDirtyRectPair(curRect, unionedRect)) {
optimized = true;
}
@ -326,12 +329,12 @@ void DirtyRectsOptimizer::Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept {
#ifdef _DEBUG
static Ignore _ = [] {
auto rectComp = [](const Rect& l, const Rect& r) {
auto rectComp = [](const RectU& l, const RectU& r) {
return std::tuple(l.left, l.top, l.right, l.bottom) <
std::tuple(r.left, r.top, r.right, r.bottom);
};
SmallVector<Rect, 0> dirtyRects;
SmallVector<RectU, 0> dirtyRects;
dirtyRects.reserve(16);
dirtyRects.emplace_back(0, 0, 2, 2);
@ -342,15 +345,15 @@ static Ignore _ = [] {
BasicOptimize(dirtyRects);
std::sort(dirtyRects.begin(), dirtyRects.end(), rectComp);
assert(dirtyRects.size() == 2);
assert((dirtyRects[0] == Rect{ 0, 0, 2, 2 }));
assert((dirtyRects[1] == Rect{ 1, 1, 4, 4 }));
assert((dirtyRects[0] == RectU{ 0, 0, 2, 2 }));
assert((dirtyRects[1] == RectU{ 1, 1, 4, 4 }));
dirtyRects.clear();
dirtyRects.emplace_back(0, 0, 1, 1);
dirtyRects.emplace_back(0, 0, 2, 2);
BasicOptimize(dirtyRects);
assert(dirtyRects.size() == 1);
assert((dirtyRects[0] == Rect{ 0, 0, 2, 2 }));
assert((dirtyRects[0] == RectU{ 0, 0, 2, 2 }));
return Ignore();
}();

View file

@ -5,7 +5,7 @@ namespace Magpie {
struct DirtyRectsOptimizer {
// 尝试减少脏矩形数量和总像素数
static void Execute(SmallVectorImpl<Rect>& dirtyRects) noexcept;
static void Execute(SmallVectorImpl<RectU>& dirtyRects) noexcept;
};
}

View file

@ -27,7 +27,7 @@ bool DuplicateFrameChecker::Initialize(
ID3D11Device5* d3d11Device,
ID3D11DeviceContext4* d3d11DC,
const ColorInfo& colorInfo,
Size frameSize,
SizeU frameSize,
uint32_t captureFrameCount,
bool disableBoundsChecking
) noexcept {
@ -138,7 +138,7 @@ bool DuplicateFrameChecker::Initialize(
HRESULT DuplicateFrameChecker::CheckFrame(
ID3D11Texture2D* frameResource,
uint32_t frameIdx,
SmallVectorImpl<Rect>& dirtyRects
SmallVectorImpl<RectU>& dirtyRects
) noexcept {
assert(!dirtyRects.empty() && dirtyRects.size() <= MAX_CAPTURE_DIRTY_RECT_COUNT);
@ -150,7 +150,7 @@ HRESULT DuplicateFrameChecker::CheckFrame(
if (_isBoundsCheckingDisabled) {
// 确保捕获帧右下两边没有多余像素
for (const Rect& rect : dirtyRects) {
for (const RectU& rect : dirtyRects) {
assert(rect.right == desc.Width && rect.bottom == desc.Height);
}
}
@ -212,7 +212,7 @@ HRESULT DuplicateFrameChecker::CheckFrame(
#ifdef MP_DEBUG_INFO
if (DEBUG_INFO.enableStatisticsForDynamicDuplicateFrameDetection) {
// 预测此帧不会重复,验证是否正确
SmallVector<Rect> tempRects(dirtyRects.begin(), dirtyRects.end());
SmallVector<RectU> tempRects(dirtyRects.begin(), dirtyRects.end());
HRESULT hr = _CheckDirtyRects(frameIdx, tempRects);
if (FAILED(hr)) {
Logger::Get().ComError("_CheckDirtyRects 失败", hr);
@ -240,7 +240,10 @@ void DuplicateFrameChecker::OnCaptureStopped() noexcept {
std::fill(_frameSrvs.begin(), _frameSrvs.end(), nullptr);
}
HRESULT DuplicateFrameChecker::_CheckDirtyRects(uint32_t newFrameIdx, SmallVectorImpl<Rect>& dirtyRects) noexcept {
HRESULT DuplicateFrameChecker::_CheckDirtyRects(
uint32_t newFrameIdx,
SmallVectorImpl<RectU>& dirtyRects
) noexcept {
assert(dirtyRects.size() <= MAX_CAPTURE_DIRTY_RECT_COUNT);
{
@ -261,7 +264,7 @@ HRESULT DuplicateFrameChecker::_CheckDirtyRects(uint32_t newFrameIdx, SmallVecto
++_curTargetValue;
for (uint32_t i = 0; i < dirtyRectCount; ++i) {
const Rect& dirtyRect = dirtyRects[i];
const RectU& dirtyRect = dirtyRects[i];
alignas(32) DirectXHelper::Constant32 constants[] = {
{.uintVal = dirtyRect.left},
@ -287,7 +290,7 @@ HRESULT DuplicateFrameChecker::_CheckDirtyRects(uint32_t newFrameIdx, SmallVecto
_deviceContext->CSSetConstantBuffers1(0, 1, &buffer, &firstConstant, &numConstants);
}
const Rect& dirtyRect = dirtyRects[i];
const RectU& dirtyRect = dirtyRects[i];
_deviceContext->Dispatch(
(dirtyRect.right - dirtyRect.left + DUP_FRAME_DISPATCH_BLOCK_SIZE - 1) / DUP_FRAME_DISPATCH_BLOCK_SIZE,
(dirtyRect.bottom - dirtyRect.top + DUP_FRAME_DISPATCH_BLOCK_SIZE - 1) / DUP_FRAME_DISPATCH_BLOCK_SIZE,

View file

@ -16,24 +16,28 @@ public:
ID3D11Device5* d3d11Device,
ID3D11DeviceContext4* d3d11DC,
const ColorInfo& colorInfo,
Size frameSize,
SizeU frameSize,
uint32_t captureFrameCount,
bool disableBoundsChecking
) noexcept;
HRESULT CheckFrame(ID3D11Texture2D* frameResource, uint32_t frameIdx, SmallVectorImpl<Rect>& dirtyRects) noexcept;
HRESULT CheckFrame(
ID3D11Texture2D* frameResource,
uint32_t frameIdx,
SmallVectorImpl<RectU>& dirtyRects
) noexcept;
void OnFrameAdopted(uint32_t frameIdx) noexcept;
void OnCaptureStopped() noexcept;
private:
HRESULT _CheckDirtyRects(uint32_t newFrameIdx, SmallVectorImpl<Rect>& dirtyRects) noexcept;
HRESULT _CheckDirtyRects(uint32_t newFrameIdx, SmallVectorImpl<RectU>& dirtyRects) noexcept;
ID3D11Device5* _device = nullptr;
ID3D11DeviceContext4* _deviceContext = nullptr;
Size _frameSize{};
SizeU _frameSize{};
winrt::com_ptr<ID3D11ComputeShader> _dupFrameCS;
winrt::com_ptr<ID3D11Buffer> _constantBuffer;

View file

@ -21,11 +21,13 @@ public:
virtual bool Bind(
ID3D12Resource* inputResource,
Size inputSize,
SizeU inputSize,
const ColorInfo& colorInfo,
Size& outputSize
SizeU& outputSize
) noexcept = 0;
virtual bool IsReady() noexcept = 0;
virtual HRESULT Draw(
ComputeContext& computeContext,
uint32_t inputSrvOffset,

View file

@ -12,8 +12,8 @@ namespace Magpie {
bool EffectsDrawer::Initialize(
D3D12Context& d3d12Context,
const ColorInfo& colorInfo,
Size inputSize,
Size rendererSize
SizeU inputSize,
SizeU rendererSize
) noexcept {
_d3d12Context = &d3d12Context;
_isScRGB = colorInfo.kind != winrt::AdvancedColorKind::StandardDynamicRange;
@ -113,7 +113,7 @@ HRESULT EffectsDrawer::Draw(
return S_OK;
}
void EffectsDrawer::OnResized(Size rendererSize) noexcept {
void EffectsDrawer::OnResized(SizeU rendererSize) noexcept {
_outputSize = rendererSize;
}

View file

@ -14,8 +14,8 @@ public:
bool Initialize(
D3D12Context& d3d12Context,
const ColorInfo& colorInfo,
Size inputSize,
Size rendererSize
SizeU inputSize,
SizeU rendererSize
) noexcept;
HRESULT Draw(
@ -27,19 +27,19 @@ public:
uint32_t outputUavOffset
) noexcept;
Size GetOutputSize() const noexcept {
SizeU GetOutputSize() const noexcept {
return _outputSize;
}
void OnResized(Size rendererSize) noexcept;
void OnResized(SizeU rendererSize) noexcept;
void OnColorInfoChanged(const ColorInfo& colorInfo) noexcept;
private:
D3D12Context* _d3d12Context = nullptr;
Size _inputSize{};
Size _outputSize{};
SizeU _inputSize{};
SizeU _outputSize{};
std::optional<CatmullRomDrawer> _catmullRomDrawer;

View file

@ -5,6 +5,7 @@
#include "Logger.h"
#include "StrHelper.h"
#include "Win32Helper.h"
#include <rapidhash.h>
namespace Magpie {
@ -67,7 +68,7 @@ winrt::fire_and_forget EffectsService::Initialize() {
}
auto lock = srwLock.lock_exclusive();
_effectsMap.emplace(effectNames[id], (uint32_t)_effects.size());
_effectsMap.emplace(effectInfo.name, (uint32_t)_effects.size());
_effects.emplace_back(std::move(effectInfo));
}, nEffect);
@ -85,13 +86,115 @@ const std::vector<EffectInfo>& EffectsService::GetEffects() noexcept {
return _effects;
}
const EffectInfo* EffectsService::GetEffect(std::wstring_view name) noexcept {
const EffectInfo* EffectsService::GetEffect(std::string_view name) noexcept {
_WaitForInitialize();
auto it = _effectsMap.find(name);
return it != _effectsMap.end() ? &_effects[it->second] : nullptr;
}
static std::string GetLinearEffectName(std::string_view effectName) {
std::string result(effectName);
for (char& c : result) {
if (c == '\\') {
c = '#';
}
}
return result;
}
static std::string GetCacheFileName(
std::string_view linearEffectName,
D3D_SHADER_MODEL shaderModel,
ShaderEffectParserFlags flags,
uint64_t hash
) {
// 缓存文件的命名: {效果名}_{shader model(4)}_{标志位(4)}_{哈希(16)}
return fmt::format("{}\\{}_{:04x}_{:04x}_{:016x}",
StrHelper::UTF16ToUTF8(CommonSharedConstants::CACHE_DIR),
linearEffectName, (uint32_t)shaderModel, (uint32_t)flags, hash);
}
std::string EffectsService::SubmitCompileShaderEffectTask(
std::string_view effectName,
const phmap::flat_hash_map<std::string, float>* inlineParams,
D3D_SHADER_MODEL shaderModel,
bool isFP16Enabled,
bool isAdvancedColorEnabled
) noexcept {
std::string source;
{
std::wstring fileName = StrHelper::Concat(
CommonSharedConstants::EFFECTS_DIR, L"\\", StrHelper::UTF8ToUTF16(effectName), L".hlsl");
Win32Helper::ReadTextFile(fileName.c_str(), source);
}
ShaderEffectParserOptions options = {
.inlineParams = inlineParams,
.shaderModel = shaderModel
};
if (isFP16Enabled) {
options.flags |= ShaderEffectParserFlags::EnableFP16;
}
if (isAdvancedColorEnabled) {
options.flags |= ShaderEffectParserFlags::EnableAdvancedColor;
}
// 传给 ParseForDesc 的几个参数都会影响字节码,其中 shaderModel 和 flags 不需要参与哈希,
// 它们影响缓存键,即缓存文件名。
std::string byteCodeKey;
byteCodeKey.append(source);
if (inlineParams) {
for (const auto& pair : *inlineParams) {
byteCodeKey.append(fmt::format("|{}|{}", pair.first, std::lroundf(pair.second * 10000)));
}
}
uint64_t hash = rapidhash(byteCodeKey.data(), byteCodeKey.size());
std::string cacheKey = GetCacheFileName(
GetLinearEffectName(effectName), shaderModel, options.flags, hash);
if (!_shaderEffectCache.contains(cacheKey)) {
_shaderEffectCache.emplace(cacheKey, _ShaderEffectMemCacheItem{});
ShaderEffectDesc effectDesc;
ShaderEffectSource effectSource;
std::string errorMsg = ShaderEffectParser::ParseForDesc(
effectName,
std::move(source),
StrHelper::UTF16ToUTF8(CommonSharedConstants::EFFECTS_DIR),
options,
effectDesc,
effectSource
);
if (errorMsg.empty()) {
} else {
// 解析失败
_shaderEffectCache.erase(cacheKey);
}
}
return cacheKey;
}
bool EffectsService::GetTaskResult(std::string taskKey, const ShaderEffectDesc*& effectDesc) noexcept {
auto it = _shaderEffectCache.find(taskKey);
if (it == _shaderEffectCache.end()) {
// 编译失败
return false;
}
if (it->second.lastAccess == std::numeric_limits<uint32_t>::max()) {
// 尚未编译完成
effectDesc = nullptr;
return true;
}
return &it->second.effectDesc;
}
void EffectsService::_WaitForInitialize() noexcept {
if (_initializedCache) {
return;

View file

@ -44,8 +44,8 @@ void FrameProducer::InitializeAsync(
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
const RECT& srcRect,
Size rendererSize,
Size& outputSize,
SizeU rendererSize,
SizeU& outputSize,
SimpleTask<bool>& task
) noexcept {
_d3d12Context.CopyDevice(d3d12Context);
@ -94,8 +94,8 @@ HRESULT FrameProducer::ConsumerEndFrame(
}
void FrameProducer::OnResizedAsync(
Size rendererSize,
Size& outputSize,
SizeU rendererSize,
SizeU& outputSize,
SimpleTask<HRESULT>& task
) noexcept {
_dispatcher.TryEnqueue([&, rendererSize] {
@ -220,8 +220,8 @@ void FrameProducer::_ProducerThreadProc(
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
RECT srcRect,
Size rendererSize,
Size& outputSize,
SizeU rendererSize,
SizeU& outputSize,
SimpleTask<bool>& initializeTask
) noexcept {
#ifdef _DEBUG
@ -319,8 +319,8 @@ bool FrameProducer::_Initialize(
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
const RECT& srcRect,
Size rendererSize,
Size& outputSize
SizeU rendererSize,
SizeU& outputSize
) noexcept {
winrt::init_apartment(winrt::apartment_type::single_threaded);
@ -365,7 +365,7 @@ bool FrameProducer::_Initialize(
}
{
const Size inputSize = {
const SizeU inputSize = {
uint32_t(srcRect.right - srcRect.left),
uint32_t(srcRect.bottom - srcRect.top)
};

View file

@ -23,8 +23,8 @@ public:
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
const RECT& srcRect,
Size rendererSize,
Size& outputSize,
SizeU rendererSize,
SizeU& outputSize,
SimpleTask<bool>& task
) noexcept;
@ -44,7 +44,7 @@ public:
uint64_t fenceValueToSignal
) const noexcept;
void OnResizedAsync(Size rendererSize, Size& outputSize, SimpleTask<HRESULT>& task) noexcept;
void OnResizedAsync(SizeU rendererSize, SizeU& outputSize, SimpleTask<HRESULT>& task) noexcept;
void OnColorInfoChangedAsync(const ColorInfo& colorInfo, SimpleTask<HRESULT>& task) noexcept;
@ -55,8 +55,8 @@ private:
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
RECT srcRect,
Size rendererSize,
Size& outputSize,
SizeU rendererSize,
SizeU& outputSize,
SimpleTask<bool>& initializeTask
) noexcept;
@ -64,8 +64,8 @@ private:
const ColorInfo& colorInfo,
HMONITOR hMonSrc,
const RECT& srcRect,
Size rendererSize,
Size& outputSize
SizeU rendererSize,
SizeU& outputSize
) noexcept;
void _CreateInputDescriptors() noexcept;

View file

@ -4,13 +4,12 @@
#include "Logger.h"
#include "ScalingWindow.h"
#include "DebugInfo.h"
#include "DescriptorHeap.h"
namespace Magpie {
bool FrameRingBuffer::Initialize(
D3D12Context& d3d12Context,
Size size,
SizeU size,
const ColorInfo& colorInfo
) noexcept {
_d3d12Context = &d3d12Context;
@ -206,7 +205,7 @@ uint64_t FrameRingBuffer::GetLatestFrameNumber() const noexcept {
return _producerFence->GetCompletedValue();
}
HRESULT FrameRingBuffer::OnResized(Size size) noexcept {
HRESULT FrameRingBuffer::OnResized(SizeU size) noexcept {
_size = size;
HRESULT hr = _CreateBuffers();

View file

@ -13,7 +13,7 @@ public:
bool Initialize(
D3D12Context& d3d12Context,
Size size,
SizeU size,
const ColorInfo& colorInfo
) noexcept;
@ -42,7 +42,7 @@ public:
uint64_t GetLatestFrameNumber() const noexcept;
HRESULT OnResized(Size size) noexcept;
HRESULT OnResized(SizeU size) noexcept;
HRESULT OnColorInfoChanged(const ColorInfo& colorInfo) noexcept;
@ -72,7 +72,7 @@ private:
uint64_t _curConsumerFenceValue = 0;
winrt::com_ptr<ID3D12Fence1> _producerFence;
Size _size{};
SizeU _size{};
bool _isScRGB = false;
};

View file

@ -252,7 +252,7 @@ bool GraphicsCaptureFrameSource::Initialize(
_d3d11Device.get(),
_d3d11DC.get(),
colorInfo,
Size{ _frameBox.right, _frameBox.bottom },
SizeU{ _frameBox.right, _frameBox.bottom },
captureFrameCount,
!_isDirtyRegionSupported
)) {
@ -438,7 +438,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
_captureFrameResourceTable[_newCaptureFrameResourceIdx].second.get();
// curSlot.output 到 curFrameResource 的脏矩形
SmallVector<Rect> allDirtyRects;
SmallVector<RectU> allDirtyRects;
if (_isDirtyRegionSupported) {
for (const _FrameResourceSlot& slot : _slots) {
allDirtyRects.append(slot.dirtyRects);
@ -447,7 +447,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
#ifdef _DEBUG
// 所有脏矩形应在 _frameBox 内
for (const Rect& dirtyRect : allDirtyRects) {
for (const RectU& dirtyRect : allDirtyRects) {
assert(dirtyRect.left >= _frameBox.left && dirtyRect.top >= _frameBox.top &&
dirtyRect.right <= _frameBox.right && dirtyRect.bottom <= _frameBox.bottom);
}
@ -505,7 +505,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
CD3DX12_TEXTURE_COPY_LOCATION dest(curCASlot.bridgeResource.get(), 0);
if (_isDirtyRegionSupported) {
for (const Rect& dirtyRect : allDirtyRects) {
for (const RectU& dirtyRect : allDirtyRects) {
D3D12_BOX box = {
.left = dirtyRect.left,
.top = dirtyRect.top,
@ -554,7 +554,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
return false;
}
const Rect& dirtyRect = allDirtyRects[0];
const RectU& dirtyRect = allDirtyRects[0];
return dirtyRect.left == _frameBox.left && dirtyRect.top == _frameBox.top &&
dirtyRect.right == _frameBox.right && dirtyRect.bottom == _frameBox.bottom;
};
@ -565,7 +565,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
CD3DX12_TEXTURE_COPY_LOCATION src(curCASlot.sharedResource.get(), 0);
CD3DX12_TEXTURE_COPY_LOCATION dest(curSlot.output.get(), 0);
for (const Rect& dirtyRect : allDirtyRects) {
for (const RectU& dirtyRect : allDirtyRects) {
D3D12_BOX box = {
.left = dirtyRect.left - _frameBox.left,
.top = dirtyRect.top - _frameBox.top,
@ -582,7 +582,7 @@ HRESULT GraphicsCaptureFrameSource::Update(uint32_t& outputIdx) noexcept {
CD3DX12_TEXTURE_COPY_LOCATION dest(curSlot.output.get(), 0);
if (_isDirtyRegionSupported) {
for (const Rect& dirtyRect : allDirtyRects) {
for (const RectU& dirtyRect : allDirtyRects) {
D3D12_BOX box = {
.left = dirtyRect.left,
.top = dirtyRect.top,
@ -1121,7 +1121,7 @@ void GraphicsCaptureFrameSource::_Direct3D11CaptureFramePool_FrameArrived(
const winrt::IInspectable&
) {
winrt::Direct3D11CaptureFrame frame{ nullptr };
SmallVector<Rect> dirtyRects;
SmallVector<RectU> dirtyRects;
// 取最新帧
while (true) {

View file

@ -94,12 +94,12 @@ private:
// 不要在持有 _latestFrameLock 时释放 _latestFrame 或调用其中的方法,和 WGC 内部的
// 同步机制冲突。如果此时_Direct3D11CaptureFramePool_FrameArrived 正在执行会死锁。
winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame _latestFrame{ nullptr };
SmallVector<Rect> _latestFrameDirtyRects;
SmallVector<RectU> _latestFrameDirtyRects;
std::vector<std::pair<ID3D11Texture2D*, winrt::com_ptr<ID3D12Resource>>> _captureFrameResourceTable;
std::unique_ptr<DuplicateFrameChecker> _duplicateFrameChecker;
winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame _newFrame{ nullptr };
SmallVector<Rect> _newFrameDirtyRects;
SmallVector<RectU> _newFrameDirtyRects;
uint32_t _newCaptureFrameResourceIdx = 0;
struct _FrameCrossAdapterResourceSlot {
@ -121,7 +121,7 @@ private:
// 保留引用防止 WGC 再次写入
winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame captureFrame{ nullptr };
uint32_t captureFrameResourceIdx = 0;
SmallVector<Rect> dirtyRects;
SmallVector<RectU> dirtyRects;
winrt::com_ptr<ID3D12Resource> output;
};

View file

@ -68,14 +68,12 @@
<ClInclude Include="include\EffectInfo.h" />
<ClInclude Include="include\EffectsService.h" />
<ClInclude Include="include\LocalizationService.h" />
<ClInclude Include="include\ShaderEffectParser.h" />
<ClInclude Include="ShaderEffectCompilerService.h" />
<ClInclude Include="ShaderEffectDesc.h" />
<ClInclude Include="ShaderEffectDrawer.h" />
<ClInclude Include="GraphicsCaptureFrameSource.h" />
<ClInclude Include="D3D12Context.h" />
<ClInclude Include="include\DirectXHelper.h" />
<ClInclude Include="include\EffectDesc.h" />
<ClInclude Include="include\ScalingOptions.h" />
<ClInclude Include="include\ScalingRuntime.h" />
<ClInclude Include="include\Win32Helper.h" />
@ -87,6 +85,7 @@
<ClInclude Include="Renderer.h" />
<ClInclude Include="ScalingWindow.h" />
<ClInclude Include="FrameRingBuffer.h" />
<ClInclude Include="ShaderEffectParser.h" />
<ClInclude Include="SrcTracker.h" />
<ClInclude Include="StepTimer.h" />
<ClInclude Include="SwapChainPresenter.h" />

View file

@ -33,9 +33,6 @@
</ClInclude>
<ClInclude Include="ScalingWindow.h" />
<ClInclude Include="CursorManager.h" />
<ClInclude Include="include\EffectDesc.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\ScalingOptions.h">
<Filter>Include</Filter>
</ClInclude>
@ -106,9 +103,6 @@
<ClInclude Include="include\EffectInfo.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\ShaderEffectParser.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="ShaderEffectCompilerService.h">
<Filter>Services</Filter>
</ClInclude>
@ -137,6 +131,7 @@
<ClInclude Include="include\LocalizationService.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="ShaderEffectParser.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ScalingRuntime.cpp" />

View file

@ -3,23 +3,23 @@
namespace Magpie {
struct RectHelper {
static bool IsOverlap(const Rect& r1, const Rect& r2) noexcept {
static bool IsOverlap(const RectU& r1, const RectU& r2) noexcept {
return r1.right > r2.left && r1.bottom > r2.top && r1.left < r2.right && r1.top < r2.bottom;
}
static bool Contains(const Rect& r1, const Rect& r2) noexcept {
static bool Contains(const RectU& r1, const RectU& r2) noexcept {
return r1.left <= r2.left && r1.top <= r2.top && r1.right >= r2.right && r1.bottom >= r2.bottom;
}
static bool Contains(const Rect& rect, Point p) noexcept {
static bool Contains(const RectU& rect, PointU p) noexcept {
return p.x >= rect.left && p.x < rect.right && p.y >= rect.top && p.y < rect.bottom;
}
static bool IsEmpty(const Rect& rect) noexcept {
static bool IsEmpty(const RectU& rect) noexcept {
return rect.left == rect.right || rect.top == rect.bottom;
}
static bool Intersect(Rect& result, const Rect& r1, const Rect& r2) noexcept {
static bool Intersect(RectU& result, const RectU& r1, const RectU& r2) noexcept {
// 计算重叠部分
result.left = std::max(r1.left, r2.left);
result.top = std::max(r1.top, r2.top);
@ -30,12 +30,12 @@ struct RectHelper {
return result.left < result.right && result.top < result.bottom;
}
static Rect Union(const Rect& r1, const Rect& r2) noexcept {
return Rect{ std::min(r1.left, r2.left), std::min(r1.top, r2.top),
static RectU Union(const RectU& r1, const RectU& r2) noexcept {
return RectU{ std::min(r1.left, r2.left), std::min(r1.top, r2.top),
std::max(r1.right, r2.right), std::max(r1.bottom, r2.bottom) };
}
static uint32_t CalcArea(const Rect& rect) noexcept {
static uint32_t CalcArea(const RectU& rect) noexcept {
assert(rect.right >= rect.left && rect.bottom >= rect.top);
return (rect.right - rect.left) * (rect.bottom - rect.top);
}

View file

@ -120,12 +120,12 @@ ScalingError Renderer::Initialize(
return ScalingError::ScalingFailedGeneral;
}
const Size rendererSize = {
const SizeU rendererSize = {
uint32_t(rendererRect.right - rendererRect.left),
uint32_t(rendererRect.bottom - rendererRect.top)
};
Size outputSize;
SizeU outputSize;
SimpleTask<bool> task;
_frameProducer.InitializeAsync(
_d3d12Context, _colorInfo, hMonitor, srcRect, rendererSize, outputSize, task);
@ -239,12 +239,12 @@ void Renderer::OnResized(const RECT& rendererRect, RECT& destRect) noexcept {
return;
}
const Size rendererSize = {
const SizeU rendererSize = {
uint32_t(rendererRect.right - rendererRect.left),
uint32_t(rendererRect.bottom - rendererRect.top)
};
Size outputSize;
SizeU outputSize;
SimpleTask<HRESULT> task;
_frameProducer.OnResizedAsync(rendererSize, outputSize, task);
@ -524,7 +524,7 @@ HRESULT Renderer::_RenderImpl(bool waitForGpu) noexcept {
_graphicsContext.SetRootSignature(_copyRootSignature.get());
const Size rendererSize = _presenter->GetSize();
const SizeU rendererSize = _presenter->GetSize();
{
float outputWidth = float(_outputRect.right - _outputRect.left);
@ -593,9 +593,9 @@ HRESULT Renderer::_RenderImpl(bool waitForGpu) noexcept {
return S_OK;
}
void Renderer::_UpdateOutputRect(Size outputSize) noexcept {
void Renderer::_UpdateOutputRect(SizeU outputSize) noexcept {
// TODO: 窗口模式缩放始终填充画面
const Size rendererSize = _presenter->GetSize();
const SizeU rendererSize = _presenter->GetSize();
OutputAlignment alignment = ScalingWindow::Get().Options().outputAlignment;
using enum OutputAlignment;

View file

@ -34,7 +34,7 @@ public:
bool* waitingForFirstFrame = nullptr
) noexcept;
const Rect& GetOutputRect() const noexcept {
const RectU& GetOutputRect() const noexcept {
return _outputRect;
}
@ -73,7 +73,7 @@ private:
HRESULT _RenderImpl(bool waitForGpu = false) noexcept;
void _UpdateOutputRect(Size outputSize) noexcept;
void _UpdateOutputRect(SizeU outputSize) noexcept;
bool _CheckResult(bool success, std::string_view errorMsg) noexcept;
@ -87,7 +87,7 @@ private:
winrt::DisplayInformation _displayInfo{ nullptr };
winrt::DisplayInformation::AdvancedColorInfoChanged_revoker _acInfoChangedRevoker;
Rect _outputRect{};
RectU _outputRect{};
// 由多个 D3D12Context 共享
DescriptorHeap _csuDescriptorHeap;

View file

@ -1,6 +1,5 @@
#pragma once
#include "SmallVector.h"
#include <variant>
namespace Magpie {
@ -39,7 +38,6 @@ enum class EffectSamplerAddressType {
};
struct ShaderEffectSamplerDesc {
std::string name;
EffectSamplerFilterType filterType = EffectSamplerFilterType::Point;
EffectSamplerAddressType addressType = EffectSamplerAddressType::Clamp;
};
@ -51,41 +49,25 @@ enum class ShaderEffectPassFlags {
DEFINE_ENUM_FLAG_OPERATORS(ShaderEffectPassFlags)
struct ShaderEffectPassDesc {
winrt::com_ptr<ID3DBlob> byteCode;
// 0: INPUT
// 1: OUTPUT
// 2+: 中间纹理
SmallVector<uint32_t> inputs;
SmallVector<uint32_t> outputs;
std::array<uint32_t, 3> numThreads{};
Size blockSize{};
SizeU blockSize{};
ShaderEffectPassFlags flags = ShaderEffectPassFlags::None;
// 用于在叠加层中显示
std::string desc;
};
enum class ShaderEffectFlags {
None = 0,
UseDynamic = 1,
// 用于在叠加层中显示
UseFP16 = 1 << 1
};
DEFINE_ENUM_FLAG_OPERATORS(ShaderEffectFlags)
struct ShaderEffectDesc {
std::pair<std::string, std::string> outputSizeExprs;
std::vector<std::variant<float, int>> params;
// 不包含 INPUT 和 OUTPUT
std::vector<ShaderEffectTextureDesc> textures;
std::vector<ShaderEffectSamplerDesc> samplers;
std::vector<ShaderEffectPassDesc> passes;
float minFrameRate = 0.0f;
ShaderEffectFlags flags = ShaderEffectFlags::None;
// 用于在叠加层中显示
std::string name;
SmallVector<ShaderEffectTextureDesc, 0> textures;
SmallVector<ShaderEffectSamplerDesc> samplers;
SmallVector<ShaderEffectPassDesc, 0> passes;
};
}

View file

@ -1,5 +1,6 @@
#include "pch.h"
#include "ShaderEffectDrawer.h"
#include "EffectsService.h"
namespace Magpie {
@ -12,13 +13,17 @@ bool ShaderEffectDrawer::Initialize(
bool ShaderEffectDrawer::Bind(
ID3D12Resource* /*inputResource*/,
Size /*inputSize*/,
SizeU /*inputSize*/,
const ColorInfo& /*colorInfo*/,
Size& /*outputSize*/
SizeU& /*outputSize*/
) noexcept {
return false;
}
bool ShaderEffectDrawer::IsReady() noexcept {
return false;
}
HRESULT ShaderEffectDrawer::Draw(
ComputeContext& /*computeContext*/,
uint32_t /*inputSrvOffset*/,

View file

@ -14,11 +14,13 @@ public:
bool Bind(
ID3D12Resource* inputResource,
Size inputSize,
SizeU inputSize,
const ColorInfo& colorInfo,
Size& outputSize
SizeU& outputSize
) noexcept override;
bool IsReady() noexcept override;
HRESULT Draw(
ComputeContext& computeContext,
uint32_t inputSrvOffset,

View file

@ -432,10 +432,41 @@ static bool ResolveHeaderSortName(
static bool ResolveHeaderUse(
std::string_view& source,
ParserState& state,
void*
void* data
) noexcept {
std::string_view flags;
return GetNextStringUntilLineEnd<false>(source, state, flags);
if (!GetNextStringUntilLineEnd<false>(source, state, flags)) {
return false;
}
static constexpr std::array FLAG_INFOS = {
std::make_pair("DYNAMIC", EffectInfoFlags::UseDynamic)
};
std::bitset<FLAG_INFOS.size()> processed;
for (std::string_view& token : StrHelper::Split(flags, ',')) {
StrHelper::Trim(token);
std::string flag = StrHelper::ToUpperCase(token);
auto it = std::find_if(FLAG_INFOS.begin(), FLAG_INFOS.end(), [&](const auto& flagInfo) {
return flagInfo.first == flag;
});
if (it != FLAG_INFOS.end()) {
size_t idx = it - FLAG_INFOS.begin();
if (processed[idx]) {
return false;
}
processed[idx] = true;
((EffectInfo*)data)->flags |= it->second;
} else {
Logger::Get().Warn(StrHelper::Concat("未知的 USE 标志: ", token));
}
}
return true;
}
static bool ResolveHeaderCapability(
@ -449,9 +480,7 @@ static bool ResolveHeaderCapability(
}
static constexpr std::array FLAG_INFOS = {
// 以下为必需
std::make_pair("FP16", EffectInfoFlags::SupportFP16),
// 以下为可选
std::make_pair("ADVANCEDCOLOR", EffectInfoFlags::SupportAdvancedColor)
};
@ -474,7 +503,7 @@ static bool ResolveHeaderCapability(
((EffectInfo*)data)->flags |= it->second;
} else {
Logger::Get().Warn(StrHelper::Concat("使用了未知 CAPABILITY 标志: ", token));
Logger::Get().Warn(StrHelper::Concat("未知 CAPABILITY 标志: ", token));
}
}
@ -681,7 +710,12 @@ static bool ResolveParameter(
return false;
}
return source.empty();
if (!source.empty()) {
SetGeneralParseError(state, source, "\n");
return false;
}
return true;
}
std::string ShaderEffectParser::ParseForInfo(
@ -830,8 +864,8 @@ std::string ShaderEffectParser::ParseForInfo(
return std::move(state.errorMsg);
}
bool ShaderEffectParser::ParseForDesc(
std::string&& name,
std::string ShaderEffectParser::ParseForDesc(
std::string_view name,
std::string&& source,
std::string&& workingFolder,
const ShaderEffectParserOptions& /*options*/,
@ -840,7 +874,6 @@ bool ShaderEffectParser::ParseForDesc(
) noexcept {
assert(!name.empty() && !source.empty() && !workingFolder.empty());
effectDesc.name = std::move(name);
effectSource.workingFolder = std::move(workingFolder);
ParserState state = {
@ -854,7 +887,7 @@ bool ShaderEffectParser::ParseForDesc(
}
// std::string_view sourceView(source);
return false;
return std::move(state.errorMsg);
}
}

View file

@ -13,9 +13,8 @@ enum class ShaderEffectParserFlags {
DEFINE_ENUM_FLAG_OPERATORS(ShaderEffectParserFlags)
struct ShaderEffectParserOptions {
// 只在效果存在参数时影响字节码。为空表示不内联
// 为空表示不内联
const phmap::flat_hash_map<std::string, float>* inlineParams = nullptr;
// 始终影响字节码
D3D_SHADER_MODEL shaderModel = D3D_SHADER_MODEL_5_1;
ShaderEffectParserFlags flags = ShaderEffectParserFlags::None;
};
@ -36,8 +35,8 @@ struct ShaderEffectParser {
struct EffectInfo& effectInfo
) noexcept;
static bool ParseForDesc(
std::string&& name,
static std::string ParseForDesc(
std::string_view name,
std::string&& source,
std::string&& workingFolder,
const ShaderEffectParserOptions& options,

View file

@ -29,7 +29,7 @@ SwapChainPresenter::~SwapChainPresenter() noexcept {
bool SwapChainPresenter::Initialize(
D3D12Context& d3d12Context,
HWND hwndAttach,
Size size,
SizeU size,
const ColorInfo& colorInfo
) noexcept {
_d3d12Context = &d3d12Context;
@ -318,7 +318,7 @@ HRESULT SwapChainPresenter::EndFrame(bool waitForGpu) noexcept {
return S_OK;
}
HRESULT SwapChainPresenter::OnResized(Size size) noexcept {
HRESULT SwapChainPresenter::OnResized(SizeU size) noexcept {
assert(size.width > 0 && size.height > 0 && size != _size);
_size = size;

View file

@ -15,7 +15,7 @@ public:
bool Initialize(
D3D12Context& graphicContext,
HWND hwndAttach,
Size size,
SizeU size,
const ColorInfo& colorInfo
) noexcept;
@ -28,9 +28,9 @@ public:
HRESULT EndFrame(bool waitForGpu = false) noexcept;
Size GetSize() const noexcept { return _size; }
SizeU GetSize() const noexcept { return _size; }
HRESULT OnResized(Size size) noexcept;
HRESULT OnResized(SizeU size) noexcept;
void OnResizeStarted() noexcept;
@ -49,7 +49,7 @@ private:
wil::unique_event_nothrow _frameLatencyWaitableObject;
std::vector<winrt::com_ptr<ID3D12Resource>> _frameBuffers;
Size _size{};
SizeU _size{};
uint32_t _bufferCount = 0;
uint32_t _rtvBaseOffset = std::numeric_limits<uint32_t>::max();
uint32_t _rawRtvBaseOffset = std::numeric_limits<uint32_t>::max();

View file

@ -1,112 +0,0 @@
#pragma once
#include "SmallVector.h"
#include <d3dcommon.h>
#include <variant>
namespace Magpie {
enum class EffectIntermediateTextureFormat {
R32G32B32A32_FLOAT,
R16G16B16A16_FLOAT,
R16G16B16A16_UNORM,
R16G16B16A16_SNORM,
R32G32_FLOAT,
R10G10B10A2_UNORM,
R11G11B10_FLOAT,
R8G8B8A8_UNORM,
R8G8B8A8_SNORM,
R16G16_FLOAT,
R16G16_UNORM,
R16G16_SNORM,
R32_FLOAT,
R8G8_UNORM,
R8G8_SNORM,
R16_FLOAT,
R16_UNORM,
R16_SNORM,
R8_UNORM,
R8_SNORM,
UNKNOWN
};
struct EffectIntermediateTextureDesc {
std::pair<std::string, std::string> sizeExpr;
EffectIntermediateTextureFormat format = EffectIntermediateTextureFormat::UNKNOWN;
std::string name;
std::string source;
};
enum class EffectSamplerFilterType {
Linear,
Point
};
enum class EffectSamplerAddressType {
Clamp,
Wrap
};
struct EffectSamplerDesc {
EffectSamplerFilterType filterType = EffectSamplerFilterType::Linear;
EffectSamplerAddressType addressType = EffectSamplerAddressType::Clamp;
std::string name;
};
template <typename T>
struct EffectConstant {
T defaultValue;
T minValue;
T maxValue;
T step;
};
struct EffectParameterDesc {
std::string name;
std::string label;
std::variant<EffectConstant<float>, EffectConstant<int>> constant;
};
struct EffectPassFlags {
static constexpr uint32_t PSStyle = 1;
};
struct EffectPassDesc {
winrt::com_ptr<ID3DBlob> cso;
SmallVector<uint32_t> inputs;
SmallVector<uint32_t> outputs;
std::array<uint32_t, 3> numThreads{};
std::pair<uint32_t, uint32_t> blockSize{};
std::string desc;
uint32_t flags = 0; // EffectPassFlags
};
struct EffectFlags {
// 效果本身的属性
static constexpr uint32_t UseDynamic = 1;
static constexpr uint32_t UseMulAdd = 1 << 1;
static constexpr uint32_t SupportFP16 = 1 << 2;
// 编译赋予的属性
static constexpr uint32_t InlineParams = 1 << 16;
static constexpr uint32_t FP16 = 1 << 17;
};
struct EffectDesc {
const std::pair<std::string, std::string>& GetOutputSizeExpr() const noexcept {
return textures[1].sizeExpr;
}
std::string name;
std::string sortName; // 仅供 UI 使用
std::vector<EffectParameterDesc> params;
// 0: INPUT
// 1: OUTPUT
// > 1: 中间纹理
std::vector<EffectIntermediateTextureDesc> textures;
std::vector<EffectSamplerDesc> samplers;
std::vector<EffectPassDesc> passes;
uint32_t flags = 0; // EffectFlags
};
}

View file

@ -16,6 +16,7 @@ enum class EffectInfoFlags {
None,
SupportFP16 = 1,
SupportAdvancedColor = 1 << 1,
UseDynamic = 1 << 2
};
DEFINE_ENUM_FLAG_OPERATORS(EffectInfoFlags)
@ -25,6 +26,8 @@ struct EffectInfo {
std::vector<EffectInfoParameter> params;
// 0 表示可以自由缩放
uint32_t scaleFactor = 0;
// 0 表示不限制
uint32_t minFrameRate = 0;
EffectInfoFlags flags = EffectInfoFlags::None;
};

View file

@ -1,6 +1,7 @@
#pragma once
#include <parallel_hashmap/phmap.h>
#include "EffectInfo.h"
#include "../ShaderEffectDesc.h"
#include <parallel_hashmap/phmap.h>
namespace Magpie {
@ -20,8 +21,17 @@ public:
const std::vector<EffectInfo>& GetEffects() noexcept;
// 由于 WinUI 使用 UTF-16这里也以 UTF-16 作为参数以减少编码转换
const EffectInfo* GetEffect(std::wstring_view name) noexcept;
const EffectInfo* GetEffect(std::string_view name) noexcept;
std::string SubmitCompileShaderEffectTask(
std::string_view effectName,
const phmap::flat_hash_map<std::string, float>* inlineParams,
D3D_SHADER_MODEL shaderModel,
bool isFP16Enabled,
bool isAdvancedColorEnabled
) noexcept;
bool GetTaskResult(std::string taskKey, const ShaderEffectDesc* &effectDesc) noexcept;
private:
EffectsService() = default;
@ -29,7 +39,15 @@ private:
void _WaitForInitialize() noexcept;
std::vector<EffectInfo> _effects;
phmap::flat_hash_map<std::wstring, uint32_t> _effectsMap;
phmap::flat_hash_map<std::string_view, uint32_t> _effectsMap;
struct _ShaderEffectMemCacheItem {
ShaderEffectDesc effectDesc;
// UINT_MAX 表示尚未编译完成
uint32_t lastAccess = std::numeric_limits<uint32_t>::max();
};
phmap::flat_hash_map<std::string, _ShaderEffectMemCacheItem> _shaderEffectCache;
std::atomic<bool> _initialized = false;
bool _initializedCache = false;
};

View file

@ -55,13 +55,6 @@ enum class OutputAlignment {
COUNT
};
enum class EffectType {
Shader,
// 下面的类型未实现
ONNX,
Extension
};
enum class ScalingType {
Normal, // Scale 表示缩放倍数
Fit, // Scale 表示相对于屏幕能容纳的最大等比缩放的比例
@ -70,7 +63,6 @@ enum class ScalingType {
};
struct EffectOption {
EffectType type;
std::string name;
phmap::flat_hash_map<std::string, float> parameters;
ScalingType scalingType = ScalingType::Normal;

View file

@ -76,41 +76,6 @@ enum class ComponentState {
Error
};
struct Size {
uint32_t width;
uint32_t height;
bool operator==(const Size&) const noexcept = default;
explicit operator SIZE() const noexcept {
return { (LONG)width,(LONG)height };
}
};
struct Point {
uint32_t x;
uint32_t y;
bool operator==(const Point&) const noexcept = default;
explicit operator POINT() const noexcept {
return { (LONG)x,(LONG)y };
}
};
struct Rect {
uint32_t left;
uint32_t top;
uint32_t right;
uint32_t bottom;
bool operator==(const Rect& other) const = default;
explicit operator RECT() const noexcept {
return { (LONG)left,(LONG)top,(LONG)right,(LONG)bottom };
}
};
struct ColorInfo {
winrt::AdvancedColorKind kind = winrt::AdvancedColorKind::StandardDynamicRange;
// HDR 模式下最大亮度1.0 表示 80nit

View file

@ -18,7 +18,6 @@
#include <ShellScalingApi.h>
#include <ShlObj.h>
using namespace winrt;
using namespace winrt::Magpie;
namespace Magpie {
@ -179,8 +178,8 @@ static HRESULT CALLBACK TaskDialogCallback(
static void ShowErrorMessage(const wchar_t* mainInstruction, const wchar_t* content) noexcept {
LocalizationService& ls = LocalizationService::Get();
const hstring errorStr = ls.GetLocalizedString(L"AppSettings_Dialog_Error");
const hstring exitStr = ls.GetLocalizedString(L"AppSettings_Dialog_Exit");
const winrt::hstring errorStr = ls.GetLocalizedString(L"AppSettings_Dialog_Error");
const winrt::hstring exitStr = ls.GetLocalizedString(L"AppSettings_Dialog_Exit");
TASKDIALOG_BUTTON button{ IDCANCEL, exitStr.c_str() };
TASKDIALOGCONFIG tdc{
@ -229,8 +228,8 @@ bool AppSettings::Initialize() noexcept {
logger.Error("读取配置文件失败");
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ReadFailed");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
winrt::hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ReadFailed");
winrt::hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
@ -251,8 +250,8 @@ bool AppSettings::Initialize() noexcept {
Logger::Get().Error(fmt::format("解析配置失败\n\t错误码: {}", (int)doc.GetParseError()));
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_NotValidJson");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
winrt::hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_NotValidJson");
winrt::hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
@ -263,8 +262,8 @@ bool AppSettings::Initialize() noexcept {
Logger::Get().Error("配置文件根元素不是 Object");
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ParseFailed");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
winrt::hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ParseFailed");
winrt::hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
@ -286,12 +285,12 @@ bool AppSettings::Save() noexcept {
return _Save(*this);
}
fire_and_forget AppSettings::SaveAsync() noexcept {
winrt::fire_and_forget AppSettings::SaveAsync() noexcept {
_UpdateWindowPlacement();
// 拷贝当前配置
_AppSettingsData data = *this;
co_await resume_background();
co_await winrt::resume_background();
_Save(data);
}
@ -715,8 +714,8 @@ void AppSettings::_LoadSettings(const rapidjson::GenericObject<true, rapidjson::
if (windowPosNode != root.MemberEnd() && windowPosNode->value.IsObject()) {
auto windowPosObj = windowPosNode->value.GetObj();
Point center{};
Size size{};
winrt::Point center{};
winrt::Size size{};
if (JsonHelper::ReadFloat(windowPosObj, "centerX", center.X, true) &&
JsonHelper::ReadFloat(windowPosObj, "centerY", center.Y, true) &&
JsonHelper::ReadFloat(windowPosObj, "width", size.Width, true) &&

View file

@ -59,7 +59,8 @@ EffectParametersViewModel::EffectParametersViewModel(uint32_t scalingModeIdx, ui
: _scalingModeIdx(scalingModeIdx), _effectIdx(effectIdx)
{
ScalingMode& scalingMode = ScalingModesService::Get().GetScalingMode(_scalingModeIdx);
_effectInfo = EffectsService::Get().GetEffect(scalingMode.effects[_effectIdx].name);
_effectInfo = EffectsService::Get().GetEffect(
StrHelper::UTF16ToUTF8(scalingMode.effects[_effectIdx].name));
phmap::flat_hash_map<std::wstring, float>& params = _Data();

View file

@ -26,7 +26,7 @@ ScalingModeEffectItem::ScalingModeEffectItem(uint32_t scalingModeIdx, uint32_t e
{
EffectItem& data = _Data();
_effectInfo = EffectsService::Get().GetEffect(data.name);
_effectInfo = EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(data.name));
if (_effectInfo) {
_name = EffectHelper::GetDisplayName(data.name);

View file

@ -215,7 +215,8 @@ void ScalingModeItem::AddEffect(const hstring& fullName) {
EffectItem& effect = _Data().effects.emplace_back();
effect.name = fullName;
const EffectInfo* effectInfo = EffectsService::Get().GetEffect(fullName);
const EffectInfo* effectInfo =
EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(fullName));
assert(effectInfo);
if (effectInfo->scaleFactor == 0) {
// 支持缩放的效果默认等比缩放到充满屏幕
@ -264,7 +265,7 @@ hstring ScalingModeItem::Description() const noexcept {
result.append(L" > ");
}
if (EffectsService::Get().GetEffect(effect.name) != nullptr) {
if (EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(effect.name))) {
result += EffectHelper::GetDisplayName(effect.name);
} else {
result += L'(';
@ -282,7 +283,7 @@ bool ScalingModeItem::HasUnkownEffects() const noexcept {
}
for (const EffectItem& effect : _Data().effects) {
if (!EffectsService::Get().GetEffect(effect.name)) {
if (!EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(effect.name))) {
return true;
}
}

View file

@ -135,13 +135,15 @@ void ScalingModesPage::_BuildEffectMenu() noexcept {
hstring name1 = unbox_value<hstring>(l.try_as<MenuFlyoutItem>().Tag());
hstring name2 = unbox_value<hstring>(r.try_as<MenuFlyoutItem>().Tag());
const EffectInfo* effectInfo1 = EffectsService::Get().GetEffect(name1);
const EffectInfo* EffectInfo = EffectsService::Get().GetEffect(name2);
const EffectInfo* effectInfo1 =
EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(name1));
const EffectInfo* effectInfo2 =
EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(name2));
const std::string& sortName1 =
effectInfo1->sortName.empty() ? effectInfo1->name : effectInfo1->sortName;
const std::string& sortName2 =
EffectInfo->sortName.empty() ? EffectInfo->name : EffectInfo->sortName;
effectInfo2->sortName.empty() ? effectInfo2->name : effectInfo2->sortName;
return sortName1 < sortName2;
});

View file

@ -1,15 +1,10 @@
#include "pch.h"
#include "AppSettings.h"
#include "EffectHelper.h"
#include "EffectsService.h"
#include "JsonHelper.h"
#include "ScalingMode.h"
#include "ScalingModesService.h"
#include "StrHelper.h"
using namespace ::Magpie;
using namespace winrt;
namespace Magpie {
ScalingMode& ScalingModesService::GetScalingMode(uint32_t idx) {

View file

@ -331,7 +331,7 @@ ScalingError ScalingService::_StartScaleImpl(HWND hWnd, const Profile& profile,
return ScalingError::InvalidScalingMode;
} else {
for (const EffectItem& effect : effects) {
if (!EffectsService::Get().GetEffect(effect.name)) {
if (!EffectsService::Get().GetEffect(StrHelper::UTF16ToUTF8(effect.name))) {
// 存在无法解析的效果
return ScalingError::InvalidScalingMode;
}

View file

@ -53,4 +53,39 @@ uint32_t Measure(const Fn& func) noexcept {
return (uint32_t)dura.count();
}
struct SizeU {
uint32_t width;
uint32_t height;
bool operator==(const SizeU&) const noexcept = default;
explicit operator SIZE() const noexcept {
return { (LONG)width,(LONG)height };
}
};
struct PointU {
uint32_t x;
uint32_t y;
bool operator==(const PointU&) const noexcept = default;
explicit operator POINT() const noexcept {
return { (LONG)x,(LONG)y };
}
};
struct RectU {
uint32_t left;
uint32_t top;
uint32_t right;
uint32_t bottom;
bool operator==(const RectU& other) const = default;
explicit operator RECT() const noexcept {
return { (LONG)left,(LONG)top,(LONG)right,(LONG)bottom };
}
};
}