Merge pull request #4587 from jpark37/alpha-hack

Apply alpha in nonlinear space for images and async video
master
Jim 2021-04-25 11:26:21 -07:00 committed by GitHub
commit 81e9ad818f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 15 deletions

View File

@ -33,6 +33,35 @@ float4 PSDrawAlphaDivide(VertInOut vert_in) : TARGET
return float4(rgba.rgb * multiplier, alpha);
}
float srgb_linear_to_nonlinear_channel(float u)
{
return (u <= 0.0031308) ? (12.92 * u) : ((1.055 * pow(u, 1.0 / 2.4)) - 0.055);
}
float3 srgb_linear_to_nonlinear(float3 v)
{
return float3(srgb_linear_to_nonlinear_channel(v.r), srgb_linear_to_nonlinear_channel(v.g), srgb_linear_to_nonlinear_channel(v.b));
}
float srgb_nonlinear_to_linear_channel(float u)
{
return (u <= 0.04045) ? (u / 12.92) : pow((u + 0.055) / 1.055, 2.4);
}
float3 srgb_nonlinear_to_linear(float3 v)
{
return float3(srgb_nonlinear_to_linear_channel(v.r), srgb_nonlinear_to_linear_channel(v.g), srgb_nonlinear_to_linear_channel(v.b));
}
float4 PSDrawNonlinearAlpha(VertInOut vert_in) : TARGET
{
float4 rgba = image.Sample(def_sampler, vert_in.uv);
rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb);
rgba.rgb *= rgba.a;
rgba.rgb = srgb_nonlinear_to_linear(rgba.rgb);
return rgba;
}
technique Draw
{
pass
@ -50,3 +79,12 @@ technique DrawAlphaDivide
pixel_shader = PSDrawAlphaDivide(vert_in);
}
}
technique DrawNonlinearAlpha
{
pass
{
vertex_shader = VSDefault(vert_in);
pixel_shader = PSDrawNonlinearAlpha(vert_in);
}
}

View File

@ -2056,17 +2056,30 @@ static void obs_source_draw_async_texture(struct obs_source *source)
{
gs_effect_t *effect = gs_get_effect();
bool def_draw = (!effect);
bool premultiplied = false;
gs_technique_t *tech = NULL;
if (def_draw) {
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
tech = gs_effect_get_technique(effect, "Draw");
const bool linear = gs_get_linear_srgb();
const char *tech_name = linear ? "DrawNonlinearAlpha" : "Draw";
premultiplied = linear;
tech = gs_effect_get_technique(effect, tech_name);
gs_technique_begin(tech);
gs_technique_begin_pass(tech, 0);
}
if (premultiplied) {
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
}
obs_source_draw_texture(source, effect);
if (premultiplied) {
gs_blend_state_pop();
}
if (def_draw) {
gs_technique_end_pass(tech);
gs_technique_end(tech);
@ -3701,10 +3714,11 @@ bool obs_source_process_filter_begin(obs_source_t *filter,
filter->filter_texrender =
gs_texrender_create(format, GS_ZS_NONE);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
if (gs_texrender_begin(filter->filter_texrender, cx, cy)) {
gs_blend_state_push();
gs_blend_function_separate(GS_BLEND_SRCALPHA, GS_BLEND_ZERO,
GS_BLEND_ONE, GS_BLEND_ZERO);
bool custom_draw = (parent_flags & OBS_SOURCE_CUSTOM_DRAW) != 0;
bool async = (parent_flags & OBS_SOURCE_ASYNC) != 0;
struct vec4 clear_color;
@ -3718,10 +3732,10 @@ bool obs_source_process_filter_begin(obs_source_t *filter,
else
obs_source_video_render(target);
gs_blend_state_pop();
gs_texrender_end(filter->filter_texrender);
}
gs_blend_state_pop();
return true;
}
@ -3748,6 +3762,9 @@ static void obs_source_process_filter_tech_end_internal(
const char *tech = tech_name ? tech_name : "Draw";
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
if (can_bypass(target, parent, parent_flags, filter->allow_direct)) {
render_filter_bypass(target, effect, tech);
} else {
@ -3757,6 +3774,8 @@ static void obs_source_process_filter_tech_end_internal(
}
}
gs_blend_state_pop();
gs_set_linear_srgb(previous);
}

View File

@ -147,19 +147,31 @@ static void image_source_render(void *data, gs_effect_t *effect)
if (!context->if2.image.texture)
return;
const bool linear_srgb = gs_get_linear_srgb();
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
gs_technique_t *tech =
gs_effect_get_technique(effect, "DrawNonlinearAlpha");
const bool previous = gs_framebuffer_srgb_enabled();
gs_enable_framebuffer_srgb(linear_srgb);
gs_enable_framebuffer_srgb(true);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
gs_eparam_t *const param = gs_effect_get_param_by_name(effect, "image");
if (linear_srgb)
gs_effect_set_texture_srgb(param, context->if2.image.texture);
else
gs_effect_set_texture(param, context->if2.image.texture);
gs_effect_set_texture_srgb(param, context->if2.image.texture);
gs_draw_sprite(context->if2.image.texture, 0, context->if2.image.cx,
context->if2.image.cy);
size_t passes = gs_technique_begin(tech);
for (size_t i = 0; i < passes; i++) {
gs_technique_begin_pass(tech, i);
gs_draw_sprite(context->if2.image.texture, 0,
context->if2.image.cx, context->if2.image.cy);
gs_technique_end_pass(tech);
}
gs_technique_end(tech);
gs_blend_state_pop();
gs_enable_framebuffer_srgb(previous);
}
@ -298,7 +310,7 @@ static obs_missing_files_t *image_source_missingfiles(void *data)
static struct obs_source_info image_source_info = {
.id = "image_source",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_VIDEO,
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW,
.get_name = image_source_get_name,
.create = image_source_create,
.destroy = image_source_destroy,