mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
优化hlsl,为若干effect添加属性
This commit is contained in:
parent
52eca2e45b
commit
f1621c7cd2
21 changed files with 517 additions and 232 deletions
|
|
@ -1,6 +1,6 @@
|
|||
#include "common.hlsli"
|
||||
|
||||
// 因为 d2d 会将着色器间传递的值限制到 [0, 1],pass1 传递到 pass2 的值需要进行压缩
|
||||
// 假设所有值在 0~32 里
|
||||
// 假设所有值在 0~32 之间
|
||||
#define Compress(value) (value / 32) // (atan(value) / PI + 0.5)
|
||||
#define Uncompress(value) (value * 32) // (tan((value - 0.5) * PI))
|
||||
|
|
|
|||
|
|
@ -31,18 +31,18 @@ D2D_PS_ENTRY(main) {
|
|||
// [ c20, c6, c7, c8, c17 ]
|
||||
// [ c15, c12, c14 ]
|
||||
// [ c13 ]
|
||||
float left1X = GetCheckedLeft(0, 1);
|
||||
float left2X = GetCheckedLeft(0, 2);
|
||||
float left3X = GetCheckedLeft(0, 3);
|
||||
float right1X = GetCheckedRight(0, 1);
|
||||
float right2X = GetCheckedRight(0, 2);
|
||||
float right3X = GetCheckedRight(0, 3);
|
||||
float top1Y = GetCheckedTop(0, 1);
|
||||
float top2Y = GetCheckedTop(0, 2);
|
||||
float top3Y = GetCheckedTop(0, 3);
|
||||
float bottom1Y = GetCheckedBottom(0, 1);
|
||||
float bottom2Y = GetCheckedBottom(0, 2);
|
||||
float bottom3Y = GetCheckedBottom(0, 3);
|
||||
float left1X = GetCheckedLeft(1);
|
||||
float left2X = GetCheckedLeft(2);
|
||||
float left3X = GetCheckedLeft(3);
|
||||
float right1X = GetCheckedRight(1);
|
||||
float right2X = GetCheckedRight(2);
|
||||
float right3X = GetCheckedRight(3);
|
||||
float top1Y = GetCheckedTop(1);
|
||||
float top2Y = GetCheckedTop(2);
|
||||
float top3Y = GetCheckedTop(3);
|
||||
float bottom1Y = GetCheckedBottom(1);
|
||||
float bottom2Y = GetCheckedBottom(2);
|
||||
float bottom3Y = GetCheckedBottom(3);
|
||||
|
||||
float3 c[25] = {
|
||||
SampleInputCur(0), // c0
|
||||
|
|
|
|||
|
|
@ -72,18 +72,18 @@ D2D_PS_ENTRY(main) {
|
|||
// [ c20, c6, c7, c8, c17 ]
|
||||
// [ c15, c12, c14 ]
|
||||
// [ c13 ]
|
||||
float left1X = GetCheckedLeft(0, 1);
|
||||
float left2X = GetCheckedLeft(0, 2);
|
||||
float left3X = GetCheckedLeft(0, 3);
|
||||
float right1X = GetCheckedRight(0, 1);
|
||||
float right2X = GetCheckedRight(0, 2);
|
||||
float right3X = GetCheckedRight(0, 3);
|
||||
float top1Y = GetCheckedTop(0, 1);
|
||||
float top2Y = GetCheckedTop(0, 2);
|
||||
float top3Y = GetCheckedTop(0, 3);
|
||||
float bottom1Y = GetCheckedBottom(0, 1);
|
||||
float bottom2Y = GetCheckedBottom(0, 2);
|
||||
float bottom3Y = GetCheckedBottom(0, 3);
|
||||
float left1X = GetCheckedLeft(1);
|
||||
float left2X = GetCheckedLeft(2);
|
||||
float left3X = GetCheckedLeft(3);
|
||||
float right1X = GetCheckedRight(1);
|
||||
float right2X = GetCheckedRight(2);
|
||||
float right3X = GetCheckedRight(3);
|
||||
float top1Y = GetCheckedTop(1);
|
||||
float top2Y = GetCheckedTop(2);
|
||||
float top3Y = GetCheckedTop(3);
|
||||
float bottom1Y = GetCheckedBottom(1);
|
||||
float bottom2Y = GetCheckedBottom(2);
|
||||
float bottom3Y = GetCheckedBottom(3);
|
||||
|
||||
float4 c[25] = {
|
||||
orig0, // c0
|
||||
|
|
|
|||
40
Magpie/Anime4KDeblurKernelShader.hlsl
Normal file
40
Magpie/Anime4KDeblurKernelShader.hlsl
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Anime4K-v3.1-Upscale(x2)+Deblur-CNN(M)-Kernel(X/Y)
|
||||
*/
|
||||
|
||||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0);
|
||||
};
|
||||
|
||||
#define D2D_INPUT_COUNT 1
|
||||
#define D2D_INPUT0_COMPLEX
|
||||
#define MAGPIE_USE_SAMPLE_INPUT
|
||||
#include "Anime4K.hlsli"
|
||||
|
||||
#define max9(a, b, c, d, e, f, g, h, i) max3(max4(a, b, c, d), max4(e, f, g, h), i)
|
||||
#define min9(a, b, c, d, e, f, g, h, i) min3(min4(a, b, c, d), min4(e, f, g, h), i)
|
||||
|
||||
|
||||
D2D_PS_ENTRY(main) {
|
||||
InitMagpieSampleInput();
|
||||
|
||||
float left1X = GetCheckedLeft(1);
|
||||
float right1X = GetCheckedRight(1);
|
||||
float top1Y = GetCheckedTop(1);
|
||||
float bottom1Y = GetCheckedBottom(1);
|
||||
|
||||
// [ a, b, c ]
|
||||
// [ d, e, f ]
|
||||
// [ g, h, i ]
|
||||
float a = GetYOfYUV(SampleInputNoCheck(0, float2(left1X, top1Y)));
|
||||
float b = GetYOfYUV(SampleInputNoCheck(0, float2(coord.x, top1Y)));
|
||||
float c = GetYOfYUV(SampleInputNoCheck(0, float2(right1X, top1Y)));
|
||||
float d = GetYOfYUV(SampleInputNoCheck(0, float2(left1X, coord.y)));
|
||||
float e = GetYOfYUV(SampleInputCur(0));
|
||||
float f = GetYOfYUV(SampleInputNoCheck(0, float2(right1X, coord.y)));
|
||||
float g = GetYOfYUV(SampleInputNoCheck(0, float2(left1X, bottom1Y)));
|
||||
float h = GetYOfYUV(SampleInputNoCheck(0, float2(coord.x, bottom1Y)));
|
||||
float i = GetYOfYUV(SampleInputNoCheck(0, float2(right1X, bottom1Y)));
|
||||
|
||||
return float4(min9(a, b, c, d, e, f, g, h, i), max9(a, b, c, d, e, f, g, h, i), 0, 0);
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#define D2D_INPUT_COUNT 1
|
||||
#define D2D_INPUT0_COMPLEX
|
||||
#include "Anime4K.hlsli"
|
||||
|
||||
/*
|
||||
* Anime4K-v3.1-Upscale(x2)+Deblur-CNN(M)-Kernel(X)
|
||||
*/
|
||||
|
||||
|
||||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0);
|
||||
};
|
||||
|
||||
|
||||
D2D_PS_ENTRY(main) {
|
||||
float4 coord = D2DGetInputCoordinate(0);
|
||||
|
||||
float a = GetYOfYUV(
|
||||
D2DSampleInput(0, float2(max(0, coord.x - coord.z), coord.y)).rgb
|
||||
);
|
||||
float b = GetYOfYUV(D2DSampleInput(0, coord.xy).rgb);
|
||||
float c = GetYOfYUV(
|
||||
D2DSampleInput(0, float2(min((srcSize.x - 1) * coord.z, coord.x + coord.z), coord.y)).rgb
|
||||
);
|
||||
|
||||
return float4(min3(a, b, c), max3(a, b, c), 0, 0);
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#define D2D_INPUT_COUNT 1
|
||||
#define D2D_INPUT0_COMPLEX
|
||||
#include "Anime4K.hlsli"
|
||||
|
||||
/*
|
||||
* Anime4K-v3.1-Upscale(x2)+Deblur-CNN(M)-Kernel(X)
|
||||
*/
|
||||
|
||||
|
||||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0);
|
||||
};
|
||||
|
||||
|
||||
D2D_PS_ENTRY(main) {
|
||||
float4 coord = D2DGetInputCoordinate(0);
|
||||
|
||||
float2 a = D2DSampleInput(0, float2(coord.x, max(0, coord.y - coord.w))).xy;
|
||||
float2 b = D2DSampleInput(0, coord.xy).xy;
|
||||
float2 c = D2DSampleInput(0, float2(coord.x, min((srcSize.y - 1) * coord.w, coord.y + coord.w))).xy;
|
||||
|
||||
return float4(min3(a.x, b.x, c.x), max3(a.y, b.y, c.y), 0, 0);
|
||||
}
|
||||
|
|
@ -21,12 +21,12 @@ public:
|
|||
// | | | | | |
|
||||
// | v-----v-----v---+-v-----v
|
||||
// | |
|
||||
// | +---v--+
|
||||
// +--------------->+<-----+reduce|
|
||||
// | +------+
|
||||
// +--v---+
|
||||
// |output|
|
||||
// +--+---+
|
||||
// +----------------+ +---v--+
|
||||
// | | |reduce|
|
||||
// | | +--+---+
|
||||
// +-v----+ +--v---+ |
|
||||
// |kernel+-------->output<-----+
|
||||
// +------+ +--+---+
|
||||
// |
|
||||
// +-v-+
|
||||
// |out|
|
||||
|
|
@ -90,18 +90,9 @@ public:
|
|||
}
|
||||
hr = SimpleDrawTransform::Create(
|
||||
pEffectContext,
|
||||
&_deblurKernelXTransform,
|
||||
MAGPIE_ANIME4K_DEBLUR_KERNEL_X_SHADER,
|
||||
GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_X_SHADER
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
hr = SimpleDrawTransform::Create(
|
||||
pEffectContext,
|
||||
&_deblurKernelYTransform,
|
||||
MAGPIE_ANIME4K_DEBLUR_KERNEL_Y_SHADER,
|
||||
GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_Y_SHADER
|
||||
&_deblurKernelTransform,
|
||||
MAGPIE_ANIME4K_DEBLUR_KERNEL_SHADER,
|
||||
GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_SHADER
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
|
@ -139,11 +130,7 @@ public:
|
|||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
hr = pTransformGraph->AddNode(_deblurKernelXTransform.Get());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
hr = pTransformGraph->AddNode(_deblurKernelYTransform.Get());
|
||||
hr = pTransformGraph->AddNode(_deblurKernelTransform.Get());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -198,11 +185,7 @@ public:
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = pTransformGraph->ConnectToEffectInput(0, _deblurKernelXTransform.Get(), 0);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
hr = pTransformGraph->ConnectNode(_deblurKernelXTransform.Get(), _deblurKernelYTransform.Get(), 0);
|
||||
hr = pTransformGraph->ConnectToEffectInput(0, _deblurKernelTransform.Get(), 0);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -215,7 +198,7 @@ public:
|
|||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
hr = pTransformGraph->ConnectNode(_deblurKernelYTransform.Get(), _outputTransform.Get(), 2);
|
||||
hr = pTransformGraph->ConnectNode(_deblurKernelTransform.Get(), _outputTransform.Get(), 2);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -269,7 +252,6 @@ private:
|
|||
ComPtr<SimpleDrawTransform> _conv4x3x3x8Transform4 = nullptr;
|
||||
ComPtr<SimpleDrawTransform> _conv4x3x3x8Transform5 = nullptr;
|
||||
ComPtr<Anime4KUpscaleConvReduceTransform> _convReduceTransform = nullptr;
|
||||
ComPtr<SimpleDrawTransform> _deblurKernelXTransform = nullptr;
|
||||
ComPtr<SimpleDrawTransform> _deblurKernelYTransform = nullptr;
|
||||
ComPtr<SimpleDrawTransform> _deblurKernelTransform = nullptr;
|
||||
ComPtr<Anime4KUpscaleDeblurOutputTransform> _outputTransform = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
|
||||
|
||||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0);
|
||||
};
|
||||
|
||||
|
||||
#define D2D_INPUT_COUNT 3
|
||||
#define D2D_INPUT0_COMPLEX
|
||||
#define D2D_INPUT1_COMPLEX
|
||||
|
|
@ -11,11 +18,6 @@
|
|||
#define NOISE_THRESHOLD 0.001 //Value where curve stops, used to not sharpen noise. Only de-blur values that fall above this threshold.
|
||||
|
||||
|
||||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0);
|
||||
};
|
||||
|
||||
|
||||
D2D_PS_ENTRY(main) {
|
||||
float4 coord = D2DGetInputCoordinate(0);
|
||||
float2 srcPos = coord.xy / 2;
|
||||
|
|
@ -23,7 +25,8 @@ D2D_PS_ENTRY(main) {
|
|||
float2 f = frac(round(coord.xy / coord.zw) / 2);
|
||||
int2 i = f * 2;
|
||||
float c0 = Uncompress(D2DSampleInput(1, srcPos + (float2(0.5, 0.5) - f) * coord.zw))[i.y * 2 + i.x];
|
||||
if (c0 < 0.001) {
|
||||
if (c0 < 0.0001) {
|
||||
// Ïû³ýÔëÉù
|
||||
return D2DSampleInput(0, srcPos);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
#include "AdaptiveSharpenEffect.h"
|
||||
#include "Anime4KUpscaleEffect.h"
|
||||
#include "Anime4KUpscaleDeblurEffect.h"
|
||||
#include "ScaleEffect.h"
|
||||
#include "Jinc2ScaleEffect.h"
|
||||
#include "MitchellNetravaliScaleEffect.h"
|
||||
#include "json.hpp"
|
||||
#include <unordered_set>
|
||||
|
||||
class EffectManager {
|
||||
public:
|
||||
|
|
@ -14,13 +16,12 @@ public:
|
|||
const std::wstring_view& effectsJson,
|
||||
const SIZE &srcSize,
|
||||
const SIZE &maxSize
|
||||
): _destSize(srcSize), _maxSize(maxSize), _d2dFactory(d2dFactory), _d2dDC(d2dDC) {
|
||||
): _maxSize(maxSize), _d2dFactory(d2dFactory), _d2dDC(d2dDC) {
|
||||
assert(srcSize.cx > 0 && srcSize.cy > 0);
|
||||
assert(maxSize.cx > 0 && maxSize.cy > 0);
|
||||
assert(d2dFactory != nullptr && d2dDC != nullptr);
|
||||
|
||||
_RegisterEffects();
|
||||
_CreateSourceEffect();
|
||||
_CreateSourceEffect(srcSize);
|
||||
_ReadEffectsJson(effectsJson);
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void _CreateSourceEffect() {
|
||||
void _CreateSourceEffect(const SIZE& srcSize) {
|
||||
// 创建 Source effect
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_D2D1BitmapSource, &_d2dSourceEffect),
|
||||
|
|
@ -48,13 +49,8 @@ private:
|
|||
|
||||
// 初始时输出为 Source effect
|
||||
_outputEffect = _d2dSourceEffect;
|
||||
}
|
||||
|
||||
void _RegisterEffects() const {
|
||||
AdaptiveSharpenEffect::Register(_d2dFactory.Get());
|
||||
Anime4KUpscaleEffect::Register(_d2dFactory.Get());
|
||||
Anime4KUpscaleDeblurEffect::Register(_d2dFactory.Get());
|
||||
ScaleEffect::Register(_d2dFactory.Get());
|
||||
_SetDestSize(srcSize);
|
||||
}
|
||||
|
||||
void _ReadEffectsJson(const std::wstring_view& effectsJson) {
|
||||
|
|
@ -70,17 +66,21 @@ private:
|
|||
const auto& subType = effect.value("type", "");
|
||||
|
||||
if (subType == "anime4K") {
|
||||
//_AddAnime4KEffect();
|
||||
_AddAnime4KEffect();
|
||||
} else if (subType == "anime4KxDeblur") {
|
||||
_AddAnime4KxDeblurEffect();
|
||||
} else if (subType == "jinc2") {
|
||||
_AddJinc2ScaleEffect(effect);
|
||||
} else if (subType == "mitchell") {
|
||||
_AddMitchellNetravaliScaleEffect(effect);
|
||||
}
|
||||
} else if (effectType == "sharpen") {
|
||||
const auto& subType = effect.value("type", "");
|
||||
|
||||
if (subType == "adaptive") {
|
||||
_AddAdaptiveSharpenEffect(effect);
|
||||
_AddBuiltInSharpenEffect();
|
||||
} else if (subType == "builtIn") {
|
||||
_AddBuiltInSharpenEffect(effect);
|
||||
}
|
||||
} else {
|
||||
Debug::ThrowIfFalse(false, L"json 格式错误");
|
||||
|
|
@ -90,6 +90,11 @@ private:
|
|||
}
|
||||
|
||||
void _AddAdaptiveSharpenEffect(const nlohmann::json& props) {
|
||||
_CheckAndRegisterEffect(
|
||||
CLSID_MAGPIE_ADAPTIVE_SHARPEN_EFFECT,
|
||||
&AdaptiveSharpenEffect::Register
|
||||
);
|
||||
|
||||
ComPtr<ID2D1Effect> adaptiveSharpenEffect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_MAGPIE_ADAPTIVE_SHARPEN_EFFECT, &adaptiveSharpenEffect),
|
||||
|
|
@ -97,7 +102,7 @@ private:
|
|||
);
|
||||
|
||||
// strength 属性
|
||||
const auto& it = props.find("strength");
|
||||
auto it = props.find("strength");
|
||||
if (it != props.end()) {
|
||||
const auto& value = *it;
|
||||
Debug::ThrowIfFalse(value.is_number(), L"非法的 strength 属性值");
|
||||
|
|
@ -115,99 +120,166 @@ private:
|
|||
}
|
||||
|
||||
// 替换 output effect
|
||||
adaptiveSharpenEffect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = adaptiveSharpenEffect;
|
||||
_PushAsOutputEffect(adaptiveSharpenEffect);
|
||||
}
|
||||
|
||||
void _AddBuiltInSharpenEffect() {
|
||||
void _AddBuiltInSharpenEffect(const nlohmann::json& props) {
|
||||
ComPtr<ID2D1Effect> d2dSharpenEffect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_D2D1Sharpen, &d2dSharpenEffect),
|
||||
L"创建 sharpen effect 失败"
|
||||
);
|
||||
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_SHARPNESS, 6.0f);
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_THRESHOLD, 0.8f);
|
||||
// sharpness 属性
|
||||
auto it = props.find("strength");
|
||||
if (it != props.end()) {
|
||||
const auto& value = *it;
|
||||
Debug::ThrowIfFalse(value.is_number(), L"非法的 sharpness 属性值");
|
||||
|
||||
float sharpness = value.get<float>();
|
||||
Debug::ThrowIfFalse(
|
||||
sharpness >= 0 && sharpness <= 10,
|
||||
L"非法的 strength 属性值"
|
||||
);
|
||||
|
||||
Debug::ThrowIfFailed(
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_SHARPNESS, sharpness),
|
||||
L"设置 strength 属性失败"
|
||||
);
|
||||
}
|
||||
|
||||
// threshold 属性
|
||||
it = props.find("threshold");
|
||||
if (it != props.end()) {
|
||||
const auto& value = *it;
|
||||
Debug::ThrowIfFalse(value.is_number(), L"非法的 threshold 属性值");
|
||||
|
||||
float threshold = value.get<float>();
|
||||
Debug::ThrowIfFalse(
|
||||
threshold >= 0 && threshold <= 1,
|
||||
L"非法的 threshold 属性值"
|
||||
);
|
||||
|
||||
Debug::ThrowIfFailed(
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_THRESHOLD, threshold),
|
||||
L"设置 threshold 属性失败"
|
||||
);
|
||||
}
|
||||
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_SHARPNESS, 3.0f);
|
||||
d2dSharpenEffect->SetValue(D2D1_SHARPEN_PROP_THRESHOLD, 0.5f);
|
||||
|
||||
// 替换 output effect
|
||||
d2dSharpenEffect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = d2dSharpenEffect;
|
||||
_PushAsOutputEffect(d2dSharpenEffect);
|
||||
}
|
||||
|
||||
void _AddAnime4KEffect() {
|
||||
_CheckAndRegisterEffect(
|
||||
CLSID_MAGIPE_ANIME4K_UPSCALE_EFFECT,
|
||||
&Anime4KUpscaleEffect::Register
|
||||
);
|
||||
|
||||
ComPtr<ID2D1Effect> anime4KEffect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_MAGIPE_ANIME4K_UPSCALE_EFFECT, &anime4KEffect),
|
||||
L"创建 Anime4K Effect 失败"
|
||||
);
|
||||
|
||||
// 替换 output effect
|
||||
anime4KEffect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = anime4KEffect;
|
||||
|
||||
// 输出图像的长和宽变为 2 倍
|
||||
_destSize.cx *= 2;
|
||||
_destSize.cy *= 2;
|
||||
_SetDestSize(SIZE{ _destSize.cx * 2, _destSize.cy * 2 });
|
||||
|
||||
_PushAsOutputEffect(anime4KEffect);
|
||||
}
|
||||
|
||||
void _AddAnime4KxDeblurEffect() {
|
||||
_CheckAndRegisterEffect(
|
||||
CLSID_MAGIPE_ANIME4K_UPSCALE_DEBLUR_EFFECT,
|
||||
&Anime4KUpscaleDeblurEffect::Register
|
||||
);
|
||||
|
||||
ComPtr<ID2D1Effect> anime4KxDeblurEffect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_MAGIPE_ANIME4K_UPSCALE_DEBLUR_EFFECT, &anime4KxDeblurEffect),
|
||||
L"创建 Anime4K Effect 失败"
|
||||
);
|
||||
|
||||
// 替换 output effect
|
||||
anime4KxDeblurEffect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = anime4KxDeblurEffect;
|
||||
|
||||
// 输出图像的长和宽变为 2 倍
|
||||
_destSize.cx *= 2;
|
||||
_destSize.cy *= 2;
|
||||
_SetDestSize(SIZE{ _destSize.cx * 2, _destSize.cy * 2 });
|
||||
|
||||
_PushAsOutputEffect(anime4KxDeblurEffect);
|
||||
}
|
||||
|
||||
void _AddJinc2ScaleEffect(const nlohmann::json& props) {
|
||||
_CheckAndRegisterEffect(
|
||||
CLSID_MAGPIE_JINC2_SCALE_EFFECT,
|
||||
&Jinc2ScaleEffect::Register
|
||||
);
|
||||
|
||||
ComPtr<ID2D1Effect> jinc2Effect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_MAGPIE_SCALE_EFFECT, &jinc2Effect),
|
||||
_d2dDC->CreateEffect(CLSID_MAGPIE_JINC2_SCALE_EFFECT, &jinc2Effect),
|
||||
L"创建 Anime4K Effect 失败"
|
||||
);
|
||||
|
||||
|
||||
// scale 属性
|
||||
auto it = props.find("scale");
|
||||
if (it != props.end()) {
|
||||
const auto& scale = _ReadScaleProp(*it);
|
||||
|
||||
Debug::ThrowIfFailed(
|
||||
jinc2Effect->SetValue(Jinc2ScaleEffect::PROP_SCALE, scale),
|
||||
L"设置 scale 属性失败"
|
||||
);
|
||||
|
||||
// 存在 scale 则输出图像尺寸改变
|
||||
_SetDestSize(SIZE{ lroundf(_destSize.cx * scale.x), lroundf(_destSize.cy * scale.y) });
|
||||
}
|
||||
|
||||
// 替换 output effect
|
||||
_PushAsOutputEffect(jinc2Effect);
|
||||
}
|
||||
|
||||
void _AddMitchellNetravaliScaleEffect(const nlohmann::json& props) {
|
||||
_CheckAndRegisterEffect(
|
||||
CLSID_MAGPIE_MITCHELL_NETRAVALI_SCALE_EFFECT,
|
||||
&MitchellNetravaliScaleEffect::Register
|
||||
);
|
||||
|
||||
ComPtr<ID2D1Effect> effect = nullptr;
|
||||
Debug::ThrowIfFailed(
|
||||
_d2dDC->CreateEffect(CLSID_MAGPIE_MITCHELL_NETRAVALI_SCALE_EFFECT, &effect),
|
||||
L"创建 Mitchell-Netraval Scale Effect 失败"
|
||||
);
|
||||
|
||||
// scale 属性
|
||||
auto it = props.find("scale");
|
||||
if (it != props.end()) {
|
||||
const auto& scaleValues = *it;
|
||||
Debug::ThrowIfFalse(
|
||||
scaleValues.is_array() && scaleValues.size() == 2
|
||||
&& scaleValues[0].is_number() && scaleValues[1].is_number(),
|
||||
L"读取 scale 属性失败"
|
||||
);
|
||||
const auto& scale = _ReadScaleProp(*it);
|
||||
|
||||
D2D1_VECTOR_2F scale{ scaleValues[0], scaleValues[1]};
|
||||
Debug::ThrowIfFalse(
|
||||
scale.x >= 0 && scale.y >= 0,
|
||||
L"scale 属性的值非法"
|
||||
);
|
||||
|
||||
if (scale.x == 0 || scale.y == 0) {
|
||||
// 输出图像充满屏幕
|
||||
scale.x = min((FLOAT)_maxSize.cx / _destSize.cx, (FLOAT)_maxSize.cy / _destSize.cy);
|
||||
scale.y = scale.x;
|
||||
}
|
||||
|
||||
Debug::ThrowIfFailed(
|
||||
jinc2Effect->SetValue(ScaleEffect::PROP_SCALE, scale),
|
||||
effect->SetValue(MitchellNetravaliScaleEffect::PROP_SCALE, scale),
|
||||
L"设置 scale 属性失败"
|
||||
);
|
||||
|
||||
// 存在 scale 则输出图像尺寸改变
|
||||
_destSize.cx = lroundf(_destSize.cx * scale.x);
|
||||
_destSize.cy = lroundf(_destSize.cy * scale.y);
|
||||
_SetDestSize(SIZE{ lroundf(_destSize.cx * scale.x), lroundf(_destSize.cy * scale.y) });
|
||||
}
|
||||
|
||||
|
||||
// useSharperVersion 属性
|
||||
it = props.find("useSharperVersion");
|
||||
if (it != props.end()) {
|
||||
const auto& val = *it;
|
||||
Debug::ThrowIfFalse(val.is_boolean(), L"非法的 useSharperVersion 属性值");
|
||||
|
||||
Debug::ThrowIfFailed(
|
||||
effect->SetValue(MitchellNetravaliScaleEffect::PROP_USE_SHARPER_VERSION, (BOOL)val.get<bool>()),
|
||||
L"设置 useSharperVersion 属性失败"
|
||||
);
|
||||
}
|
||||
|
||||
// 替换 output effect
|
||||
jinc2Effect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = jinc2Effect;
|
||||
_PushAsOutputEffect(effect);
|
||||
}
|
||||
|
||||
void _AddCubicScaleEffect() {
|
||||
|
|
@ -223,8 +295,61 @@ private:
|
|||
float scale = min((FLOAT)_maxSize.cx / _destSize.cx, (FLOAT)_maxSize.cy / _destSize.cy);
|
||||
cubicEffect->SetValue(D2D1_SCALE_PROP_SCALE, D2D1_VECTOR_2F{ scale, scale });
|
||||
|
||||
cubicEffect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = cubicEffect;
|
||||
_PushAsOutputEffect(cubicEffect);
|
||||
}
|
||||
|
||||
D2D1_VECTOR_2F _ReadScaleProp(const nlohmann::json& prop) {
|
||||
Debug::ThrowIfFalse(
|
||||
prop.is_array() && prop.size() == 2
|
||||
&& prop[0].is_number() && prop[1].is_number(),
|
||||
L"读取 scale 属性失败"
|
||||
);
|
||||
|
||||
D2D1_VECTOR_2F scale{ prop[0], prop[1] };
|
||||
Debug::ThrowIfFalse(
|
||||
scale.x >= 0 && scale.y >= 0,
|
||||
L"scale 属性的值非法"
|
||||
);
|
||||
|
||||
if (scale.x == 0 || scale.y == 0) {
|
||||
// 输出图像充满屏幕
|
||||
scale.x = min((FLOAT)_maxSize.cx / _destSize.cx, (FLOAT)_maxSize.cy / _destSize.cy);
|
||||
scale.y = scale.x;
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
// 将 effect 添加到 effect 链作为输出
|
||||
void _PushAsOutputEffect(ComPtr<ID2D1Effect> effect) {
|
||||
effect->SetInputEffect(0, _outputEffect.Get());
|
||||
_outputEffect = effect;
|
||||
}
|
||||
|
||||
// 设置 destSize 的同时增大 tile 的大小以容纳图像
|
||||
void _SetDestSize(SIZE value) {
|
||||
if (value.cx > _destSize.cx || value.cy > _destSize.cy) {
|
||||
// 需要更大的 tile
|
||||
rc.tileSize.width = max(value.cx, _destSize.cx);
|
||||
rc.tileSize.height = max(value.cy, _destSize.cy);
|
||||
_d2dDC->SetRenderingControls(rc);
|
||||
}
|
||||
|
||||
_destSize = value;
|
||||
}
|
||||
|
||||
|
||||
// 必要时注册 effect
|
||||
void _CheckAndRegisterEffect(const GUID& effectID, std::function<HRESULT(ID2D1Factory1*)> registerFunc) {
|
||||
if (_registeredEffects.find(effectID) == _registeredEffects.end()) {
|
||||
// 未注册
|
||||
Debug::ThrowIfFailed(
|
||||
registerFunc(_d2dFactory.Get()),
|
||||
L"注册 Effect 失败"
|
||||
);
|
||||
|
||||
_registeredEffects.insert(effectID);
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<ID2D1Factory1> _d2dFactory;
|
||||
|
|
@ -237,4 +362,16 @@ private:
|
|||
SIZE _destSize{};
|
||||
// 全屏窗口尺寸
|
||||
SIZE _maxSize;
|
||||
|
||||
// 存储已注册的 effect 的 GUID
|
||||
std::unordered_set<GUID> _registeredEffects;
|
||||
|
||||
// 用于确定 tile 的大小
|
||||
SIZE _maxDestSize{};
|
||||
|
||||
D2D1_RENDERING_CONTROLS rc{
|
||||
D2D1_BUFFER_PRECISION_32BPC_FLOAT,
|
||||
1024,
|
||||
1024
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
// 将输出图像显示在窗口中央
|
||||
_d2dDC->BeginDraw();
|
||||
_d2dDC->Clear(D2D1_COLOR_F{ 0,1,0,1 });
|
||||
_d2dDC->Clear();
|
||||
_d2dDC->DrawImage(
|
||||
outputImg.Get(),
|
||||
D2D1_POINT_2F{
|
||||
|
|
@ -187,13 +187,6 @@ private:
|
|||
// Now we can set the Direct2D render target.
|
||||
_d2dDC->SetTarget(d2dTargetBitmap.Get());
|
||||
_d2dDC->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
|
||||
|
||||
D2D1_RENDERING_CONTROLS rc{};
|
||||
_d2dDC->GetRenderingControls(&rc);
|
||||
rc.bufferPrecision = D2D1_BUFFER_PRECISION_32BPC_FLOAT;
|
||||
rc.tileSize.width = _hostWndClientSize.cx * 2;
|
||||
rc.tileSize.height = _hostWndClientSize.cy * 2;
|
||||
_d2dDC->SetRenderingControls(rc);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,13 +50,9 @@ DEFINE_GUID(GUID_MAGPIE_ANIME4K_UPSCALE_OUTPUT_SHADER,
|
|||
0x97dbf32e, 0x65b, 0x417a, 0x9c, 0x2d, 0x87, 0x75, 0x3f, 0xb8, 0xeb, 0xbe);
|
||||
|
||||
// {C25507A7-845B-4DD2-BEA7-32E64EFBE5C5}
|
||||
DEFINE_GUID(GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_X_SHADER,
|
||||
DEFINE_GUID(GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_SHADER,
|
||||
0xc25507a7, 0x845b, 0x4dd2, 0xbe, 0xa7, 0x32, 0xe6, 0x4e, 0xfb, 0xe5, 0xc5);
|
||||
|
||||
// {4ED918AA-1569-40A0-80BF-D7E1A0C51026}
|
||||
DEFINE_GUID(GUID_MAGPIE_ANIME4K_DEBLUR_KERNEL_Y_SHADER,
|
||||
0x4ed918aa, 0x1569, 0x40a0, 0x80, 0xbf, 0xd7, 0xe1, 0xa0, 0xc5, 0x10, 0x26);
|
||||
|
||||
// {898ACF79-3FEE-471D-8565-EA5E45A0C887}
|
||||
DEFINE_GUID(GUID_MAGPIE_ANIME4K_UPSCALE_DEBLUR_OUTPUT_SHADER,
|
||||
0x898acf79, 0x3fee, 0x471d, 0x85, 0x65, 0xea, 0x5e, 0x45, 0xa0, 0xc8, 0x87);
|
||||
|
|
@ -84,5 +80,9 @@ DEFINE_GUID(CLSID_MAGIPE_ANIME4K_UPSCALE_DEBLUR_EFFECT,
|
|||
|
||||
|
||||
// {1F1D758E-5EEA-4FE7-BDC0-FC9E98702108}
|
||||
DEFINE_GUID(CLSID_MAGPIE_SCALE_EFFECT,
|
||||
DEFINE_GUID(CLSID_MAGPIE_JINC2_SCALE_EFFECT,
|
||||
0x1f1d758e, 0x5eea, 0x4fe7, 0xbd, 0xc0, 0xfc, 0x9e, 0x98, 0x70, 0x21, 0x8);
|
||||
|
||||
// {DED5C76B-9308-4122-AC81-578C6542B7BD}
|
||||
DEFINE_GUID(CLSID_MAGPIE_MITCHELL_NETRAVALI_SCALE_EFFECT,
|
||||
0xded5c76b, 0x9308, 0x4122, 0xac, 0x81, 0x57, 0x8c, 0x65, 0x42, 0xb7, 0xbd);
|
||||
|
|
|
|||
|
|
@ -6,18 +6,21 @@
|
|||
#include <d2d1effecthelpers.h>
|
||||
|
||||
|
||||
class ScaleEffect : public EffectBase {
|
||||
class Jinc2ScaleEffect : public EffectBase {
|
||||
public:
|
||||
IFACEMETHODIMP Initialize(
|
||||
_In_ ID2D1EffectContext* pEffectContext,
|
||||
_In_ ID2D1TransformGraph* pTransformGraph
|
||||
) {
|
||||
HRESULT hr = SimpleScaleTransform::Create(pEffectContext, &_jinc2SharpTransform, MAGPIE_MITCHELL_NETRAVALI_SCALE_SHADER, GUID_MAGPIE_MITCHELL_NETRAVALI_SCALE_SHADER);
|
||||
HRESULT hr = SimpleScaleTransform::Create(
|
||||
pEffectContext, &_transform,
|
||||
MAGPIE_JINC2_SCALE_SHADER,
|
||||
GUID_MAGPIE_JINC2_SCALE_SHADER);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = pTransformGraph->SetSingleTransformNode(_jinc2SharpTransform.Get());
|
||||
hr = pTransformGraph->SetSingleTransformNode(_transform.Get());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -30,12 +33,12 @@ public:
|
|||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
_jinc2SharpTransform->SetScale(value);
|
||||
_transform->SetScale(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D2D_VECTOR_2F GetScale() const {
|
||||
return _jinc2SharpTransform->GetScale();
|
||||
return _transform->GetScale();
|
||||
}
|
||||
|
||||
enum PROPS {
|
||||
|
|
@ -48,7 +51,7 @@ public:
|
|||
D2D1_VALUE_TYPE_BINDING(L"Scale", &SetScale, &GetScale),
|
||||
};
|
||||
|
||||
HRESULT hr = pFactory->RegisterEffectFromString(CLSID_MAGPIE_SCALE_EFFECT, XML(
|
||||
HRESULT hr = pFactory->RegisterEffectFromString(CLSID_MAGPIE_JINC2_SCALE_EFFECT, XML(
|
||||
<?xml version='1.0'?>
|
||||
<Effect>
|
||||
<!--System Properties-->
|
||||
|
|
@ -70,7 +73,7 @@ public:
|
|||
}
|
||||
|
||||
static HRESULT CALLBACK CreateEffect(_Outptr_ IUnknown** ppEffectImpl) {
|
||||
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new ScaleEffect());
|
||||
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new Jinc2ScaleEffect());
|
||||
|
||||
if (*ppEffectImpl == nullptr) {
|
||||
return E_OUTOFMEMORY;
|
||||
|
|
@ -80,7 +83,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
ScaleEffect() {}
|
||||
Jinc2ScaleEffect() {}
|
||||
|
||||
ComPtr<SimpleScaleTransform> _jinc2SharpTransform = nullptr;
|
||||
ComPtr<SimpleScaleTransform> _transform = nullptr;
|
||||
};
|
||||
|
|
@ -203,7 +203,9 @@
|
|||
<ClInclude Include="Jinc2Transform.h" />
|
||||
<ClInclude Include="json.hpp" />
|
||||
<ClInclude Include="MagWindow.h" />
|
||||
<ClInclude Include="ScaleEffect.h" />
|
||||
<ClInclude Include="MitchellNetravaliScaleEffect.h" />
|
||||
<ClInclude Include="MitchellNetravaliScaleTransform.h" />
|
||||
<ClInclude Include="Jinc2ScaleEffect.h" />
|
||||
<ClInclude Include="KeyBoardHook.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Shaders.h" />
|
||||
|
|
@ -243,6 +245,7 @@
|
|||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl" />
|
||||
<FxCompile Include="Anime4KUpscaleConv4x3x3x1Shader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
|
|
@ -308,19 +311,6 @@
|
|||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelXShader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelYShader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Jinc2ScaleShader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,6 @@
|
|||
<FxCompile Include="AdaptiveSharpenPass2Shader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelXShader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelYShader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KUpscaleConv4x3x3x1Shader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
|
|
@ -49,6 +43,9 @@
|
|||
<FxCompile Include="MitchellNetravaliScaleShader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl">
|
||||
<Filter>着色器</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GUIDs.cpp">
|
||||
|
|
@ -140,10 +137,16 @@
|
|||
<ClInclude Include="SimpleScaleTransform.h">
|
||||
<Filter>头文件\Effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScaleEffect.h">
|
||||
<ClInclude Include="AdaptiveSharpenPass2Transform.h">
|
||||
<Filter>头文件\Effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AdaptiveSharpenPass2Transform.h">
|
||||
<ClInclude Include="MitchellNetravaliScaleTransform.h">
|
||||
<Filter>头文件\Effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MitchellNetravaliScaleEffect.h">
|
||||
<Filter>头文件\Effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Jinc2ScaleEffect.h">
|
||||
<Filter>头文件\Effect</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
|||
[
|
||||
{
|
||||
"effect": "scale",
|
||||
"type": "anime4K"
|
||||
"type": "anime4KxDeblur"
|
||||
},
|
||||
{
|
||||
"effect": "scale",
|
||||
|
|
@ -49,7 +49,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
|||
{
|
||||
"effect": "sharpen",
|
||||
"type": "adaptive",
|
||||
"strength": 0.6
|
||||
"strength": 0.3
|
||||
}
|
||||
])"));
|
||||
} else {
|
||||
|
|
|
|||
101
Magpie/MitchellNetravaliScaleEffect.h
Normal file
101
Magpie/MitchellNetravaliScaleEffect.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "GUIDs.h"
|
||||
#include "MitchellNetravaliScaleTransform.h"
|
||||
#include "EffectBase.h"
|
||||
#include <d2d1effecthelpers.h>
|
||||
|
||||
|
||||
class MitchellNetravaliScaleEffect : public EffectBase {
|
||||
public:
|
||||
IFACEMETHODIMP Initialize(
|
||||
_In_ ID2D1EffectContext* pEffectContext,
|
||||
_In_ ID2D1TransformGraph* pTransformGraph
|
||||
) {
|
||||
HRESULT hr = MitchellNetravaliScaleTransform::Create(pEffectContext, &_transform);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = pTransformGraph->SetSingleTransformNode(_transform.Get());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT SetScale(D2D_VECTOR_2F value) {
|
||||
if (value.x <= 0 || value.y <= 0) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
_transform->SetScale(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D2D_VECTOR_2F GetScale() const {
|
||||
return _transform->GetScale();
|
||||
}
|
||||
|
||||
HRESULT SetUseSharperVersion(BOOL value) {
|
||||
_transform->SetUseSharpenVersion((bool)value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL IsUseSharperVersion() const {
|
||||
return (BOOL)_transform->IsUseSharpenVersion();
|
||||
}
|
||||
|
||||
enum PROPS {
|
||||
PROP_SCALE = 0,
|
||||
PROP_USE_SHARPER_VERSION = 0
|
||||
};
|
||||
|
||||
static HRESULT Register(_In_ ID2D1Factory1* pFactory) {
|
||||
const D2D1_PROPERTY_BINDING bindings[] =
|
||||
{
|
||||
D2D1_VALUE_TYPE_BINDING(L"Scale", &SetScale, &GetScale),
|
||||
D2D1_VALUE_TYPE_BINDING(L"UseSharperVersion", &SetUseSharperVersion, &IsUseSharperVersion)
|
||||
};
|
||||
|
||||
HRESULT hr = pFactory->RegisterEffectFromString(CLSID_MAGPIE_MITCHELL_NETRAVALI_SCALE_EFFECT, XML(
|
||||
<?xml version='1.0'?>
|
||||
<Effect>
|
||||
<!--System Properties-->
|
||||
<Property name='DisplayName' type='string' value='Mitchell-Netravali Scale' />
|
||||
<Property name='Author' type='string' value='Xu Liu' />
|
||||
<Property name='Category' type='string' value='Scale' />
|
||||
<Property name='Description' type='string' value='Mitchell-Netravali scale algorithm' />
|
||||
<Inputs>
|
||||
<Input name='Source' />
|
||||
</Inputs>
|
||||
<Property name='Scale' type='vector2'>
|
||||
<Property name='DisplayName' type='string' value='Scale' />
|
||||
<Property name='Default' type='vector2' value='(1,1)' />
|
||||
</Property>
|
||||
<Property name='UseSharperVersion' type='bool'>
|
||||
<Property name='DisplayName' type='string' value='Use Sharper Version' />
|
||||
<Property name='Default' type='bool' value='false' />
|
||||
</Property>
|
||||
</Effect>
|
||||
), bindings, ARRAYSIZE(bindings), CreateEffect);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT CALLBACK CreateEffect(_Outptr_ IUnknown** ppEffectImpl) {
|
||||
*ppEffectImpl = static_cast<ID2D1EffectImpl*>(new MitchellNetravaliScaleEffect());
|
||||
|
||||
if (*ppEffectImpl == nullptr) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
MitchellNetravaliScaleEffect() {}
|
||||
|
||||
ComPtr<MitchellNetravaliScaleTransform> _transform = nullptr;
|
||||
};
|
||||
|
|
@ -5,19 +5,25 @@
|
|||
cbuffer constants : register(b0) {
|
||||
int2 srcSize : packoffset(c0.x);
|
||||
int2 destSize : packoffset(c0.z);
|
||||
int useSharperVersion : packoffset(c1.x);
|
||||
};
|
||||
|
||||
float weight(float x) {
|
||||
float ax = abs(x);
|
||||
// Mitchel-Netravali coefficients.
|
||||
// Best psychovisual result.
|
||||
const float B = 1.0 / 3.0;
|
||||
const float C = 1.0 / 3.0;
|
||||
|
||||
// Sharper version.
|
||||
// May look better in some cases.
|
||||
//const float B = 0.0;
|
||||
//const float C = 0.75;
|
||||
float B = 0.0;
|
||||
float C = 0.0;
|
||||
if (useSharperVersion == 0) {
|
||||
// Mitchel-Netravali coefficients.
|
||||
// Best psychovisual result.
|
||||
B = 1.0 / 3.0;
|
||||
C = 1.0 / 3.0;
|
||||
} else {
|
||||
// Sharper version.
|
||||
// May look better in some cases.
|
||||
B = 0.0;
|
||||
C = 0.75;
|
||||
}
|
||||
|
||||
if (ax < 1.0) {
|
||||
return
|
||||
|
|
|
|||
59
Magpie/MitchellNetravaliScaleTransform.h
Normal file
59
Magpie/MitchellNetravaliScaleTransform.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "GUIDs.h"
|
||||
#include "SimpleScaleTransform.h"
|
||||
|
||||
// Mitchell-Netravali 插值算法,一种双三次插值,可以获得平滑的边缘
|
||||
// 可选是否使用更锐利的版本,默认为否
|
||||
// (经测试两种版本几乎没有区别)
|
||||
class MitchellNetravaliScaleTransform : public SimpleScaleTransform {
|
||||
private:
|
||||
MitchellNetravaliScaleTransform() : SimpleScaleTransform(GUID_MAGPIE_MITCHELL_NETRAVALI_SCALE_SHADER) {}
|
||||
public:
|
||||
static HRESULT Create(_In_ ID2D1EffectContext* d2dEC, _Outptr_ MitchellNetravaliScaleTransform** ppOutput) {
|
||||
if (!ppOutput) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = DrawTransformBase::LoadShader(
|
||||
d2dEC,
|
||||
MAGPIE_MITCHELL_NETRAVALI_SCALE_SHADER,
|
||||
GUID_MAGPIE_MITCHELL_NETRAVALI_SCALE_SHADER
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
*ppOutput = new MitchellNetravaliScaleTransform();
|
||||
return hr;
|
||||
}
|
||||
|
||||
void SetUseSharpenVersion(bool value) {
|
||||
_useSharperVersion = value;
|
||||
}
|
||||
|
||||
bool IsUseSharpenVersion() {
|
||||
return _useSharperVersion;
|
||||
}
|
||||
|
||||
protected:
|
||||
void _SetShaderContantBuffer(const SIZE& srcSize, const SIZE& destSize) override {
|
||||
struct {
|
||||
INT32 srcWidth;
|
||||
INT32 srcHeight;
|
||||
INT32 destWidth;
|
||||
INT32 destHeight;
|
||||
INT32 useSharperVersion;
|
||||
} shaderConstants{
|
||||
srcSize.cx,
|
||||
srcSize.cy,
|
||||
destSize.cx,
|
||||
destSize.cy,
|
||||
(INT32)_useSharperVersion
|
||||
};
|
||||
|
||||
_drawInfo->SetPixelShaderConstantBuffer((BYTE*)&shaderConstants, sizeof(shaderConstants));
|
||||
}
|
||||
private:
|
||||
bool _useSharperVersion = false;
|
||||
};
|
||||
|
|
@ -19,8 +19,7 @@ constexpr auto MAGPIE_ANIME4K_UPSCALE_CONV_4x3x3x8_SHADER4 = L"shaders/Anime4KUp
|
|||
constexpr auto MAGPIE_ANIME4K_UPSCALE_CONV_4x3x3x8_SHADER5 = L"shaders/Anime4KUpscaleConv4x3x3x8Shader5.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_UPSCALE_CONV_REDUCE_SHADER = L"shaders/Anime4KUpscaleConvReduceShader.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_UPSCALE_OUTPUT_SHADER = L"shaders/Anime4KUpscaleOutputShader.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_DEBLUR_KERNEL_X_SHADER = L"shaders/Anime4KDeblurKernelXShader.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_DEBLUR_KERNEL_Y_SHADER = L"shaders/Anime4KDeblurKernelYShader.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_DEBLUR_KERNEL_SHADER = L"shaders/Anime4KDeblurKernelShader.cso";
|
||||
constexpr auto MAGPIE_ANIME4K_UPSCALE_DEBLUR_OUTPUT_SHADER = L"shaders/Anime4KUpscaleDeblurOutputShader.cso";
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "Shlwapi.h"
|
||||
#include <utility>
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
|
|
@ -141,4 +142,22 @@ public:
|
|||
Debug::ThrowIfFailed(bmpEncoder->Commit(), L"");
|
||||
stream->Commit(STGC_DEFAULT);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
namespace std {
|
||||
// std::hash µÄ GUID ÌØ»¯
|
||||
template<>
|
||||
struct hash<GUID> {
|
||||
size_t operator()(const GUID& value) const {
|
||||
size_t result = hash<unsigned long>()(value.Data1);
|
||||
result ^= hash<unsigned short>()(value.Data2) << 1;
|
||||
result ^= hash<unsigned short>()(value.Data3) << 2;
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
result ^= hash<unsigned short>()(value.Data4[i]) << i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ static float2 _maxCoord = 0;
|
|||
|
||||
// 限制坐标在边界内
|
||||
// n 为 offset
|
||||
#define GetCheckedLeft(index, n) _checkLeft(coord.x - n * coord.z)
|
||||
#define GetCheckedRight(index, n) _checkRight(coord.x + n * coord.w)
|
||||
#define GetCheckedTop(index, n) _checkTop(coord.y - n * coord.z)
|
||||
#define GetCheckedBottom(index, n) _checkBottom(coord.y + n * coord.w)
|
||||
#define GetCheckedLeft(n) _checkLeft(coord.x - n * coord.z)
|
||||
#define GetCheckedRight(n) _checkRight(coord.x + n * coord.w)
|
||||
#define GetCheckedTop(n) _checkTop(coord.y - n * coord.z)
|
||||
#define GetCheckedBottom(n) _checkBottom(coord.y + n * coord.w)
|
||||
|
||||
|
||||
// 需要 main 函数的开头调用
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue