feat: 新版 FX 解析器 (p5)

This commit is contained in:
Xu 2026-03-30 13:33:27 +08:00
commit d0d17311c3
13 changed files with 365 additions and 153 deletions

View file

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Magpie::SmallVectorImpl&lt;*&gt;">
<DisplayString IncludeView ="elt0" Condition="Size == 0"></DisplayString>

View file

@ -4,6 +4,7 @@ namespace Magpie {
class D3D12Context;
struct EffectOption;
struct EffectInfo;
class ComputeContext;
class EffectDrawerBase {
@ -14,17 +15,12 @@ public:
virtual ~EffectDrawerBase() noexcept = default;
virtual bool Initialize(
virtual const EffectInfo* Initialize(
D3D12Context& d3d12Context,
const EffectOption& effectOption
) noexcept = 0;
virtual bool Bind(
ID3D12Resource* inputResource,
SizeU inputSize,
const ColorInfo& colorInfo,
SizeU& outputSize
) noexcept = 0;
virtual bool Bind(SizeU inputSize, const ColorInfo& colorInfo) noexcept = 0;
virtual bool IsReady() noexcept = 0;

View file

@ -5,35 +5,124 @@
#include "D3D12Context.h"
#include "Logger.h"
#include "ScalingWindow.h"
#include "StrHelper.h"
#include "ShaderEffectDrawer.h"
#include "EffectInfo.h"
namespace Magpie {
EffectsDrawer::~EffectsDrawer() noexcept {}
static SizeU CalcOutputSize(
uint32_t scaleFactor,
SizeU inputSize,
SizeU rendererSize,
const EffectOption& effectOption
) noexcept {
if (scaleFactor != 0) {
return SizeU{ inputSize.width * scaleFactor, inputSize.height * scaleFactor };
}
// 支持自由缩放
switch (effectOption.scalingType) {
case ScalingType::Normal:
{
return SizeU{
(uint32_t)std::lroundf(inputSize.width * effectOption.scale.first),
(uint32_t)std::lroundf(inputSize.height * effectOption.scale.second)
};
}
case ScalingType::Absolute:
{
return SizeU{
(uint32_t)std::lroundf(effectOption.scale.first),
(uint32_t)std::lroundf(effectOption.scale.second)
};
}
case ScalingType::Fit:
{
// 窗口模式缩放时将缩放比例为 1 的 Fit 视为 Fill。此时缩放确保是等比例的但由于舍入
// 可能存在一个像素的误差。考虑长 100 高 50 的矩形窗口,长调整到 101 时高将四舍五入到
// 51再将长调整到 102 高仍是 51Fit 的计算方式会使这两次调整中有一次存在黑边,而且
// 也会影响后续计算是否追加 Bicubic。
bool treatFitAsFill = ScalingWindow::Get().Options().IsWindowedMode() &&
IsApprox(effectOption.scale.first, 1.0f) &&
IsApprox(effectOption.scale.second, 1.0f);
if (!treatFitAsFill) {
float fillScale = std::min(
float(rendererSize.width) / inputSize.width,
float(rendererSize.height) / inputSize.height
);
return SizeU{
(uint32_t)std::lroundf(inputSize.width * fillScale * effectOption.scale.first),
(uint32_t)std::lroundf(inputSize.height * fillScale * effectOption.scale.second)
};
}
[[fallthrough]];
}
default:
assert(effectOption.scalingType == ScalingType::Fit ||
effectOption.scalingType == ScalingType::Fill);
return rendererSize;
}
}
bool EffectsDrawer::Initialize(
D3D12Context& d3d12Context,
const ColorInfo& colorInfo,
SizeU inputSize,
SizeU rendererSize
SizeU rendererSize,
SizeU& outputSize
) noexcept {
_d3d12Context = &d3d12Context;
_isScRGB = colorInfo.kind != winrt::AdvancedColorKind::StandardDynamicRange;
_inputSize = inputSize;
ID3D12Device5* device = d3d12Context.GetDevice();
const ScalingOptions& options = ScalingWindow::Get().Options();
if (ScalingWindow::Get().Options().IsWindowedMode()) {
_outputSize = rendererSize;
} else {
const float fillScale = std::min(
float(rendererSize.width) / inputSize.width,
float(rendererSize.height) / inputSize.height
);
_outputSize.width = std::lroundf(inputSize.width * fillScale);
_outputSize.height = std::lroundf(inputSize.height * fillScale);
uint32_t effectCount = (uint32_t)options.effects.size();
_effectDatas.resize(effectCount);
outputSize = inputSize;
for (uint32_t i = 0; i < effectCount; ++i) {
auto& effectData = _effectDatas[i];
const auto& effectOption = options.effects[i];
effectData.drawer = std::make_unique<ShaderEffectDrawer>();
effectData.effectInfo = effectData.drawer->Initialize(d3d12Context, options.effects[i]);
if (!effectData.effectInfo) {
return false;
}
outputSize = CalcOutputSize(
effectData.effectInfo->scaleFactor, outputSize, rendererSize, effectOption);
effectData.outputSize = outputSize;
}
_catmullRomDrawer.emplace();
_catmullRomDrawer->Initialize(d3d12Context);
// 如果输出尺寸比渲染区域更大则使用 CatmullRom 等比缩小,更小时不放大
if (outputSize.width > rendererSize.width || outputSize.height > rendererSize.height) {
float scaleX = float(rendererSize.width) / outputSize.width;
float scaleY = float(rendererSize.height) / outputSize.height;
if (scaleX <= scaleY) {
outputSize.width = rendererSize.width;
outputSize.height = std::lroundf(inputSize.height * scaleX);
} else {
outputSize.width = std::lroundf(inputSize.width * scaleY);
outputSize.height = rendererSize.height;
}
}
_outputSize = outputSize;
for (auto& effectData : _effectDatas) {
if (!effectData.drawer->Bind(outputSize, colorInfo)) {
return false;
}
}
// CatmullRomDrawer 将在渲染时按需创建 PSO初始化无代价
_catmullRomDrawer.Initialize(d3d12Context);
{
// 每帧两个时间戳
@ -103,7 +192,7 @@ HRESULT EffectsDrawer::Draw(
//commandList->EndQuery(_queryHeap.get(), D3D12_QUERY_TYPE_TIMESTAMP, queryHeapIndex);
_catmullRomDrawer->Draw(
_catmullRomDrawer.Draw(
computeContext, _inputSize, _outputSize, inputSrvOffset, outputUavOffset, false);
// commandList->EndQuery(_queryHeap.get(), D3D12_QUERY_TYPE_TIMESTAMP, queryHeapIndex + 1);
@ -113,8 +202,9 @@ HRESULT EffectsDrawer::Draw(
return S_OK;
}
void EffectsDrawer::OnResized(SizeU rendererSize) noexcept {
void EffectsDrawer::OnResized(SizeU rendererSize, SizeU& outputSize) noexcept {
_outputSize = rendererSize;
outputSize = _outputSize;
}
void EffectsDrawer::OnColorInfoChanged(const ColorInfo& colorInfo) noexcept {

View file

@ -1,9 +1,12 @@
#pragma once
#include "CatmullRomDrawer.h"
#include "SmallVector.h"
namespace Magpie {
class ComputeContext;
class EffectDrawerBase;
struct EffectInfo;
class EffectsDrawer {
public:
@ -11,11 +14,14 @@ public:
EffectsDrawer(const EffectsDrawer&) = delete;
EffectsDrawer(EffectsDrawer&&) = delete;
~EffectsDrawer() noexcept;
bool Initialize(
D3D12Context& d3d12Context,
const ColorInfo& colorInfo,
SizeU inputSize,
SizeU rendererSize
SizeU rendererSize,
SizeU& outputSize
) noexcept;
HRESULT Draw(
@ -31,7 +37,7 @@ public:
return _outputSize;
}
void OnResized(SizeU rendererSize) noexcept;
void OnResized(SizeU rendererSize, SizeU& outputSize) noexcept;
void OnColorInfoChanged(const ColorInfo& colorInfo) noexcept;
@ -41,7 +47,14 @@ private:
SizeU _inputSize{};
SizeU _outputSize{};
std::optional<CatmullRomDrawer> _catmullRomDrawer;
struct _EffectData {
std::unique_ptr<EffectDrawerBase> drawer;
const EffectInfo* effectInfo;
SizeU outputSize;
};
SmallVector<_EffectData> _effectDatas;
CatmullRomDrawer _catmullRomDrawer;
winrt::com_ptr<ID3D12QueryHeap> _queryHeap;
winrt::com_ptr<ID3D12Resource> _queryResultBuffer;

View file

@ -109,70 +109,85 @@ static std::string GetCacheFileName(
ShaderEffectParserFlags flags,
uint64_t hash
) {
// 缓存文件的命名: {效果名}_{shader model(4)}_{标志位(4)}_{哈希(16)}
return fmt::format("{}\\{}_{:04x}_{:04x}_{:016x}",
// 缓存文件的命名: {效果名}_{shader model(2)}{标志位(4)}{哈希(16)}
return fmt::format("{}\\{}_{:02x}{:04x}{:016x}",
StrHelper::UTF16ToUTF8(CommonSharedConstants::CACHE_DIR),
linearEffectName, (uint32_t)shaderModel, (uint32_t)flags, hash);
linearEffectName, (uint16_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
bool isFP16Supported,
bool isAdvancedColorSupported
) noexcept {
_WaitForInitialize();
std::string cacheKey;
auto it = _effectsMap.find(effectName);
if (it == _effectsMap.end()) {
return cacheKey;
}
const EffectInfo& effectInfo = _effects[it->second];
std::string source;
{
std::wstring fileName = StrHelper::Concat(
CommonSharedConstants::EFFECTS_DIR, L"\\", StrHelper::UTF8ToUTF16(effectName), L".hlsl");
Win32Helper::ReadTextFile(fileName.c_str(), source);
if (!Win32Helper::ReadTextFile(fileName.c_str(), source)) {
return cacheKey;
}
}
ShaderEffectParserOptions options = {
.inlineParams = inlineParams,
.shaderModel = shaderModel
};
if (isFP16Enabled) {
if (isFP16Supported && bool(effectInfo.flags & EffectInfoFlags::SupportFP16)) {
options.flags |= ShaderEffectParserFlags::EnableFP16;
}
if (isAdvancedColorEnabled) {
if (isAdvancedColorSupported && bool(effectInfo.flags & EffectInfoFlags::SupportAdvancedColor)) {
options.flags |= ShaderEffectParserFlags::EnableAdvancedColor;
}
// 传给 ParseForDesc 的几个参数都会影响字节码,其中 shaderModel 和 flags 不需要参与哈希,
// 它们影响缓存键,即缓存文件名。
std::string byteCodeKey;
byteCodeKey.append(source);
// shaderModel 和 flags 不参与哈希,它们决定缓存键(也是缓存文件名)
uint64_t hash = rapidhash(source.data(), source.size());
if (inlineParams) {
for (const auto& pair : *inlineParams) {
byteCodeKey.append(fmt::format("|{}|{}", pair.first, std::lroundf(pair.second * 10000)));
for (const EffectInfoParameter& param : effectInfo.params) {
if (param.name == pair.first) {
// 将参数值归一化然后保留 4 位精度
long normValue = std::lroundf((pair.second - param.minValue) /
(param.maxValue - param.minValue) * 10000);
hash = phmap::HashState().combine(hash, pair.first, normValue);
break;
}
}
}
}
uint64_t hash = rapidhash(byteCodeKey.data(), byteCodeKey.size());
std::string cacheKey = GetCacheFileName(
cacheKey = GetCacheFileName(
GetLinearEffectName(effectName), shaderModel, options.flags, hash);
if (!_shaderEffectCache.contains(cacheKey)) {
_shaderEffectCache.emplace(cacheKey, _ShaderEffectMemCacheItem{});
// _shaderEffectCache.emplace(cacheKey, _ShaderEffectMemCacheItem{});
ShaderEffectDesc effectDesc;
ShaderEffectSource effectSource;
std::string errorMsg = ShaderEffectParser::ParseForDesc(
effectName,
effectInfo,
std::move(source),
StrHelper::UTF16ToUTF8(CommonSharedConstants::EFFECTS_DIR),
options,
effectDesc,
effectSource
);
if (errorMsg.empty()) {
} else {
if (!errorMsg.empty()) {
// 解析失败
_shaderEffectCache.erase(cacheKey);
cacheKey.clear();
return cacheKey;
}
}
@ -195,6 +210,9 @@ bool EffectsService::GetTaskResult(std::string taskKey, const ShaderEffectDesc*&
return &it->second.effectDesc;
}
void EffectsService::CleanCache(bool /*clearAll*/) noexcept {
}
void EffectsService::_WaitForInitialize() noexcept {
if (_initializedCache) {
return;

View file

@ -116,8 +116,7 @@ void FrameProducer::OnResizedAsync(
return;
}
_effectsDrawer.OnResized(rendererSize);
outputSize = _effectsDrawer.GetOutputSize();
_effectsDrawer.OnResized(rendererSize, outputSize);
hr = _frameRingBuffer.OnResized(outputSize);
if (!_CheckResult(hr, "FrameRingBuffer::OnResized 失败")) {
@ -370,12 +369,12 @@ bool FrameProducer::_Initialize(
uint32_t(srcRect.bottom - srcRect.top)
};
if (!_effectsDrawer.Initialize(_d3d12Context, colorInfo, inputSize, rendererSize)) {
if (!_effectsDrawer.Initialize(_d3d12Context, colorInfo, inputSize, rendererSize, outputSize)) {
Logger::Get().Error("EffectsDrawer::Initialize 失败");
return false;
}
outputSize = _effectsDrawer.GetOutputSize();
assert(outputSize.width <= rendererSize.width && outputSize.height <= rendererSize.height);
if (!_frameRingBuffer.Initialize(_d3d12Context, outputSize, colorInfo)) {
Logger::Get().Error("初始化 FrameRingBuffer 失败");

View file

@ -121,7 +121,6 @@
<ClInclude Include="CommandContext.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Renderer.h" />
<ClInclude Include="RectHelper.h">
<Filter>Helpers</Filter>
</ClInclude>
@ -132,6 +131,9 @@
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="ShaderEffectParser.h" />
<ClInclude Include="Renderer.h">
<Filter>Render</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ScalingRuntime.cpp" />
@ -201,13 +203,15 @@
<ClCompile Include="CommandContext.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Renderer.cpp" />
<ClCompile Include="LocalizationService.cpp">
<Filter>Services</Filter>
</ClCompile>
<ClCompile Include="EffectsService.cpp">
<Filter>Services</Filter>
</ClCompile>
<ClCompile Include="Renderer.cpp">
<Filter>Render</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<FxCompile Include="shaders\MaskedCursorPS.hlsl">

View file

@ -1,16 +1,17 @@
#include "pch.h"
#include "Renderer.h"
#include "DebugInfo.h"
#include "DirectXHelper.h"
#include "EffectDrawerBase.h"
#include "FrameProducer.h"
#include "GraphicsCaptureFrameSource.h"
#include "Logger.h"
#include "Renderer.h"
#include "ScalingWindow.h"
#include "SwapChainPresenter.h"
#include "shaders/CopyFrameVS.h"
#include "shaders/CopyFrameVS_SM5.h"
#include "shaders/TextureBlitPS.h"
#include "shaders/TextureBlitPS_SM5.h"
#include "GraphicsCaptureFrameSource.h"
#include "SwapChainPresenter.h"
#include <d3dkmthk.h>
#include <windows.graphics.display.interop.h>

View file

@ -1,23 +1,45 @@
#include "pch.h"
#include "ShaderEffectDrawer.h"
#include "D3D12Context.h"
#include "EffectsService.h"
#include "Logger.h"
#include "ScalingOptions.h"
#include "ScalingWindow.h"
#include "ShaderEffectDrawer.h"
namespace Magpie {
bool ShaderEffectDrawer::Initialize(
D3D12Context& /*d3d12Context*/,
const EffectOption& /*effectOption*/
const EffectInfo* ShaderEffectDrawer::Initialize(
D3D12Context& d3d12Context,
const EffectOption& effectOption
) noexcept {
return false;
_d3d12Context = &d3d12Context;
_effectOption = &effectOption;
const EffectInfo* effectInfo = EffectsService::Get().GetEffect(effectOption.name);
if (!effectInfo) {
Logger::Get().Error("EffectsService::GetEffect 失败");
return nullptr;
}
return effectInfo;
}
bool ShaderEffectDrawer::Bind(
ID3D12Resource* /*inputResource*/,
SizeU /*inputSize*/,
const ColorInfo& /*colorInfo*/,
SizeU& /*outputSize*/
) noexcept {
return false;
bool ShaderEffectDrawer::Bind(SizeU /*inputSize*/, const ColorInfo& colorInfo) noexcept {
const ScalingOptions& options = ScalingWindow::Get().Options();
_compilationTaskId = EffectsService::Get().SubmitCompileShaderEffectTask(
_effectOption->name,
options.IsInlineParams() ? &_effectOption->parameters : nullptr,
_d3d12Context->GetShaderModel(),
_d3d12Context->IsFP16Supported(),
colorInfo.kind != winrt::AdvancedColorKind::StandardDynamicRange
);
if (_compilationTaskId.empty()) {
Logger::Get().Error("EffectsService::SubmitCompileShaderEffectTask 失败");
return false;
}
return true;
}
bool ShaderEffectDrawer::IsReady() noexcept {

View file

@ -7,17 +7,12 @@ class ShaderEffectDrawer : public EffectDrawerBase {
public:
virtual ~ShaderEffectDrawer() noexcept = default;
bool Initialize(
const EffectInfo* Initialize(
D3D12Context& d3d12Context,
const EffectOption& effectOption
) noexcept override;
bool Bind(
ID3D12Resource* inputResource,
SizeU inputSize,
const ColorInfo& colorInfo,
SizeU& outputSize
) noexcept override;
bool Bind(SizeU inputSize, const ColorInfo& colorInfo) noexcept override;
bool IsReady() noexcept override;
@ -26,6 +21,11 @@ public:
uint32_t inputSrvOffset,
uint32_t outputUavOffset
) noexcept override;
private:
D3D12Context* _d3d12Context = nullptr;
const EffectOption* _effectOption = nullptr;
std::string _compilationTaskId;
};
}

View file

@ -23,6 +23,20 @@ struct ParserState {
bool isNewLine;
};
enum class BlockType {
Header,
Parameter,
Texture,
Sampler,
Common,
Pass
};
struct BlockData {
std::string_view source;
uint32_t startLineNumer;
};
static std::string DebugFormat(std::string_view str) noexcept {
return fmt::format("{:?s}", std::span<const char>(str.begin(), str.end()));
}
@ -718,6 +732,61 @@ static bool ResolveParameter(
return true;
}
template <typename Fn>
static bool ResolveBlocks(
std::string_view sourceView,
const Fn& completeCurrentBlock,
ParserState& state
) noexcept {
for (size_t i = 0; i < sourceView.size(); ++i) {
char c = sourceView[i];
if (c == '\n') {
++state.lineNumber;
state.isNewLine = true;
} else if (c == '/') {
bool isComment;
bool isMetaIdicator;
if (!RemoveLeadingComment(sourceView, state, i, isComment, isMetaIdicator)) {
return false;
}
if (isMetaIdicator) {
std::string_view tempSource = sourceView.substr(i + 3);
std::string_view token;
if (!GetNextToken<false, false>(tempSource, state, token)) {
return false;
}
std::string newBlockType = StrHelper::ToUpperCase(token);
size_t newBlockOffset = tempSource.data() - sourceView.data();
// sourceView[i - 1] 是换行符,因此每个区块都以换行结尾。区块开头不包含声明该区块的
// 指令,如果该指令没有参数,此区块就以换行符开头。
if (newBlockType == "PARAMETER") {
completeCurrentBlock(BlockType::Parameter, i, newBlockOffset);
} else if (newBlockType == "TEXTURE") {
completeCurrentBlock(BlockType::Texture, i, newBlockOffset);
} else if (newBlockType == "SAMPLER") {
completeCurrentBlock(BlockType::Sampler, i, newBlockOffset);
} else if (newBlockType == "COMMON") {
completeCurrentBlock(BlockType::Common, i, newBlockOffset);
} else if (newBlockType == "PASS") {
completeCurrentBlock(BlockType::Pass, i, newBlockOffset);
}
// 下个循环会加一
i = newBlockOffset - 1;
state.isNewLine = false;
}
}
}
// 结束最后一个区块。sourceView 以换行符结尾,因此最后一个区块也以换行符结尾。
completeCurrentBlock(BlockType::Header, sourceView.size(), std::numeric_limits<size_t>::max());
return true;
}
std::string ShaderEffectParser::ParseForInfo(
std::string&& name,
std::string&& source,
@ -743,20 +812,6 @@ std::string ShaderEffectParser::ParseForInfo(
return std::move(state.errorMsg);
}
enum class BlockType {
Header,
Parameter,
Texture,
Sampler,
Common,
Pass
};
struct BlockData {
std::string_view source;
uint32_t startLineNumer;
};
BlockData headerBlock{};
SmallVector<BlockData> paramBlocks;
@ -796,55 +851,13 @@ std::string ShaderEffectParser::ParseForInfo(
curBlockStartLineNumber = state.lineNumber;
};
for (size_t i = 0; i < sourceView.size(); ++i) {
char c = sourceView[i];
if (c == '\n') {
++state.lineNumber;
state.isNewLine = true;
} else if (c == '/') {
bool isComment;
bool isMetaIdicator;
if (!RemoveLeadingComment(sourceView, state, i, isComment, isMetaIdicator)) {
return std::move(state.errorMsg);
}
if (isMetaIdicator) {
std::string_view tempSource = sourceView.substr(i + 3);
std::string_view token;
if (!GetNextToken<false, false>(tempSource, state, token)) {
return std::move(state.errorMsg);
}
std::string newBlockType = StrHelper::ToUpperCase(token);
size_t newBlockOffset = tempSource.data() - sourceView.data();
// sourceView[i - 1] 是换行符,因此每个区块都以换行结尾。区块开头不包含声明该区块的
// 指令,如果该指令没有参数,此区块就以换行符开头。
if (newBlockType == "PARAMETER") {
completeCurrentBlock(BlockType::Parameter, i, newBlockOffset);
} else if (newBlockType == "TEXTURE") {
completeCurrentBlock(BlockType::Texture, i, newBlockOffset);
} else if (newBlockType == "SAMPLER") {
completeCurrentBlock(BlockType::Sampler, i, newBlockOffset);
} else if (newBlockType == "COMMON") {
completeCurrentBlock(BlockType::Common, i, newBlockOffset);
} else if (newBlockType == "PASS") {
completeCurrentBlock(BlockType::Pass, i, newBlockOffset);
}
i = newBlockOffset;
state.isNewLine = false;
}
}
if (!ResolveBlocks(sourceView, completeCurrentBlock, state)) {
Logger::Get().Error(StrHelper::Concat("ResolveBlocks 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
}
// 结束最后一个区块。source 以换行符结尾,因此最后一个区块也以换行符结尾。
completeCurrentBlock(BlockType::Header, sourceView.size(), std::numeric_limits<size_t>::max());
state.lineNumber = headerBlock.startLineNumer;
state.isNewLine = false;
if (!ResolveHeader(headerBlock.source, state, effectInfo)) {
Logger::Get().Error(StrHelper::Concat("ResolveHeader 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
@ -854,7 +867,6 @@ std::string ShaderEffectParser::ParseForInfo(
for (size_t i = 0; i < paramBlocks.size(); ++i) {
state.lineNumber = paramBlocks[i].startLineNumer;
state.isNewLine = false;
if (!ResolveParameter(paramBlocks[i].source, state, effectInfo.params[i])) {
Logger::Get().Error(fmt::format("ResolveParameter#{} 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
@ -865,16 +877,13 @@ std::string ShaderEffectParser::ParseForInfo(
}
std::string ShaderEffectParser::ParseForDesc(
std::string_view name,
const EffectInfo& /*effectInfo*/,
std::string&& source,
std::string&& workingFolder,
const ShaderEffectParserOptions& /*options*/,
struct ShaderEffectDesc& effectDesc,
ShaderEffectSource& effectSource
ShaderEffectDesc& /*effectDesc*/,
ShaderEffectSource& /*effectSource*/
) noexcept {
assert(!name.empty() && !source.empty() && !workingFolder.empty());
effectSource.workingFolder = std::move(workingFolder);
assert(!source.empty());
ParserState state = {
.lineNumber = 1,
@ -885,7 +894,65 @@ std::string ShaderEffectParser::ParseForDesc(
if (!source.ends_with('\n')) {
source.push_back('\n');
}
// std::string_view sourceView(source);
std::string_view sourceView(source);
if (!CheckMagic(sourceView, state)) {
Logger::Get().Error(StrHelper::Concat("CheckMagic 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
}
SmallVector<BlockData> textureBlocks;
SmallVector<BlockData> samplerBlocks;
SmallVector<BlockData> commonBlocks;
SmallVector<BlockData> passBlocks;
BlockType curBlockType = BlockType::Header;
size_t curBlockOffset = 0;
uint32_t curBlockStartLineNumber = state.lineNumber;
const auto completeCurrentBlock = [&](
BlockType newBlockType,
size_t curBlockEnd,
size_t newBlockOffset
) {
assert(curBlockOffset < curBlockEnd && curBlockEnd < newBlockOffset);
assert(sourceView[curBlockEnd - 1] == '\n');
switch (curBlockType) {
case BlockType::Header:
case BlockType::Parameter:
break;
case BlockType::Texture:
textureBlocks.push_back(BlockData{
sourceView.substr(curBlockOffset, curBlockEnd - curBlockOffset),curBlockStartLineNumber });
break;
case BlockType::Sampler:
samplerBlocks.push_back(BlockData{
sourceView.substr(curBlockOffset, curBlockEnd - curBlockOffset),curBlockStartLineNumber });
break;
case BlockType::Common:
commonBlocks.push_back(BlockData{
sourceView.substr(curBlockOffset, curBlockEnd - curBlockOffset),curBlockStartLineNumber });
break;
case BlockType::Pass:
passBlocks.push_back(BlockData{
sourceView.substr(curBlockOffset, curBlockEnd - curBlockOffset),curBlockStartLineNumber });
break;
default:
assert(false);
break;
}
curBlockType = newBlockType;
curBlockOffset = newBlockOffset;
curBlockStartLineNumber = state.lineNumber;
};
if (!ResolveBlocks(sourceView, completeCurrentBlock, state)) {
Logger::Get().Error(StrHelper::Concat("ResolveBlocks 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
}
return std::move(state.errorMsg);
}

View file

@ -3,11 +3,12 @@
namespace Magpie {
struct EffectInfo;
struct ShaderEffectDesc;
enum class ShaderEffectParserFlags {
None = 0,
// 只在效果支持 FP16 时影响字节码
EnableFP16 = 1,
// 只在效果支持 scRGB 时影响字节码
EnableAdvancedColor = 1 << 1
};
DEFINE_ENUM_FLAG_OPERATORS(ShaderEffectParserFlags)
@ -21,8 +22,6 @@ struct ShaderEffectParserOptions {
struct ShaderEffectSource {
std::vector<std::string> sources;
// 用于解析 #include
std::string workingFolder;
std::vector<std::pair<std::string, std::string>> macros;
D3D_SHADER_MODEL shaderModel = D3D_SHADER_MODEL_5_1;
};
@ -32,15 +31,14 @@ struct ShaderEffectParser {
static std::string ParseForInfo(
std::string&& name,
std::string&& source,
struct EffectInfo& effectInfo
EffectInfo& effectInfo
) noexcept;
static std::string ParseForDesc(
std::string_view name,
const EffectInfo& effectInfo,
std::string&& source,
std::string&& workingFolder,
const ShaderEffectParserOptions& options,
struct ShaderEffectDesc& effectDesc,
ShaderEffectDesc& effectDesc,
ShaderEffectSource& effectSource
) noexcept;
};

View file

@ -27,12 +27,15 @@ public:
std::string_view effectName,
const phmap::flat_hash_map<std::string, float>* inlineParams,
D3D_SHADER_MODEL shaderModel,
bool isFP16Enabled,
bool isAdvancedColorEnabled
bool isFP16Supported,
bool isAdvancedColorSupported
) noexcept;
bool GetTaskResult(std::string taskKey, const ShaderEffectDesc* &effectDesc) noexcept;
// 缩放结束时调用
void CleanCache(bool clearAll) noexcept;
private:
EffectsService() = default;