aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/render.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-12 22:36:11 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-12 22:36:11 +1000
commitc699a86e472d81c4654f19d39e42eb8cfd64bd94 (patch)
treed73f1824e5d76f4a6556e1d9a880329517847e00 /sway/desktop/render.c
parentMerge pull request #2821 from meakio/master (diff)
downloadsway-c699a86e472d81c4654f19d39e42eb8cfd64bd94.tar.gz
sway-c699a86e472d81c4654f19d39e42eb8cfd64bd94.tar.zst
sway-c699a86e472d81c4654f19d39e42eb8cfd64bd94.zip
Fix pixel leaks when using fractional scaling
The basic idea here is to apply rounding after scaling. It's not as simple as this, though, and I've detailed it in the comments for a function. In order to fix some pixel leaks in the title bar, I found it easier to change how we place rectangles to fill the area. Instead of placing two rectangles across the full width above and below the title and having shorter rectangles in the inner area, it's now pieced together in vertical chunks. This method involves drawing two less rectangles per container.
Diffstat (limited to 'sway/desktop/render.c')
-rw-r--r--sway/desktop/render.c165
1 files changed, 81 insertions, 84 deletions
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 3617da87..9b26c560 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -33,11 +33,27 @@ struct render_data {
33 float alpha; 33 float alpha;
34}; 34};
35 35
36/**
37 * Apply scale to a width or height.
38 *
39 * One does not simply multiply the width by the scale. We allow fractional
40 * scaling, which means the resulting scaled width might be a decimal.
41 * So we round it.
42 *
43 * But even this can produce undesirable results depending on the X or Y offset
44 * of the box. For example, with a scale of 1.5, a box with width=1 should not
45 * scale to 2px if its X coordinate is 1, because the X coordinate would have
46 * scaled to 2px.
47 */
48static int scale_length(int length, int offset, float scale) {
49 return round((offset + length) * scale) - round(offset * scale);
50}
51
36static void scale_box(struct wlr_box *box, float scale) { 52static void scale_box(struct wlr_box *box, float scale) {
37 box->x *= scale; 53 box->width = scale_length(box->width, box->x, scale);
38 box->y *= scale; 54 box->height = scale_length(box->height, box->y, scale);
39 box->width *= scale; 55 box->x = round(box->x * scale);
40 box->height *= scale; 56 box->y = round(box->y * scale);
41} 57}
42 58
43static void scissor_output(struct wlr_output *wlr_output, 59static void scissor_output(struct wlr_output *wlr_output,
@@ -392,14 +408,23 @@ static void render_titlebar(struct sway_output *output,
392 render_rect(output->wlr_output, output_damage, &box, color); 408 render_rect(output->wlr_output, output_damage, &box, color);
393 409
394 // Single pixel right edge 410 // Single pixel right edge
395 box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; 411 box.x = x + width - TITLEBAR_BORDER_THICKNESS;
412 box.y = y + TITLEBAR_BORDER_THICKNESS;
413 box.width = TITLEBAR_BORDER_THICKNESS;
414 box.height =
415 container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
416 scale_box(&box, output_scale);
396 render_rect(output->wlr_output, output_damage, &box, color); 417 render_rect(output->wlr_output, output_damage, &box, color);
397 } 418 }
398 419
399 size_t inner_width = width - TITLEBAR_H_PADDING * 2; 420 size_t inner_width = width - TITLEBAR_H_PADDING * 2;
421 int bg_y = y + TITLEBAR_BORDER_THICKNESS;
422 int ob_bg_height = scale_length(
423 (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
424 config->font_height, bg_y, output_scale);
400 425
401 // Marks 426 // Marks
402 size_t marks_ob_width = 0; // output-buffer-local 427 int marks_ob_width = 0; // output-buffer-local
403 if (config->show_marks && marks_texture) { 428 if (config->show_marks && marks_texture) {
404 struct wlr_box texture_box; 429 struct wlr_box texture_box;
405 wlr_texture_get_size(marks_texture, 430 wlr_texture_get_size(marks_texture,
@@ -408,15 +433,14 @@ static void render_titlebar(struct sway_output *output,
408 433
409 // The marks texture might be shorter than the config->font_height, in 434 // The marks texture might be shorter than the config->font_height, in
410 // which case we need to pad it as evenly as possible above and below. 435 // which case we need to pad it as evenly as possible above and below.
411 int ob_padding_total = config->font_height * output_scale - 436 int ob_padding_total = ob_bg_height - texture_box.height;
412 texture_box.height; 437 int ob_padding_above = floor(ob_padding_total / 2.0);
413 int ob_padding_above = floor(ob_padding_total / 2); 438 int ob_padding_below = ceil(ob_padding_total / 2.0);
414 int ob_padding_below = ceil(ob_padding_total / 2);
415 439
416 // Render texture 440 // Render texture
417 texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) 441 texture_box.x = round((x - output_x + width - TITLEBAR_H_PADDING)
418 * output_scale - texture_box.width; 442 * output_scale) - texture_box.width;
419 texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + 443 texture_box.y = round((bg_y - output_y) * output_scale) +
420 ob_padding_above; 444 ob_padding_above;
421 445
422 float matrix[9]; 446 float matrix[9];
@@ -431,29 +455,18 @@ static void render_titlebar(struct sway_output *output,
431 &texture_box, matrix, con->alpha); 455 &texture_box, matrix, con->alpha);
432 456
433 // Padding above 457 // Padding above
434 if (ob_padding_above > 0) { 458 memcpy(&color, colors->background, sizeof(float) * 4);
435 memcpy(&color, colors->background, sizeof(float) * 4); 459 premultiply_alpha(color, con->alpha);
436 premultiply_alpha(color, con->alpha); 460 box.x = texture_box.x + round(output_x * output_scale);
437 box.x = (x + width - TITLEBAR_H_PADDING) * output_scale - 461 box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
438 texture_box.width; 462 box.width = texture_box.width;
439 box.y = (y + TITLEBAR_V_PADDING) * output_scale; 463 box.height = ob_padding_above;
440 box.width = texture_box.width; 464 render_rect(output->wlr_output, output_damage, &box, color);
441 box.height = ob_padding_above;
442 render_rect(output->wlr_output, output_damage, &box, color);
443 }
444 465
445 // Padding below 466 // Padding below
446 if (ob_padding_below > 0) { 467 box.y += ob_padding_above + texture_box.height;
447 memcpy(&color, colors->background, sizeof(float) * 4); 468 box.height = ob_padding_below;
448 premultiply_alpha(color, con->alpha); 469 render_rect(output->wlr_output, output_damage, &box, color);
449 box.x = (x + width - TITLEBAR_H_PADDING) * output_scale -
450 texture_box.width;
451 box.y = (y + TITLEBAR_V_PADDING) * output_scale +
452 ob_padding_above + texture_box.height;
453 box.width = texture_box.width;
454 box.height = ob_padding_below;
455 render_rect(output->wlr_output, output_damage, &box, color);
456 }
457 } 470 }
458 471
459 // Title text 472 // Title text
@@ -466,89 +479,73 @@ static void render_titlebar(struct sway_output *output,
466 479
467 // The title texture might be shorter than the config->font_height, 480 // The title texture might be shorter than the config->font_height,
468 // in which case we need to pad it above and below. 481 // in which case we need to pad it above and below.
469 int ob_padding_above = (config->font_baseline - con->title_baseline) 482 int ob_padding_above = round((config->font_baseline -
470 * output_scale; 483 con->title_baseline + TITLEBAR_V_PADDING -
471 int ob_padding_below = (config->font_height - con->title_height) 484 TITLEBAR_BORDER_THICKNESS) * output_scale);
472 * output_scale - ob_padding_above; 485 int ob_padding_below = ob_bg_height - ob_padding_above -
486 texture_box.height;
473 487
474 // Render texture 488 // Render texture
475 texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; 489 texture_box.x =
476 texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + 490 round((x - output_x + TITLEBAR_H_PADDING) * output_scale);
477 ob_padding_above; 491 texture_box.y =
492 round((bg_y - output_y) * output_scale) + ob_padding_above;
478 493
479 float matrix[9]; 494 float matrix[9];
480 wlr_matrix_project_box(matrix, &texture_box, 495 wlr_matrix_project_box(matrix, &texture_box,
481 WL_OUTPUT_TRANSFORM_NORMAL, 496 WL_OUTPUT_TRANSFORM_NORMAL,
482 0.0, output->wlr_output->transform_matrix); 497 0.0, output->wlr_output->transform_matrix);
483 498
484 if (inner_width * output_scale - marks_ob_width < texture_box.width) { 499 int inner_x = x - output_x + TITLEBAR_H_PADDING;
485 texture_box.width = inner_width * output_scale - marks_ob_width; 500 int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
501 if (ob_inner_width - marks_ob_width < texture_box.width) {
502 texture_box.width = ob_inner_width - marks_ob_width;
486 } 503 }
487 render_texture(output->wlr_output, output_damage, title_texture, 504 render_texture(output->wlr_output, output_damage, title_texture,
488 &texture_box, matrix, con->alpha); 505 &texture_box, matrix, con->alpha);
489 506
490 // Padding above 507 // Padding above
491 if (ob_padding_above > 0) { 508 memcpy(&color, colors->background, sizeof(float) * 4);
492 memcpy(&color, colors->background, sizeof(float) * 4); 509 premultiply_alpha(color, con->alpha);
493 premultiply_alpha(color, con->alpha); 510 box.x = texture_box.x + round(output_x * output_scale);
494 box.x = (x + TITLEBAR_H_PADDING) * output_scale; 511 box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
495 box.y = (y + TITLEBAR_V_PADDING) * output_scale; 512 box.width = texture_box.width;
496 box.width = texture_box.width; 513 box.height = ob_padding_above;
497 box.height = ob_padding_above; 514 render_rect(output->wlr_output, output_damage, &box, color);
498 render_rect(output->wlr_output, output_damage, &box, color);
499 }
500 515
501 // Padding below 516 // Padding below
502 if (ob_padding_below > 0) { 517 box.y += ob_padding_above + texture_box.height;
503 memcpy(&color, colors->background, sizeof(float) * 4); 518 box.height = ob_padding_below;
504 premultiply_alpha(color, con->alpha); 519 render_rect(output->wlr_output, output_damage, &box, color);
505 box.x = (x + TITLEBAR_H_PADDING) * output_scale;
506 box.y = (y + TITLEBAR_V_PADDING) * output_scale +
507 ob_padding_above + texture_box.height;
508 box.width = texture_box.width;
509 box.height = ob_padding_below;
510 render_rect(output->wlr_output, output_damage, &box, color);
511 }
512 } 520 }
513 521
514 // Padding above title
515 memcpy(&color, colors->background, sizeof(float) * 4);
516 premultiply_alpha(color, con->alpha);
517 box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
518 box.y = y + TITLEBAR_BORDER_THICKNESS;
519 box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
520 box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
521 scale_box(&box, output_scale);
522 render_rect(output->wlr_output, output_damage, &box, color);
523
524 // Padding below title
525 box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
526 render_rect(output->wlr_output, output_damage, &box, color);
527
528 // Filler between title and marks 522 // Filler between title and marks
529 box.width = inner_width * output_scale - title_ob_width - marks_ob_width; 523 box.width =
524 round(inner_width * output_scale) - title_ob_width - marks_ob_width;
530 if (box.width > 0) { 525 if (box.width > 0) {
531 box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width; 526 box.x = round((x + TITLEBAR_H_PADDING) * output_scale) + title_ob_width;
532 box.y = (y + TITLEBAR_V_PADDING) * output_scale; 527 box.y = round(bg_y * output_scale);
533 box.height = config->font_height * output_scale; 528 box.height = ob_bg_height;
534 render_rect(output->wlr_output, output_damage, &box, color); 529 render_rect(output->wlr_output, output_damage, &box, color);
535 } 530 }
536 531
537 // Padding left of title 532 // Padding left of title
538 left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; 533 left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
539 box.x = x + left_offset; 534 box.x = x + left_offset;
540 box.y = y + TITLEBAR_V_PADDING; 535 box.y = y + TITLEBAR_BORDER_THICKNESS;
541 box.width = TITLEBAR_H_PADDING - left_offset; 536 box.width = TITLEBAR_H_PADDING - left_offset;
542 box.height = config->font_height; 537 box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
538 config->font_height;
543 scale_box(&box, output_scale); 539 scale_box(&box, output_scale);
544 render_rect(output->wlr_output, output_damage, &box, color); 540 render_rect(output->wlr_output, output_damage, &box, color);
545 541
546 // Padding right of marks 542 // Padding right of marks
547 right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; 543 right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
548 box.x = x + width - TITLEBAR_H_PADDING; 544 box.x = x + width - TITLEBAR_H_PADDING;
549 box.y = y + TITLEBAR_V_PADDING; 545 box.y = y + TITLEBAR_BORDER_THICKNESS;
550 box.width = TITLEBAR_H_PADDING - right_offset; 546 box.width = TITLEBAR_H_PADDING - right_offset;
551 box.height = config->font_height; 547 box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
548 config->font_height;
552 scale_box(&box, output_scale); 549 scale_box(&box, output_scale);
553 render_rect(output->wlr_output, output_damage, &box, color); 550 render_rect(output->wlr_output, output_damage, &box, color);
554 551