image-source: Premultiply images on load

This ensures correct texture filtering, simplifies the render callback,
and allows us to remove the custom draw flag, restoring the direct
rendering optimization for filters against image sources.
This commit is contained in:
jpark37 2021-05-10 22:23:55 -07:00
parent abe1cb1425
commit 3ee57878a3

View file

@ -23,7 +23,7 @@ struct image_source {
uint64_t last_time;
bool active;
gs_image_file2_t if2;
gs_image_file3_t if3;
};
static time_t get_modified_timestamp(const char *filename)
@ -45,20 +45,23 @@ static void image_source_load(struct image_source *context)
char *file = context->file;
obs_enter_graphics();
gs_image_file2_free(&context->if2);
gs_image_file3_free(&context->if3);
obs_leave_graphics();
if (file && *file) {
debug("loading texture '%s'", file);
context->file_timestamp = get_modified_timestamp(file);
gs_image_file2_init(&context->if2, file);
gs_image_file3_init(&context->if3, file,
context->linear_alpha
? GS_IMAGE_ALPHA_PREMULTIPLY_SRGB
: GS_IMAGE_ALPHA_PREMULTIPLY);
context->update_time_elapsed = 0;
obs_enter_graphics();
gs_image_file2_init_texture(&context->if2);
gs_image_file3_init_texture(&context->if3);
obs_leave_graphics();
if (!context->if2.image.loaded)
if (!context->if3.image2.image.loaded)
warn("failed to load texture '%s'", file);
}
}
@ -66,7 +69,7 @@ static void image_source_load(struct image_source *context)
static void image_source_unload(struct image_source *context)
{
obs_enter_graphics();
gs_image_file2_free(&context->if2);
gs_image_file3_free(&context->if3);
obs_leave_graphics();
}
@ -135,28 +138,22 @@ static void image_source_destroy(void *data)
static uint32_t image_source_getwidth(void *data)
{
struct image_source *context = data;
return context->if2.image.cx;
return context->if3.image2.image.cx;
}
static uint32_t image_source_getheight(void *data)
{
struct image_source *context = data;
return context->if2.image.cy;
return context->if3.image2.image.cy;
}
static void image_source_render(void *data, gs_effect_t *effect)
{
struct image_source *context = data;
if (!context->if2.image.texture)
if (!context->if3.image2.image.texture)
return;
const char *tech_name = context->linear_alpha ? "DrawAlphaBlend"
: "DrawNonlinearAlpha";
effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
gs_technique_t *tech = gs_effect_get_technique(effect, tech_name);
const bool previous = gs_framebuffer_srgb_enabled();
gs_enable_framebuffer_srgb(true);
@ -164,18 +161,11 @@ static void image_source_render(void *data, gs_effect_t *effect)
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
gs_eparam_t *const param = gs_effect_get_param_by_name(effect, "image");
gs_effect_set_texture_srgb(param, context->if2.image.texture);
gs_effect_set_texture_srgb(param, context->if3.image2.image.texture);
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_draw_sprite(context->if3.image2.image.texture, 0,
context->if3.image2.image.cx,
context->if3.image2.image.cy);
gs_blend_state_pop();
@ -202,20 +192,20 @@ static void image_source_tick(void *data, float seconds)
if (obs_source_active(context->source)) {
if (!context->active) {
if (context->if2.image.is_animated_gif)
if (context->if3.image2.image.is_animated_gif)
context->last_time = frame_time;
context->active = true;
}
} else {
if (context->active) {
if (context->if2.image.is_animated_gif) {
context->if2.image.cur_frame = 0;
context->if2.image.cur_loop = 0;
context->if2.image.cur_time = 0;
if (context->if3.image2.image.is_animated_gif) {
context->if3.image2.image.cur_frame = 0;
context->if3.image2.image.cur_loop = 0;
context->if3.image2.image.cur_time = 0;
obs_enter_graphics();
gs_image_file2_update_texture(&context->if2);
gs_image_file3_update_texture(&context->if3);
obs_leave_graphics();
}
@ -225,13 +215,13 @@ static void image_source_tick(void *data, float seconds)
return;
}
if (context->last_time && context->if2.image.is_animated_gif) {
if (context->last_time && context->if3.image2.image.is_animated_gif) {
uint64_t elapsed = frame_time - context->last_time;
bool updated = gs_image_file2_tick(&context->if2, elapsed);
bool updated = gs_image_file3_tick(&context->if3, elapsed);
if (updated) {
obs_enter_graphics();
gs_image_file2_update_texture(&context->if2);
gs_image_file3_update_texture(&context->if3);
obs_leave_graphics();
}
}
@ -281,7 +271,7 @@ static obs_properties_t *image_source_properties(void *data)
uint64_t image_source_get_memory_usage(void *data)
{
struct image_source *s = data;
return s->if2.mem_usage;
return s->if3.image2.mem_usage;
}
static void missing_file_callback(void *src, const char *new_path, void *data)
@ -318,8 +308,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 | OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_SRGB,
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_SRGB,
.get_name = image_source_get_name,
.create = image_source_create,
.destroy = image_source_destroy,