obs-StreamFX/data/effects/blur/box-linear.effect
Michael Fabian 'Xaymar' Dirks 5d4f88e614 gfx/blur: Reduce code duplication with shared file
A lot of the blur effects share quite a bit of code, which can be offloaded into a single include.
2023-04-05 18:51:01 +02:00

88 lines
2.9 KiB
Text

#include "common.effect"
// # Linear Optimization
// While the normal way is to sample every texel in the pSize, linear optimization
// takes advantage of the fact that most people, especially after compression,
// will not be able to tell the difference between a linear approximation and
// the actual thing.
//
// Instead of sampling every texel like this:
//
// |Tx|Tx|Tx|Tx|Tx|
// Tx|-2|-1| 0|+1|+2|
//
// Linear optimization will sample like this:
//
// |Tx|Tx|Tx|Tx|Tx|
// Tx| -1 | 0| +1 |
//
// This effectively removes half the necessary samples and looks identical when
// when used with box blur. However there is an edge case when the blur width
// is not a multiple of two, where two additional samples have to be spent on
// reading the outer edge:
//
// |Tx|Tx|Tx|Tx|Tx|Tx|Tx|
// Tx|-2| -1 | 0| +1 |+2|
//
// or this alternative pattern that uses two less samples:
//
// |Tx|Tx|Tx|Tx|Tx|Tx|Tx|
// Tx| 0 | +1 | +2 |+3|
//
// With careful planning this can even be used for other types of Blur, such as
// Gaussian Blur, which suffers a larger hit - however there are better and
// faster alternatives than linear sampling with Gaussian Blur, such as
// Dual Filtering ("Dual Kawase").
//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
#define MAX_BLUR_SIZE 128
//------------------------------------------------------------------------------
// Technique: Directional / Area
//------------------------------------------------------------------------------
float4 PSBlur1D(VertexInformation vtx) : TARGET {
float4 final = pImage.Sample(LinearClampSampler, vtx.uv);
bool is_odd = ((uint(round(pSize)) % 2) == 1);
// y = yes, s = skip, b = break
// Size-> | 1| 2| 3| 4| 5| 6| 7|
// -------+--+--+--+--+--+--+--+
// n=1 | b| y| y| y| y| y| y|
// n=2 | |bs| s| s| s| s| s|
// n=3 | | b| b| y| y| y| y|
// n=4 | | | |bs| s| s| s|
// n=5 | | | | b| b| y| y|
// n=6 | | | | | |bs| s|
// n=7 | | | | | | b| b|
// n=8 | | | | | | | |
// Loop unrolling is only possible with a fixed known maximum.
// Some compilers may unroll up to x iterations, but most will not.
for (int n = 1; n <= MAX_BLUR_SIZE; n+=2) {
// Different from normal box, early exit instead of late exit.
if (n >= pSize) {
break;
}
float2 nstep = (pImageTexel * pStepScale) * (n + 0.5);
final += pImage.Sample(LinearClampSampler, vtx.uv + nstep) * 2.;
final += pImage.Sample(LinearClampSampler, vtx.uv - nstep) * 2.;
}
if (is_odd) {
float2 nstep = (pImageTexel * pStepScale) * pSize;
final += pImage.Sample(LinearClampSampler, vtx.uv + nstep);
final += pImage.Sample(LinearClampSampler, vtx.uv - nstep);
}
final *= pSizeInverseMul;
return final;
}
technique Draw {
pass {
vertex_shader = VSDefault(vtx);
pixel_shader = PSBlur1D(vtx);
}
}