mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
feat: 新版 FX 解析器 (p5)
This commit is contained in:
parent
0279dca40c
commit
d0d17311c3
13 changed files with 365 additions and 153 deletions
|
|
@ -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<*>">
|
||||
<DisplayString IncludeView ="elt0" Condition="Size == 0"></DisplayString>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 高仍是 51,Fit 的计算方式会使这两次调整中有一次存在黑边,而且
|
||||
// 也会影响后续计算是否追加 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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 失败");
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue