Work on getting rendering of background image with background_opacity < 1 to work somewhat correctly at least

This commit is contained in:
Kovid Goyal
2025-08-08 14:22:12 +05:30
parent 7dc78046c0
commit 3165c5d852
3 changed files with 53 additions and 21 deletions

View File

@@ -7,6 +7,7 @@ uniform float text_contrast;
uniform float text_gamma_adjustment;
uniform float for_final_output;
uniform float has_under_bg;
uniform float has_background_image;
uniform sampler2DArray sprites;
uniform sampler2D under_bg_layer;
uniform sampler2D under_fg_layer;
@@ -103,10 +104,15 @@ vec4 layer_color(sampler2D s) {
void main() {
vec4 ans_premul = vec4_premul(background);
#ifdef HAS_LAYERS
// if its a default background cell and there is an under_bg layer, use the
// under_bg layer blended onto the background, as the background
blend_layer(ans_premul = if_one_then(has_under_bg * cell_has_default_bg,
alpha_blend_premul(layer_color(under_bg_layer), ans_premul), ans_premul));
// under_bg layer blended onto the background, as the background. If there
// is a background image then dont blend onto the background as the
// background image is our background.
vec4 under_bg_color = layer_color(under_bg_layer);
under_bg_color = if_one_then(has_background_image, under_bg_color, alpha_blend_premul(under_bg_color, ans_premul));
blend_layer(ans_premul = if_one_then(has_under_bg * cell_has_default_bg, under_bg_color, ans_premul));
#endif
// blend in the under_fg layer
blend_layer(ans_premul = alpha_blend_premul(layer_color(under_fg_layer), ans_premul));
// blend in the foreground color

View File

@@ -119,7 +119,7 @@ typedef struct {
struct { uint32_t graphics_change_count; } under_fg_layer;
struct {
struct { bool was_drawn; uint32_t change_count; } graphics;
struct { bool was_drawn; uint32_t render_counter; } bgimage;
struct { bool was_drawn; uint32_t render_counter; float background_opacity; } bgimage;
struct { bool was_drawn; unsigned width, height; int left, top; window_logo_id_t id; float alpha; } logo;
} under_bg_layer;
} last_rendered;

View File

@@ -41,6 +41,7 @@ typedef struct UIRenderData {
GraphicsRenderData grd;
WindowLogoRenderData *window_logo;
float inactive_text_alpha;
bool has_background_image;
} UIRenderData;
// Sprites {{{
@@ -74,6 +75,9 @@ color_vec4_premult(GLint location, color_type color, GLfloat alpha) {
}
static void
clear_canvas(void) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); }
SPRITE_MAP_HANDLE
alloc_sprite_map(void) {
if (!max_texture_size) {
@@ -677,18 +681,38 @@ ensure_layer_ready_to_render(ScreenLayer *which, unsigned screen_width, unsigned
return needs_redraw;
}
static float
linear_to_srgb(float c) { return (c <= 0.0031308f) ? 12.92f * c : 1.055f * powf(c, 1.0f / 2.4f) - 0.055f; }
static void
save_texture_as_png(GLuint texture_id, unsigned width, unsigned height, const char *filename) {
save_texture_as_png(GLuint texture_id, const char *filename) {
GLint prev_tex = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex);
glBindTexture(GL_TEXTURE_2D, texture_id);
int width = 0, height = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
size_t sz = width * height * sizeof(uint32_t);
uint32_t* data = malloc(sz);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
// assume data is linear and pre0multiplied
for (int i = 0; i < width * height; i++) {
uint32_t px = data[i];
uint8_t r = (px >> 0) & 0xFF; uint8_t g = (px >> 8) & 0xFF; uint8_t b = (px >> 16) & 0xFF;
uint8_t a = (px >> 24) & 0xFF; float alpha = a / 255.0f;
float rf = 0, gf = 0, bf = 0;
if (alpha > 0.0f) { rf = (r / 255.0f) / alpha; gf = (g / 255.0f) / alpha; bf = (b / 255.0f) / alpha; }
rf = linear_to_srgb(rf); gf = linear_to_srgb(gf); bf = linear_to_srgb(bf);
r = (uint8_t)(rf*255); g = (uint8_t)(gf * 255); b = (uint8_t)(bf * 255);
data[i] = (r << 0) | (g << 8) | (b << 16) | (a << 24);
}
const char *png = png_from_32bit_rgba(data, width, height, &sz, true);
if (!sz) fatal("Failed to save PNG to %s with error: %s", filename, png);
free(data);
FILE* file = fopen(filename, "wb");
fwrite(png, 1, sz, file);
fclose(file);
glBindTexture(GL_TEXTURE_2D, prev_tex);
}
static void
@@ -929,12 +953,12 @@ update_ui_layer(const UIRenderData *ui, bool cell_size_changed) {
needs_redraw |= scrollbar_needs_redraw || visual_bell_needs_redraw || hyperlink_target_needs_redraw || window_number_needs_redraw;
if (needs_redraw || ui->screen->reload_all_gpu_data) {
blank_canvas(0, 0); // clear the framebuffer
clear_canvas();
if (visual_bell_drawn && intensity > 0) draw_visual_bell_flash(lvb.intensity, lvb.color);
if (scrollback_indicator_drawn) draw_scroll_indicator(bar_color, bar_alpha, bar_frac, ui);
if (hyperlink_target_drawn) draw_hyperlink_target(screen, ui, ht.along_bottom);
if (window_number_drawn) draw_window_number(ui);
if (0) save_texture_as_png(screen->textures.ui.id, ui->screen_width, ui->screen_height, "/tmp/ui.png");
if (0) save_texture_as_png(screen->textures.ui.id, "/tmp/ui.png");
}
#undef wn
#undef ht
@@ -990,30 +1014,31 @@ get_window_logo_settings(const UIRenderData *ui, Screen *s, bool has_logo) {
static void
update_under_bg_layer(const UIRenderData *ui) {
const bool has_graphics = ui->grd.num_of_below_refs > 0;
const bool has_bg = has_bgimage(ui->os_window);
const bool has_logo = ui->window_logo != NULL;
ui->screen->textures.under_bg.present = has_bg || has_graphics || has_logo;
ui->screen->textures.under_bg.present = ui->has_background_image || has_graphics || has_logo;
if (!ui->screen->textures.under_bg.present) return;
bool needs_redraw = ensure_layer_ready_to_render(&ui->screen->textures.under_bg, ui->screen_width, ui->screen_height);
#define lr ui->screen->last_rendered.under_bg_layer
needs_redraw |= lr.graphics.change_count != ui->grd.change_count || lr.graphics.was_drawn != has_graphics;
lr.graphics.change_count = ui->grd.change_count; lr.graphics.was_drawn = has_graphics;
needs_redraw |= lr.bgimage.was_drawn != has_bg || lr.bgimage.render_counter != ui->os_window->bgimage.render_counter;
lr.bgimage.was_drawn = has_bg; lr.bgimage.render_counter = ui->os_window->bgimage.render_counter;
float background_opacity = ui->os_window->is_semi_transparent ? ui->os_window->background_opacity : 1.0f;
needs_redraw |= lr.bgimage.was_drawn != ui->has_background_image || lr.bgimage.render_counter != ui->os_window->bgimage.render_counter || lr.bgimage.background_opacity != background_opacity;
lr.bgimage.was_drawn = ui->has_background_image; lr.bgimage.render_counter = ui->os_window->bgimage.render_counter;
lr.bgimage.background_opacity = background_opacity;
needs_redraw |= get_window_logo_settings(ui, ui->screen, has_logo);
if (needs_redraw | ui->screen->reload_all_gpu_data) {
blank_canvas(0, 0); // clear the framebuffer
if (has_bg) {
clear_canvas();
if (ui->has_background_image) {
ImageRenderData d = {.texture_id = ui->os_window->bgimage.rendered_texture_id};
gpu_data_for_image(&d, -1, 1, 1, -1);
d.src_rect.left = tex_pos_x(ui->screen_left, ui->full_framebuffer_width);
d.src_rect.top = tex_pos_y(ui->screen_top, ui->full_framebuffer_height);
d.src_rect.right = tex_pos_x(ui->screen_left + ui->screen_width, ui->full_framebuffer_width);
d.src_rect.bottom = tex_pos_y(ui->screen_top + ui->screen_height, ui->full_framebuffer_height);
draw_graphics(GRAPHICS_PROGRAM, &d, 0, 1, 1.f);
draw_graphics(GRAPHICS_PROGRAM, &d, 0, 1, lr.bgimage.background_opacity);
}
if (has_logo) {
float left = gl_pos_x(lr.logo.left, ui->screen_width), top = gl_pos_y(lr.logo.top, ui->screen_height);
@@ -1023,7 +1048,7 @@ update_under_bg_layer(const UIRenderData *ui) {
}
if (has_graphics) draw_graphics(
GRAPHICS_PROGRAM, ui->grd.images, 0, ui->grd.num_of_below_refs, ui->inactive_text_alpha);
if (0) save_texture_as_png(ui->screen->textures.under_bg.id, ui->screen_width, ui->screen_height, "/tmp/under-bg.png");
if (0) save_texture_as_png(ui->screen->textures.under_bg.id, "/tmp/under-bg.png");
}
#undef lr
}
@@ -1036,7 +1061,7 @@ update_under_fg_layer(const UIRenderData *ui) {
needs_redraw |= ui->screen->last_rendered.under_fg_layer.graphics_change_count != ui->grd.change_count;
ui->screen->last_rendered.under_fg_layer.graphics_change_count = ui->grd.change_count;
if (needs_redraw | ui->screen->reload_all_gpu_data) {
blank_canvas(0, 0); // clear the framebuffer
clear_canvas();
if (ui->grd.num_of_negative_refs) draw_graphics(
GRAPHICS_PROGRAM, ui->grd.images, ui->grd.num_of_below_refs,
ui->grd.num_of_negative_refs, ui->inactive_text_alpha);
@@ -1051,7 +1076,7 @@ update_over_fg_layer(const UIRenderData *ui) {
needs_redraw |= ui->screen->last_rendered.over_fg_layer.graphics_change_count != ui->grd.change_count;
ui->screen->last_rendered.over_fg_layer.graphics_change_count = ui->grd.change_count;
if (needs_redraw | ui->screen->reload_all_gpu_data) {
blank_canvas(0, 0); // clear the framebuffer
clear_canvas();
if (ui->grd.num_of_positive_refs) draw_graphics(
GRAPHICS_PROGRAM, ui->grd.images, ui->grd.num_of_negative_refs + ui->grd.num_of_below_refs,
ui->grd.num_of_positive_refs, ui->inactive_text_alpha);
@@ -1120,6 +1145,7 @@ draw_cells_with_layers(bool for_final_output, const UIRenderData *ui, ssize_t va
}
glUniform1f(cell_program_layouts[program].uniforms.has_under_bg, ui->screen->textures.under_bg.present);
glUniform1f(cell_program_layouts[program].uniforms.inactive_text_alpha, ui->inactive_text_alpha);
glUniform1f(cell_program_layouts[program].uniforms.has_background_image, ui->has_background_image ? 1.f : 0.f);
CELL_BUFFERS;
bind_vao_uniform_buffer(vao_idx, uniform_buffer, cell_program_layouts[program].render_data.index);
save_viewport_using_top_left_origin(
@@ -1176,7 +1202,7 @@ draw_cells(bool for_final_output, const WindowRenderData *srd, OSWindow *os_wind
.screen_left = srd->geometry.left, .screen_top = srd->geometry.top,
.full_framebuffer_width = os_window->viewport_width, .full_framebuffer_height = os_window->viewport_height,
.window = window, .screen = screen, .os_window = os_window, .grd = grman_render_data(grman), .window_logo = wl,
.inactive_text_alpha = current_inactive_text_alpha,
.inactive_text_alpha = current_inactive_text_alpha, .has_background_image = has_bgimage(os_window),
};
update_screen_layers(&ui);
screen->reload_all_gpu_data = false;
@@ -1253,7 +1279,7 @@ draw_bgimage(GLuint texture_id, BackgroundImageRenderSettings s, unsigned image_
glActiveTexture(GL_TEXTURE0 + BGIMAGE_UNIT);
glBindTexture(GL_TEXTURE_2D, texture_id);
save_viewport_using_bottom_left_origin(0, 0, s.os_window.width, s.os_window.height);
blank_canvas(0, 0);
clear_canvas();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
restore_viewport();
unbind_program();
@@ -1276,8 +1302,8 @@ ensure_bgimage_texture(OSWindow *os_window) {
draw_bgimage(os_window->bgimage.instance->texture_id, s, os_window->bgimage.instance->width, os_window->bgimage.instance->height);
bind_framebuffer_for_output(0);
free_framebuffer(&framebuffer_id);
if (0) save_texture_as_png(os_window->bgimage.instance->texture_id, os_window->bgimage.instance->width, os_window->bgimage.instance->height, "/tmp/bg-image.png");
if (0) save_texture_as_png(os_window->bgimage.rendered_texture_id, s.os_window.width, s.os_window.height, "/tmp/bg-layer.png");
if (0) save_texture_as_png(os_window->bgimage.instance->texture_id, "/tmp/bg-image.png");
if (0) save_texture_as_png(os_window->bgimage.rendered_texture_id, "/tmp/bg-layer.png");
os_window->bgimage.render_counter++;
}
os_window->bgimage.last_rendered = s;