libobs: Add high-precision sRGB support

This commit is contained in:
jpark37
2022-04-08 17:19:23 -07:00
committed by Jim
parent 848e128435
commit 06111d5b10
10 changed files with 329 additions and 101 deletions
+83 -61
View File
@@ -1550,8 +1550,10 @@ enum convert_type {
CONVERT_800,
CONVERT_RGB_LIMITED,
CONVERT_BGR3,
CONVERT_I010_SRGB,
CONVERT_I010_PQ_2020_709,
CONVERT_I010_HLG_2020_709,
CONVERT_P010_SRGB,
CONVERT_P010_PQ_2020_709,
CONVERT_P010_HLG_2020_709,
};
@@ -1599,15 +1601,25 @@ static inline enum convert_type get_convert_type(enum video_format format,
return CONVERT_444_A_PACK;
case VIDEO_FORMAT_I010: {
const bool hlg = trc == VIDEO_TRC_HLG;
return hlg ? CONVERT_I010_HLG_2020_709
: CONVERT_I010_PQ_2020_709;
switch (trc) {
case VIDEO_TRC_SRGB:
return CONVERT_I010_SRGB;
case VIDEO_TRC_HLG:
return CONVERT_I010_HLG_2020_709;
default:
return CONVERT_I010_PQ_2020_709;
}
}
case VIDEO_FORMAT_P010: {
const bool hlg = trc == VIDEO_TRC_HLG;
return hlg ? CONVERT_P010_HLG_2020_709
: CONVERT_P010_PQ_2020_709;
switch (trc) {
case VIDEO_TRC_SRGB:
return CONVERT_P010_SRGB;
case VIDEO_TRC_HLG:
return CONVERT_P010_HLG_2020_709;
default:
return CONVERT_P010_PQ_2020_709;
}
}
}
@@ -1885,10 +1897,12 @@ static inline bool init_gpu_conversion(struct obs_source *source,
case CONVERT_444_A_PACK:
return set_packed444_alpha_sizes(source, frame);
case CONVERT_I010_SRGB:
case CONVERT_I010_PQ_2020_709:
case CONVERT_I010_HLG_2020_709:
return set_i010_sizes(source, frame);
case CONVERT_P010_SRGB:
case CONVERT_P010_PQ_2020_709:
case CONVERT_P010_HLG_2020_709:
return set_p010_sizes(source, frame);
@@ -1980,8 +1994,10 @@ static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
case CONVERT_422_A:
case CONVERT_444_A:
case CONVERT_444_A_PACK:
case CONVERT_I010_SRGB:
case CONVERT_I010_PQ_2020_709:
case CONVERT_I010_HLG_2020_709:
case CONVERT_P010_SRGB:
case CONVERT_P010_PQ_2020_709:
case CONVERT_P010_HLG_2020_709:
for (size_t c = 0; c < MAX_AV_PLANES; c++) {
@@ -2041,15 +2057,25 @@ static const char *select_conversion_technique(enum video_format format,
return "AYUV_Reverse";
case VIDEO_FORMAT_I010: {
const bool hlg = trc == VIDEO_TRC_HLG;
return hlg ? "I010_HLG_2020_709_Reverse"
: "I010_PQ_2020_709_Reverse";
switch (trc) {
case VIDEO_TRC_SRGB:
return "I010_SRGB_Reverse";
case VIDEO_TRC_HLG:
return "I010_HLG_2020_709_Reverse";
default:
return "I010_PQ_2020_709_Reverse";
}
}
case VIDEO_FORMAT_P010: {
const bool hlg = trc == VIDEO_TRC_HLG;
return hlg ? "P010_HLG_2020_709_Reverse"
: "P010_PQ_2020_709_Reverse";
switch (trc) {
case VIDEO_TRC_SRGB:
return "P010_SRGB_Reverse";
case VIDEO_TRC_HLG:
return "P010_HLG_2020_709_Reverse";
default:
return "P010_PQ_2020_709_Reverse";
}
}
case VIDEO_FORMAT_BGRA:
@@ -2240,42 +2266,6 @@ static inline void obs_source_draw_texture(struct obs_source *source,
gs_enable_framebuffer_srgb(previous);
}
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);
const bool nonlinear_alpha = gs_get_linear_srgb() &&
!source->async_linear_alpha;
const char *tech_name = nonlinear_alpha ? "DrawNonlinearAlpha"
: "Draw";
premultiplied = nonlinear_alpha;
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);
}
}
static void recreate_async_texture(obs_source_t *source,
enum gs_color_format format)
{
@@ -2354,37 +2344,53 @@ static void rotate_async_video(obs_source_t *source, long rotation)
static inline void obs_source_render_async_video(obs_source_t *source)
{
if (source->async_textures[0] && source->async_active) {
enum gs_color_space source_space = GS_CS_SRGB;
if (source->async_color_format == GS_RGBA16F) {
source_space = (source->async_trc == VIDEO_TRC_SRGB)
? GS_CS_SRGB_16F
: GS_CS_709_EXTENDED;
}
gs_effect_t *const effect =
obs_get_base_effect(OBS_EFFECT_DEFAULT);
const char *tech_name = "Draw";
float multiplier = 1.0;
const enum gs_color_space source_space =
(source->async_color_format == GS_RGBA16F)
? GS_CS_709_EXTENDED
: GS_CS_SRGB;
const enum gs_color_space current_space = gs_get_color_space();
bool linear_srgb = gs_get_linear_srgb();
const bool linear_srgb = gs_get_linear_srgb();
bool nonlinear_alpha = false;
switch (source_space) {
case GS_CS_SRGB:
nonlinear_alpha = linear_srgb &&
!source->async_linear_alpha;
switch (current_space) {
case GS_CS_SRGB:
if (linear_srgb &&
!source->async_linear_alpha) {
case GS_CS_SRGB_16F:
case GS_CS_709_EXTENDED:
if (nonlinear_alpha)
tech_name = "DrawNonlinearAlpha";
}
break;
case GS_CS_709_SCRGB:
tech_name =
nonlinear_alpha
? "DrawNonlinearAlphaMultiply"
: "DrawMultiply";
multiplier =
obs_get_video_sdr_white_level() / 80.0f;
}
break;
case GS_CS_SRGB_16F:
switch (current_space) {
case GS_CS_709_SCRGB:
tech_name = "DrawMultiply";
multiplier =
obs_get_video_sdr_white_level() / 80.0f;
linear_srgb = true;
}
break;
case GS_CS_709_EXTENDED:
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
tech_name = "DrawTonemap";
linear_srgb = true;
break;
case GS_CS_709_SCRGB:
tech_name = "DrawMultiply";
@@ -2395,10 +2401,10 @@ static inline void obs_source_render_async_video(obs_source_t *source)
case GS_CS_709_SCRGB:
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
tech_name = "DrawMultiplyTonemap";
multiplier =
80.0f / obs_get_video_sdr_white_level();
linear_srgb = true;
break;
case GS_CS_709_EXTENDED:
tech_name = "DrawMultiply";
@@ -2422,7 +2428,18 @@ static inline void obs_source_render_async_video(obs_source_t *source)
gs_matrix_push();
rotate_async_video(source, rotation);
}
obs_source_draw_async_texture(source);
if (nonlinear_alpha) {
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
}
obs_source_draw_texture(source, effect);
if (nonlinear_alpha) {
gs_blend_state_pop();
}
if (rotation) {
gs_matrix_pop();
}
@@ -2509,6 +2526,7 @@ static void source_render(obs_source_t *source, gs_effect_t *effect)
enum gs_color_format format = gs_get_format_from_space(source_space);
switch (source_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
switch (current_space) {
case GS_CS_709_EXTENDED:
convert_tech = "Draw";
@@ -2521,6 +2539,7 @@ static void source_render(obs_source_t *source, gs_effect_t *effect)
case GS_CS_709_EXTENDED:
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
convert_tech = "DrawTonemap";
break;
case GS_CS_709_SCRGB:
@@ -2531,6 +2550,7 @@ static void source_render(obs_source_t *source, gs_effect_t *effect)
case GS_CS_709_SCRGB:
switch (current_space) {
case GS_CS_SRGB:
case GS_CS_SRGB_16F:
convert_tech = "DrawMultiplyTonemap";
multiplier = 80.0f / obs_get_video_sdr_white_level();
break;
@@ -2796,7 +2816,9 @@ obs_source_get_color_space(obs_source_t *source, size_t count,
}
if (source->info.output_flags & OBS_SOURCE_ASYNC) {
return convert_video_space(source->async_format, count,
return convert_video_space(source->async_format,
source->async_trc,
source->async_color_format, count,
preferred_spaces);
}