renderer: fix rendering flickering window rendering
This commit is contained in:
parent
bd3128c516
commit
4e9b6def83
3 changed files with 108 additions and 41 deletions
|
|
@ -189,6 +189,51 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<FdSync> {
|
|||
let copy_tex = &mut *copy_tex;
|
||||
let mut triangles = state.triangles.borrow_mut();
|
||||
let triangles = &mut *triangles;
|
||||
// Flush accumulated fill rects (sorted by color for batching).
|
||||
macro_rules! flush_fills {
|
||||
() => {
|
||||
if fill_rect.is_not_empty() {
|
||||
fill_rect.sort_unstable_by_key(|f| f.color);
|
||||
let mut j = 0;
|
||||
while j < fill_rect.len() {
|
||||
triangles.clear();
|
||||
let mut color = None;
|
||||
while j < fill_rect.len() {
|
||||
let fr = &fill_rect[j];
|
||||
match color {
|
||||
None => color = Some(fr.color),
|
||||
Some(c) if c == fr.color => {}
|
||||
_ => break,
|
||||
}
|
||||
let [top_right, top_left, bottom_right, bottom_left] =
|
||||
fr.rect.to_points();
|
||||
triangles.extend_from_slice(&[
|
||||
top_right,
|
||||
top_left,
|
||||
bottom_left,
|
||||
top_right,
|
||||
bottom_left,
|
||||
bottom_right,
|
||||
]);
|
||||
j += 1;
|
||||
}
|
||||
if let Some(color) = color {
|
||||
fill_boxes3(&fb.ctx, triangles, &color);
|
||||
}
|
||||
}
|
||||
fill_rect.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
// Flush accumulated texture copies (preserving insertion order).
|
||||
macro_rules! flush_textures {
|
||||
() => {
|
||||
for tex in copy_tex.iter() {
|
||||
render_texture(&fb.ctx, tex);
|
||||
}
|
||||
copy_tex.clear();
|
||||
};
|
||||
}
|
||||
let mut i = 0;
|
||||
while i < ops.len() {
|
||||
macro_rules! has_ops {
|
||||
|
|
@ -218,47 +263,19 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<FdSync> {
|
|||
i += 1;
|
||||
}
|
||||
GfxApiOpt::RoundedFillRect(rf) => {
|
||||
flush_fills!();
|
||||
render_rounded_fill(&fb.ctx, rf);
|
||||
i += 1;
|
||||
}
|
||||
GfxApiOpt::RoundedCopyTexture(ct) => {
|
||||
flush_textures!();
|
||||
render_rounded_texture(&fb.ctx, ct);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if fill_rect.is_not_empty() {
|
||||
fill_rect.sort_unstable_by_key(|f| f.color);
|
||||
let mut i = 0;
|
||||
while i < fill_rect.len() {
|
||||
triangles.clear();
|
||||
let mut color = None;
|
||||
while i < fill_rect.len() {
|
||||
let fr = &fill_rect[i];
|
||||
match color {
|
||||
None => color = Some(fr.color),
|
||||
Some(c) if c == fr.color => {}
|
||||
_ => break,
|
||||
}
|
||||
let [top_right, top_left, bottom_right, bottom_left] = fr.rect.to_points();
|
||||
triangles.extend_from_slice(&[
|
||||
top_right,
|
||||
top_left,
|
||||
bottom_left,
|
||||
top_right,
|
||||
bottom_left,
|
||||
bottom_right,
|
||||
]);
|
||||
i += 1;
|
||||
}
|
||||
if let Some(color) = color {
|
||||
fill_boxes3(&fb.ctx, triangles, &color);
|
||||
}
|
||||
}
|
||||
}
|
||||
for tex in &*copy_tex {
|
||||
render_texture(&fb.ctx, tex);
|
||||
}
|
||||
flush_fills!();
|
||||
flush_textures!();
|
||||
}
|
||||
if fb.ctx.ctx.dpy.explicit_sync {
|
||||
let file = match fb.ctx.ctx.export_sync_file() {
|
||||
|
|
|
|||
|
|
@ -923,20 +923,19 @@ impl VulkanRenderer {
|
|||
#[derive(Eq, PartialEq, PartialOrd, Ord)]
|
||||
enum Key {
|
||||
Fill { color: [u32; 4] },
|
||||
Tex(usize),
|
||||
RoundedFill { z_order: u32, color: [u32; 4] },
|
||||
RoundedTex(usize),
|
||||
Tex(usize),
|
||||
}
|
||||
match o {
|
||||
VulkanOp::Fill(f) => Key::Fill {
|
||||
color: f.color.map(|c| c.to_bits()),
|
||||
},
|
||||
VulkanOp::Tex(t) => Key::Tex(t.index),
|
||||
VulkanOp::RoundedFill(f) => Key::RoundedFill {
|
||||
z_order: f.z_order,
|
||||
color: f.color.map(|c| c.to_bits()),
|
||||
},
|
||||
VulkanOp::RoundedTex(t) => Key::RoundedTex(t.index),
|
||||
VulkanOp::Tex(t) => Key::Tex(t.index),
|
||||
VulkanOp::RoundedTex(t) => Key::Tex(t.index),
|
||||
}
|
||||
});
|
||||
let mops = &mut memory.ops[pass];
|
||||
|
|
@ -1638,6 +1637,30 @@ impl VulkanRenderer {
|
|||
}
|
||||
}
|
||||
};
|
||||
let full_scissor = Rect2D {
|
||||
offset: Default::default(),
|
||||
extent: Extent2D {
|
||||
width: target.width,
|
||||
height: target.height,
|
||||
},
|
||||
};
|
||||
let paint_regions = &memory.paint_regions[pass];
|
||||
// Draws a rounded op once per intersecting paint region using scissor
|
||||
// rects. Unlike CopyTexture/FillRect which clip their geometry to each
|
||||
// paint region, rounded ops must keep their full geometry so the shader
|
||||
// computes correct corner rounding. Scissor rects achieve this.
|
||||
macro_rules! draw_rounded {
|
||||
($target_point:expr) => {
|
||||
for region in paint_regions {
|
||||
if region.intersects(&$target_point) {
|
||||
let scissor = region.to_scissor(target);
|
||||
dev.cmd_set_scissor(buf, 0, slice::from_ref(&scissor));
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
dev.cmd_set_scissor(buf, 0, slice::from_ref(&full_scissor));
|
||||
};
|
||||
}
|
||||
for opt in &memory.ops[pass] {
|
||||
match opt {
|
||||
VulkanOp::Fill(r) => {
|
||||
|
|
@ -1768,7 +1791,7 @@ impl VulkanRenderer {
|
|||
0,
|
||||
uapi::as_bytes(&push),
|
||||
);
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
draw_rounded!(r.target);
|
||||
}
|
||||
} else {
|
||||
let push = LegacyRoundedFillPushConstants {
|
||||
|
|
@ -1791,7 +1814,7 @@ impl VulkanRenderer {
|
|||
0,
|
||||
uapi::as_bytes(&push),
|
||||
);
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
draw_rounded!(r.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1837,7 +1860,7 @@ impl VulkanRenderer {
|
|||
0,
|
||||
uapi::as_bytes(&push),
|
||||
);
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
draw_rounded!(c.target);
|
||||
}
|
||||
} else {
|
||||
let write_descriptor_set = WriteDescriptorSet::default()
|
||||
|
|
@ -1872,7 +1895,7 @@ impl VulkanRenderer {
|
|||
0,
|
||||
uapi::as_bytes(&push),
|
||||
);
|
||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
||||
draw_rounded!(c.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2716,6 +2739,21 @@ impl PaintRegion {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_scissor(&self, target: &VulkanImage) -> Rect2D {
|
||||
let from_norm = |c: f32, max: u32| ((c + 1.0) * 0.5 * max as f32).round() as i32;
|
||||
let x1 = from_norm(self.x1, target.width).max(0);
|
||||
let y1 = from_norm(self.y1, target.height).max(0);
|
||||
let x2 = from_norm(self.x2, target.width).min(target.width as i32);
|
||||
let y2 = from_norm(self.y2, target.height).min(target.height as i32);
|
||||
Rect2D {
|
||||
offset: Offset2D { x: x1, y: y1 },
|
||||
extent: Extent2D {
|
||||
width: (x2 - x1).max(0) as u32,
|
||||
height: (y2 - y1).max(0) as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain(&self, pos: &mut Point, tex_pos: Option<&mut Point>) -> bool {
|
||||
zone!("constrain");
|
||||
let mut npos = *pos;
|
||||
|
|
|
|||
|
|
@ -215,6 +215,9 @@ impl Renderer<'_> {
|
|||
};
|
||||
}
|
||||
render_stacked!(self.state.root.stacked);
|
||||
// Flush RoundedFillRect ops from container/float borders so they don't
|
||||
// sort after (and render on top of) layer-shell CopyTexture ops.
|
||||
self.base.sync();
|
||||
if fullscreen.is_none() {
|
||||
render_layer!(output.layers[2]);
|
||||
}
|
||||
|
|
@ -289,7 +292,7 @@ impl Renderer<'_> {
|
|||
let bar_height = tab_bar.height;
|
||||
let render_scale = tab_bar.render_scale;
|
||||
|
||||
// Vulkan sorts ops: Fill < Tex < RoundedFill (by z_order, color) < RoundedTex.
|
||||
// Vulkan sorts ops: Fill < RoundedFill (by z_order, color) < Tex/RoundedTex (by index).
|
||||
// We use:
|
||||
// FillRect – tiny strip for Vulkan paint regions (hidden)
|
||||
// RoundedFillRect z0 – solid rounded bg
|
||||
|
|
@ -466,6 +469,7 @@ impl Renderer<'_> {
|
|||
.node
|
||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||
self.stretch = None;
|
||||
self.corner_radius = None;
|
||||
} else {
|
||||
let gap = self.state.theme.sizes.gap.get();
|
||||
let (srgb_srgb, bw, border_color, focused_border_color) = if gap != 0 {
|
||||
|
|
@ -545,6 +549,7 @@ impl Renderer<'_> {
|
|||
.node
|
||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||
self.stretch = None;
|
||||
self.corner_radius = None;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -630,6 +635,9 @@ impl Renderer<'_> {
|
|||
is_subsurface: bool,
|
||||
) {
|
||||
let stretch = self.stretch.take();
|
||||
// Take corner_radius early so it is never leaked on early return
|
||||
// and so that below-subsurfaces cannot steal it from the main surface.
|
||||
let corner_radius = self.corner_radius.take();
|
||||
let children = surface.children.borrow();
|
||||
let buffer = match surface.buffer.get() {
|
||||
Some(b) => b,
|
||||
|
|
@ -680,9 +688,12 @@ impl Renderer<'_> {
|
|||
};
|
||||
}
|
||||
render!(&children.below);
|
||||
// Restore corner_radius only for the main surface's render_buffer call.
|
||||
self.corner_radius = corner_radius;
|
||||
self.render_buffer(surface, &buffer, x, y, tpoints, size, bounds);
|
||||
render!(&children.above);
|
||||
} else {
|
||||
self.corner_radius = corner_radius;
|
||||
self.render_buffer(surface, &buffer, x, y, tpoints, size, bounds);
|
||||
}
|
||||
}
|
||||
|
|
@ -827,6 +838,7 @@ impl Renderer<'_> {
|
|||
self.corner_radius = Some(inner_cr);
|
||||
}
|
||||
child.node_render(self, body.x1(), body.y1(), Some(&scissor_body));
|
||||
self.corner_radius = None;
|
||||
}
|
||||
|
||||
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue