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:
@@ -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)
|
||||
|
Reference in New Issue
Block a user