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:
jpark37
2019-07-17 21:11:18 -07:00
parent 8af49016fa
commit 85cc7c84bc
4 changed files with 135 additions and 41 deletions

View File

@@ -36,7 +36,9 @@ struct scale_filter_data {
gs_effect_t *effect;
gs_eparam_t *image_param;
gs_eparam_t *dimension_param;
gs_eparam_t *dimension_i_param;
gs_eparam_t *undistort_factor_param;
struct vec2 dimension;
struct vec2 dimension_i;
double undistort_factor;
int cx_in;
@@ -49,6 +51,7 @@ struct scale_filter_data {
bool target_valid;
bool valid;
bool undistort;
bool upscale;
bool base_canvas_resolution;
};
@@ -203,6 +206,7 @@ static void scale_filter_tick(void *data, float seconds)
filter->cy_out = filter->cy_in;
}
vec2_set(&filter->dimension, (float)cx, (float)cy);
vec2_set(&filter->dimension_i, 1.0f / (float)cx, 1.0f / (float)cy);
if (filter->undistort) {
@@ -211,6 +215,8 @@ static void scale_filter_tick(void *data, float seconds)
filter->undistort_factor = 1.0;
}
filter->upscale = false;
/* ------------------------- */
lower_than_2x = filter->cx_out < cx / 2 || filter->cy_out < cy / 2;
@@ -232,6 +238,8 @@ static void scale_filter_tick(void *data, float seconds)
break;
case OBS_SCALE_AREA:
type = OBS_EFFECT_AREA;
if ((filter->cx_out >= cx) && (filter->cy_out >= cy))
filter->upscale = true;
break;
}
}
@@ -242,9 +250,12 @@ static void scale_filter_tick(void *data, float seconds)
if (type != OBS_EFFECT_DEFAULT) {
filter->dimension_param = gs_effect_get_param_by_name(
filter->effect, "base_dimension");
filter->dimension_i_param = gs_effect_get_param_by_name(
filter->effect, "base_dimension_i");
} else {
filter->dimension_param = NULL;
filter->dimension_i_param = NULL;
}
if (type == OBS_EFFECT_BICUBIC || type == OBS_EFFECT_LANCZOS) {
@@ -260,7 +271,9 @@ static void scale_filter_tick(void *data, float seconds)
static void scale_filter_render(void *data, gs_effect_t *effect)
{
struct scale_filter_data *filter = data;
const char *technique = filter->undistort ? "DrawUndistort" : "Draw";
const char *technique =
filter->undistort ? "DrawUndistort"
: (filter->upscale ? "DrawUpscale" : "Draw");
if (!filter->valid || !filter->target_valid) {
obs_source_skip_video_filter(filter->context);
@@ -272,7 +285,10 @@ static void scale_filter_render(void *data, gs_effect_t *effect)
return;
if (filter->dimension_param)
gs_effect_set_vec2(filter->dimension_param,
gs_effect_set_vec2(filter->dimension_param, &filter->dimension);
if (filter->dimension_i_param)
gs_effect_set_vec2(filter->dimension_i_param,
&filter->dimension_i);
if (filter->undistort_factor_param)