libobs: Add dormant SRGB format support

GS_RGBA, GS_BGRX, and GS_BGRA now use TYPELESS DXGI formats, so we can
alias them between UNORM and UNORM_SRGB as necessary. GS_RGBA_UNORM,
GS_BGRX_UNORM, and GS_BGRA_UNORM have been added to support straight
UNORM types, which Windows requires for sharing textures from D3D9 and
OpenGL. The D3D path aliases via views, and GL aliases via
GL_EXT_texture_sRGB_decode/GL_FRAMEBUFFER_SRGB.

A significant amount of code has changed in the D3D/GL backends, but the
concepts are simple. On the D3D side, we need separate SRVs and RTVs to
support nonlinear/linear reads and writes. On the GL side, we need to
set the proper GL parameters to emulate the same.

Add gs_enable_framebuffer_srgb/gs_framebuffer_srgb_enabled to set/get
the framebuffer as SRGB or not.

Add gs_linear_srgb_active/gs_set_linear_srgb to instruct sources that
they should render as SRGB. Legacy sources can ignore this setting
without regression.

Update obs_source_draw to use linear SRGB as needed.

Update render_filter_tex to use linear SRGB as needed.

Add gs_effect_set_texture_srgb next to gs_effect_set_texture to set
texture with SRGB view instead.

Add SRGB helpers for vec4 struct.

Create GDI-compatible textures without SRGB support. Doesn't seem to
work with SRGB formats.
This commit is contained in:
jpark37
2021-01-19 15:00:51 -08:00
parent 7427272062
commit 66259560e0
18 changed files with 667 additions and 187 deletions

View File

@@ -525,8 +525,13 @@ static void program_set_param_data(struct gs_program *program,
}
glUniform1i(pp->obj, pp->param->texture_id);
device_load_texture(program->device, pp->param->texture,
pp->param->texture_id);
if (pp->param->srgb)
device_load_texture_srgb(program->device,
pp->param->texture,
pp->param->texture_id);
else
device_load_texture(program->device, pp->param->texture,
pp->param->texture_id);
}
}
@@ -757,7 +762,7 @@ void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
expected_size = sizeof(float) * 4 * 4;
break;
case GS_SHADER_PARAM_TEXTURE:
expected_size = sizeof(void *);
expected_size = sizeof(struct gs_shader_texture);
break;
default:
expected_size = 0;
@@ -773,10 +778,14 @@ void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
return;
}
if (param->type == GS_SHADER_PARAM_TEXTURE)
gs_shader_set_texture(param, *(gs_texture_t **)val);
else
if (param->type == GS_SHADER_PARAM_TEXTURE) {
struct gs_shader_texture shader_tex;
memcpy(&shader_tex, val, sizeof(shader_tex));
gs_shader_set_texture(param, shader_tex.tex);
param->srgb = shader_tex.srgb;
} else {
da_copy_array(param->cur_value, val, size);
}
}
void gs_shader_set_default(gs_sparam_t *param)

View File

@@ -138,6 +138,12 @@ static bool gl_init_extensions(struct gs_device *device)
gl_enable_debug();
if (!GLAD_GL_EXT_texture_sRGB_decode) {
blog(LOG_ERROR, "OpenGL extension EXT_texture_sRGB_decode "
"is required.");
return false;
}
gl_enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ARB_copy_image)
@@ -492,7 +498,8 @@ static inline struct gs_shader_param *get_texture_param(gs_device_t *device,
return NULL;
}
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
static void device_load_texture_internal(gs_device_t *device, gs_texture_t *tex,
int unit, GLint decode)
{
struct gs_shader_param *param;
struct gs_sampler_state *sampler;
@@ -530,6 +537,10 @@ void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
if (!gl_bind_texture(tex->gl_target, tex->texture))
goto fail;
if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_SRGB_DECODE_EXT, decode))
goto fail;
if (sampler && !load_texture_sampler(tex, sampler))
goto fail;
@@ -539,6 +550,16 @@ fail:
blog(LOG_ERROR, "device_load_texture (GL) failed");
}
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
{
device_load_texture_internal(device, tex, unit, GL_SKIP_DECODE_EXT);
}
void device_load_texture_srgb(gs_device_t *device, gs_texture_t *tex, int unit)
{
device_load_texture_internal(device, tex, unit, GL_DECODE_EXT);
}
static bool load_sampler_on_textures(gs_device_t *device, gs_samplerstate_t *ss,
int sampler_unit)
{
@@ -863,6 +884,21 @@ fail:
blog(LOG_ERROR, "device_set_cube_render_target (GL) failed");
}
void device_enable_framebuffer_srgb(gs_device_t *device, bool enable)
{
if (enable)
gl_enable(GL_FRAMEBUFFER_SRGB);
else
gl_disable(GL_FRAMEBUFFER_SRGB);
}
bool device_framebuffer_srgb_enabled(gs_device_t *device)
{
const GLboolean enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB);
gl_success("glIsEnabled");
return enabled == GL_TRUE;
}
void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst,
uint32_t dst_x, uint32_t dst_y,
gs_texture_t *src, uint32_t src_x,

View File

@@ -71,6 +71,12 @@ static inline GLenum convert_gs_format(enum gs_color_format format)
return GL_RGBA;
case GS_DXT5:
return GL_RGBA;
case GS_RGBA_UNORM:
return GL_RGBA;
case GS_BGRX_UNORM:
return GL_BGRA;
case GS_BGRA_UNORM:
return GL_BGRA;
case GS_UNKNOWN:
return 0;
}
@@ -86,11 +92,11 @@ static inline GLenum convert_gs_internal_format(enum gs_color_format format)
case GS_R8:
return GL_R8;
case GS_RGBA:
return GL_RGBA;
return GL_SRGB8_ALPHA8;
case GS_BGRX:
return GL_RGB;
return GL_SRGB8;
case GS_BGRA:
return GL_RGBA;
return GL_SRGB8_ALPHA8;
case GS_R10G10B10A2:
return GL_RGB10_A2;
case GS_RGBA16:
@@ -117,6 +123,12 @@ static inline GLenum convert_gs_internal_format(enum gs_color_format format)
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case GS_DXT5:
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case GS_RGBA_UNORM:
return GL_RGBA;
case GS_BGRX_UNORM:
return GL_RGB;
case GS_BGRA_UNORM:
return GL_RGBA;
case GS_UNKNOWN:
return 0;
}
@@ -163,6 +175,12 @@ static inline GLenum get_gl_format_type(enum gs_color_format format)
return GL_UNSIGNED_BYTE;
case GS_DXT5:
return GL_UNSIGNED_BYTE;
case GS_RGBA_UNORM:
return GL_UNSIGNED_BYTE;
case GS_BGRX_UNORM:
return GL_UNSIGNED_BYTE;
case GS_BGRA_UNORM:
return GL_UNSIGNED_BYTE;
case GS_UNKNOWN:
return 0;
}
@@ -411,6 +429,7 @@ struct gs_shader_param {
int array_count;
struct gs_texture *texture;
bool srgb;
DARRAY(uint8_t) cur_value;
DARRAY(uint8_t) def_value;