libobs: obs-filters: Area upscale shader
Add a separate shader for area upscaling to take advantage of bilinear filtering. Iterating over texels is unnecessary in the upscale case because a target pixel can only overlap 1 or 2 texels in X and Y directions. When only overlapping one texel, adjust UVs to sample texel center to avoid filtering. Also add "base_dimension" uniform to avoid unnecessary division. Intel HD Graphics 530, 644x478 -> 1323x1080: ~836 us -> ~232 us
This commit is contained in:
@@ -1,13 +1,29 @@
|
||||
uniform float4x4 ViewProj;
|
||||
uniform float2 base_dimension;
|
||||
uniform float2 base_dimension_i;
|
||||
uniform texture2d image;
|
||||
|
||||
struct VertInOut {
|
||||
sampler_state textureSampler {
|
||||
Filter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
};
|
||||
|
||||
struct VertData {
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertInOut VSDefault(VertInOut vert_in)
|
||||
struct VertInOut {
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 pos : POSITION;
|
||||
};
|
||||
|
||||
struct FragData {
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertInOut VSDefault(VertData vert_in)
|
||||
{
|
||||
VertInOut vert_out;
|
||||
vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj);
|
||||
@@ -15,50 +31,85 @@ VertInOut VSDefault(VertInOut vert_in)
|
||||
return vert_out;
|
||||
}
|
||||
|
||||
float4 PSDrawAreaRGBA(VertInOut vert_in) : TARGET
|
||||
float4 PSDrawAreaRGBA(FragData frag_in) : TARGET
|
||||
{
|
||||
float4 totalcolor = float4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float2 uv = vert_in.uv;
|
||||
float2 uvdelta = float2(ddx(uv.x), ddy(uv.y));
|
||||
float2 uv = frag_in.uv;
|
||||
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
|
||||
|
||||
// Handle potential OpenGL flip.
|
||||
uvdelta.y = abs(uvdelta.y);
|
||||
if (obs_glsl_compile)
|
||||
uv_delta.y = abs(uv_delta.y);
|
||||
|
||||
float2 uvhalfdelta = 0.5 * uvdelta;
|
||||
float2 uvmin = uv - uvhalfdelta;
|
||||
float2 uvmax = uv + uvhalfdelta;
|
||||
float2 uv_min = uv - 0.5 * uv_delta;
|
||||
float2 uv_max = uv_min + uv_delta;
|
||||
|
||||
float2 imagesize = 1.0 / base_dimension_i;
|
||||
float2 loadindexmin = floor(uvmin * imagesize);
|
||||
float2 loadindexmax = floor(uvmax * imagesize);
|
||||
float2 load_index_begin = floor(uv_min * base_dimension);
|
||||
float2 load_index_end = ceil(uv_max * base_dimension);
|
||||
|
||||
float2 targetsize = 1.0 / uvdelta;
|
||||
float2 targetpos = uv * targetsize;
|
||||
float2 targetposmin = targetpos - 0.5;
|
||||
float2 targetposmax = targetpos + 0.5;
|
||||
float2 scale = base_dimension_i * targetsize;
|
||||
float2 target_dimension = 1.0 / uv_delta;
|
||||
float2 target_pos = uv * target_dimension;
|
||||
float2 target_pos_min = target_pos - 0.5;
|
||||
float2 target_pos_max = target_pos + 0.5;
|
||||
float2 scale = base_dimension_i * target_dimension;
|
||||
|
||||
float loadindexy = loadindexmin.y;
|
||||
float4 total_color = float4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
float load_index_y = load_index_begin.y;
|
||||
do {
|
||||
float loadindexx = loadindexmin.x;
|
||||
float source_y_min = load_index_y * scale.y;
|
||||
float source_y_max = source_y_min + scale.y;
|
||||
float y_min = max(source_y_min, target_pos_min.y);
|
||||
float y_max = min(source_y_max, target_pos_max.y);
|
||||
float height = y_max - y_min;
|
||||
|
||||
float load_index_x = load_index_begin.x;
|
||||
do {
|
||||
float2 loadindex = float2(loadindexx, loadindexy);
|
||||
float2 potentialtargetmin = loadindex * scale;
|
||||
float2 potentialtargetmax = potentialtargetmin + scale;
|
||||
float2 targetmin = max(potentialtargetmin, targetposmin);
|
||||
float2 targetmax = min(potentialtargetmax, targetposmax);
|
||||
float area = (targetmax.x - targetmin.x) * (targetmax.y - targetmin.y);
|
||||
float4 sample = image.Load(int3(loadindex, 0));
|
||||
totalcolor += area * sample;
|
||||
float source_x_min = load_index_x * scale.x;
|
||||
float source_x_max = source_x_min + scale.x;
|
||||
float x_min = max(source_x_min, target_pos_min.x);
|
||||
float x_max = min(source_x_max, target_pos_max.x);
|
||||
float width = x_max - x_min;
|
||||
float area = width * height;
|
||||
|
||||
++loadindexx;
|
||||
} while (loadindexx <= loadindexmax.x);
|
||||
float4 color = image.Load(int3(load_index_x, load_index_y, 0));
|
||||
total_color += area * color;
|
||||
|
||||
++loadindexy;
|
||||
} while (loadindexy <= loadindexmax.y);
|
||||
++load_index_x;
|
||||
} while (load_index_x < load_index_end.x);
|
||||
|
||||
return totalcolor;
|
||||
++load_index_y;
|
||||
} while (load_index_y < load_index_end.y);
|
||||
|
||||
return total_color;
|
||||
}
|
||||
|
||||
float4 PSDrawAreaUpscaleRGBA(FragData frag_in) : TARGET
|
||||
{
|
||||
float2 uv = frag_in.uv;
|
||||
float2 uv_delta = float2(ddx(uv.x), ddy(uv.y));
|
||||
|
||||
// Handle potential OpenGL flip.
|
||||
if (obs_glsl_compile)
|
||||
uv_delta.y = abs(uv_delta.y);
|
||||
|
||||
float2 uv_min = uv - 0.5 * uv_delta;
|
||||
float2 uv_max = uv_min + uv_delta;
|
||||
|
||||
float2 load_index_first = floor(uv_min * base_dimension);
|
||||
float2 load_index_last = ceil(uv_max * base_dimension) - 1.0;
|
||||
|
||||
if (load_index_first.x < load_index_last.x) {
|
||||
float uv_boundary_x = load_index_last.x * base_dimension_i.x;
|
||||
uv.x = ((uv.x - uv_boundary_x) / uv_delta.x) * base_dimension_i.x + uv_boundary_x;
|
||||
} else
|
||||
uv.x = (load_index_first.x + 0.5) * base_dimension_i.x;
|
||||
if (load_index_first.y < load_index_last.y) {
|
||||
float uv_boundary_y = load_index_last.y * base_dimension_i.y;
|
||||
uv.y = ((uv.y - uv_boundary_y) / uv_delta.y) * base_dimension_i.y + uv_boundary_y;
|
||||
} else
|
||||
uv.y = (load_index_first.y + 0.5) * base_dimension_i.y;
|
||||
|
||||
return image.Sample(textureSampler, uv);
|
||||
}
|
||||
|
||||
technique Draw
|
||||
@@ -66,6 +117,15 @@ technique Draw
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBA(vert_in);
|
||||
pixel_shader = PSDrawAreaRGBA(frag_in);
|
||||
}
|
||||
}
|
||||
|
||||
technique DrawUpscale
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(vert_in);
|
||||
pixel_shader = PSDrawAreaUpscaleRGBA(frag_in);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user