(API Change) libobs: Add bicubic/lanczos scaling

This adds bicubic and lanczos scaling capability to libobs to improve
scaling quality and sharpness when the output resolution has to be
scaled relative to the base resolution.  Bilinear is also available,
although bilinear has rather poor quality and causes scaling to appear
blurry.

If the output resolution is close to the base resolution, then bilinear
is used instead as an optimization, as there's no need to use these
shaders if scaling is not in use.

The Bicubic and Lanczos effects are also exposed via exported function
to allow the ability to use those shaders in plugin modules if desired.

The API change adds a variable 'scale_type' to the obs_video_info
structure that allows the user interface to choose what type of scaling
filter should be used.
This commit is contained in:
jp9000
2014-12-14 23:45:44 -08:00
parent 1b454647bd
commit c88220552f
6 changed files with 358 additions and 2 deletions

View File

@@ -109,6 +109,44 @@ static inline void render_main_texture(struct obs_core_video *video,
video->textures_rendered[cur_texture] = true;
}
static inline gs_effect_t *get_scale_effect_internal(
struct obs_core_video *video)
{
switch (video->scale_type) {
case OBS_SCALE_BILINEAR: return video->default_effect;
case OBS_SCALE_LANCZOS: return video->lanczos_effect;
case OBS_SCALE_BICUBIC:;
}
return video->bicubic_effect;
}
static inline bool resolution_close(struct obs_core_video *video,
uint32_t width, uint32_t height)
{
long width_cmp = (long)video->base_width - (long)width;
long height_cmp = (long)video->base_height - (long)height;
return labs(width_cmp) <= 16 && labs(height_cmp) <= 16;
}
static inline gs_effect_t *get_scale_effect(struct obs_core_video *video,
uint32_t width, uint32_t height)
{
if (resolution_close(video, width, height)) {
return video->default_effect;
} else {
/* if the scale method couldn't be loaded, use either bicubic
* or bilinear by default */
gs_effect_t *effect = get_scale_effect_internal(video);
if (!effect)
effect = !!video->bicubic_effect ?
video->bicubic_effect :
video->default_effect;
return effect;
}
}
static inline void render_output_texture(struct obs_core_video *video,
int cur_texture, int prev_texture)
{
@@ -116,13 +154,19 @@ static inline void render_output_texture(struct obs_core_video *video,
gs_texture_t *target = video->output_textures[cur_texture];
uint32_t width = gs_texture_get_width(target);
uint32_t height = gs_texture_get_height(target);
struct vec2 base_i;
/* TODO: replace with actual downscalers or unpackers */
gs_effect_t *effect = video->default_effect;
vec2_set(&base_i,
1.0f / (float)video->base_width,
1.0f / (float)video->base_height);
gs_effect_t *effect = get_scale_effect(video, width, height);
gs_technique_t *tech = gs_effect_get_technique(effect, "DrawMatrix");
gs_eparam_t *image = gs_effect_get_param_by_name(effect, "image");
gs_eparam_t *matrix = gs_effect_get_param_by_name(effect,
"color_matrix");
gs_eparam_t *bres_i = gs_effect_get_param_by_name(effect,
"base_dimension_i");
size_t passes, i;
if (!video->textures_rendered[prev_texture])
@@ -131,6 +175,9 @@ static inline void render_output_texture(struct obs_core_video *video,
gs_set_render_target(target, NULL);
set_render_size(width, height);
if (bres_i)
gs_effect_set_vec2(bres_i, &base_i);
gs_effect_set_val(matrix, video->color_matrix, sizeof(float) * 16);
gs_effect_set_texture(image, texture);