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 copy_tex = &mut *copy_tex;
|
||||||
let mut triangles = state.triangles.borrow_mut();
|
let mut triangles = state.triangles.borrow_mut();
|
||||||
let triangles = &mut *triangles;
|
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;
|
let mut i = 0;
|
||||||
while i < ops.len() {
|
while i < ops.len() {
|
||||||
macro_rules! has_ops {
|
macro_rules! has_ops {
|
||||||
|
|
@ -218,47 +263,19 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<FdSync> {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
GfxApiOpt::RoundedFillRect(rf) => {
|
GfxApiOpt::RoundedFillRect(rf) => {
|
||||||
|
flush_fills!();
|
||||||
render_rounded_fill(&fb.ctx, rf);
|
render_rounded_fill(&fb.ctx, rf);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
GfxApiOpt::RoundedCopyTexture(ct) => {
|
GfxApiOpt::RoundedCopyTexture(ct) => {
|
||||||
|
flush_textures!();
|
||||||
render_rounded_texture(&fb.ctx, ct);
|
render_rounded_texture(&fb.ctx, ct);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fill_rect.is_not_empty() {
|
flush_fills!();
|
||||||
fill_rect.sort_unstable_by_key(|f| f.color);
|
flush_textures!();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if fb.ctx.ctx.dpy.explicit_sync {
|
if fb.ctx.ctx.dpy.explicit_sync {
|
||||||
let file = match fb.ctx.ctx.export_sync_file() {
|
let file = match fb.ctx.ctx.export_sync_file() {
|
||||||
|
|
|
||||||
|
|
@ -923,20 +923,19 @@ impl VulkanRenderer {
|
||||||
#[derive(Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Eq, PartialEq, PartialOrd, Ord)]
|
||||||
enum Key {
|
enum Key {
|
||||||
Fill { color: [u32; 4] },
|
Fill { color: [u32; 4] },
|
||||||
Tex(usize),
|
|
||||||
RoundedFill { z_order: u32, color: [u32; 4] },
|
RoundedFill { z_order: u32, color: [u32; 4] },
|
||||||
RoundedTex(usize),
|
Tex(usize),
|
||||||
}
|
}
|
||||||
match o {
|
match o {
|
||||||
VulkanOp::Fill(f) => Key::Fill {
|
VulkanOp::Fill(f) => Key::Fill {
|
||||||
color: f.color.map(|c| c.to_bits()),
|
color: f.color.map(|c| c.to_bits()),
|
||||||
},
|
},
|
||||||
VulkanOp::Tex(t) => Key::Tex(t.index),
|
|
||||||
VulkanOp::RoundedFill(f) => Key::RoundedFill {
|
VulkanOp::RoundedFill(f) => Key::RoundedFill {
|
||||||
z_order: f.z_order,
|
z_order: f.z_order,
|
||||||
color: f.color.map(|c| c.to_bits()),
|
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];
|
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] {
|
for opt in &memory.ops[pass] {
|
||||||
match opt {
|
match opt {
|
||||||
VulkanOp::Fill(r) => {
|
VulkanOp::Fill(r) => {
|
||||||
|
|
@ -1768,7 +1791,7 @@ impl VulkanRenderer {
|
||||||
0,
|
0,
|
||||||
uapi::as_bytes(&push),
|
uapi::as_bytes(&push),
|
||||||
);
|
);
|
||||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
draw_rounded!(r.target);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let push = LegacyRoundedFillPushConstants {
|
let push = LegacyRoundedFillPushConstants {
|
||||||
|
|
@ -1791,7 +1814,7 @@ impl VulkanRenderer {
|
||||||
0,
|
0,
|
||||||
uapi::as_bytes(&push),
|
uapi::as_bytes(&push),
|
||||||
);
|
);
|
||||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
draw_rounded!(r.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1837,7 +1860,7 @@ impl VulkanRenderer {
|
||||||
0,
|
0,
|
||||||
uapi::as_bytes(&push),
|
uapi::as_bytes(&push),
|
||||||
);
|
);
|
||||||
dev.cmd_draw(buf, 4, 1, 0, 0);
|
draw_rounded!(c.target);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let write_descriptor_set = WriteDescriptorSet::default()
|
let write_descriptor_set = WriteDescriptorSet::default()
|
||||||
|
|
@ -1872,7 +1895,7 @@ impl VulkanRenderer {
|
||||||
0,
|
0,
|
||||||
uapi::as_bytes(&push),
|
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 {
|
fn constrain(&self, pos: &mut Point, tex_pos: Option<&mut Point>) -> bool {
|
||||||
zone!("constrain");
|
zone!("constrain");
|
||||||
let mut npos = *pos;
|
let mut npos = *pos;
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,9 @@ impl Renderer<'_> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
render_stacked!(self.state.root.stacked);
|
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() {
|
if fullscreen.is_none() {
|
||||||
render_layer!(output.layers[2]);
|
render_layer!(output.layers[2]);
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +292,7 @@ impl Renderer<'_> {
|
||||||
let bar_height = tab_bar.height;
|
let bar_height = tab_bar.height;
|
||||||
let render_scale = tab_bar.render_scale;
|
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:
|
// We use:
|
||||||
// FillRect – tiny strip for Vulkan paint regions (hidden)
|
// FillRect – tiny strip for Vulkan paint regions (hidden)
|
||||||
// RoundedFillRect z0 – solid rounded bg
|
// RoundedFillRect z0 – solid rounded bg
|
||||||
|
|
@ -466,6 +469,7 @@ impl Renderer<'_> {
|
||||||
.node
|
.node
|
||||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||||
self.stretch = None;
|
self.stretch = None;
|
||||||
|
self.corner_radius = None;
|
||||||
} else {
|
} else {
|
||||||
let gap = self.state.theme.sizes.gap.get();
|
let gap = self.state.theme.sizes.gap.get();
|
||||||
let (srgb_srgb, bw, border_color, focused_border_color) = if gap != 0 {
|
let (srgb_srgb, bw, border_color, focused_border_color) = if gap != 0 {
|
||||||
|
|
@ -545,6 +549,7 @@ impl Renderer<'_> {
|
||||||
.node
|
.node
|
||||||
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
.node_render(self, x + content.x1(), y + content.y1(), Some(&body));
|
||||||
self.stretch = None;
|
self.stretch = None;
|
||||||
|
self.corner_radius = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -630,6 +635,9 @@ impl Renderer<'_> {
|
||||||
is_subsurface: bool,
|
is_subsurface: bool,
|
||||||
) {
|
) {
|
||||||
let stretch = self.stretch.take();
|
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 children = surface.children.borrow();
|
||||||
let buffer = match surface.buffer.get() {
|
let buffer = match surface.buffer.get() {
|
||||||
Some(b) => b,
|
Some(b) => b,
|
||||||
|
|
@ -680,9 +688,12 @@ impl Renderer<'_> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
render!(&children.below);
|
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);
|
self.render_buffer(surface, &buffer, x, y, tpoints, size, bounds);
|
||||||
render!(&children.above);
|
render!(&children.above);
|
||||||
} else {
|
} else {
|
||||||
|
self.corner_radius = corner_radius;
|
||||||
self.render_buffer(surface, &buffer, x, y, tpoints, size, bounds);
|
self.render_buffer(surface, &buffer, x, y, tpoints, size, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -827,6 +838,7 @@ impl Renderer<'_> {
|
||||||
self.corner_radius = Some(inner_cr);
|
self.corner_radius = Some(inner_cr);
|
||||||
}
|
}
|
||||||
child.node_render(self, body.x1(), body.y1(), Some(&scissor_body));
|
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) {
|
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue