micro optimization fixes
This commit is contained in:
1 parent
0d7203f84b
commit
da60ecb719
36 files changed
+1781
-521
No files matched your search
@@ -130,7 +130,7 @@ pub(super) fn window_border_element(
|
||||
let context = renderer.context_id().erased();
|
||||
let buffers = &mut resources.windows.entry(id).or_default().borders;
|
||||
if !buffers.contexts.contains_key(&context) {
|
||||
let element = PixelShaderElement::new(
|
||||
let element = SharedPixelShaderElement::new(
|
||||
programs.border.clone(),
|
||||
geometry,
|
||||
None,
|
||||
@@ -164,16 +164,16 @@ pub(super) fn window_border_element(
|
||||
|
||||
pub(super) fn border_uniforms(parameters: &BorderParameters) -> Vec<Uniform<'static>> {
|
||||
vec![
|
||||
Uniform::new("clip_rect", parameters.clip_rect).into_owned(),
|
||||
Uniform::new("radius", parameters.radius).into_owned(),
|
||||
Uniform::new("border_width", parameters.width).into_owned(),
|
||||
Uniform::new("border_color", parameters.color).into_owned(),
|
||||
Uniform::new("border_color_to", parameters.color_to).into_owned(),
|
||||
Uniform::new("gradient_line", parameters.gradient_line).into_owned(),
|
||||
Uniform::new("focus_color", parameters.focus_color).into_owned(),
|
||||
Uniform::new("focus_color_to", parameters.focus_color_to).into_owned(),
|
||||
Uniform::new("focus_gradient_line", parameters.focus_gradient_line).into_owned(),
|
||||
Uniform::new("focus_mix", parameters.focus_mix).into_owned(),
|
||||
Uniform::new("clip_rect", parameters.clip_rect),
|
||||
Uniform::new("radius", parameters.radius),
|
||||
Uniform::new("border_width", parameters.width),
|
||||
Uniform::new("border_color", parameters.color),
|
||||
Uniform::new("border_color_to", parameters.color_to),
|
||||
Uniform::new("gradient_line", parameters.gradient_line),
|
||||
Uniform::new("focus_color", parameters.focus_color),
|
||||
Uniform::new("focus_color_to", parameters.focus_color_to),
|
||||
Uniform::new("focus_gradient_line", parameters.focus_gradient_line),
|
||||
Uniform::new("focus_mix", parameters.focus_mix),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -213,12 +213,12 @@ pub(super) fn window_tint_element(
|
||||
};
|
||||
let uniforms = |p: &BorderParameters| {
|
||||
vec![
|
||||
Uniform::new("visible_rect", p.clip_rect).into_owned(),
|
||||
Uniform::new("material_radius", p.radius).into_owned(),
|
||||
Uniform::new("tint", p.color).into_owned(),
|
||||
Uniform::new("paint_mode", 0.0_f32).into_owned(),
|
||||
Uniform::new("shadow_rect", p.clip_rect).into_owned(),
|
||||
Uniform::new("shadow_values", [0.0_f32; 2]).into_owned(),
|
||||
Uniform::new("visible_rect", p.clip_rect),
|
||||
Uniform::new("material_radius", p.radius),
|
||||
Uniform::new("tint", p.color),
|
||||
Uniform::new("paint_mode", 0.0_f32),
|
||||
Uniform::new("shadow_rect", p.clip_rect),
|
||||
Uniform::new("shadow_values", [0.0_f32; 2]),
|
||||
]
|
||||
};
|
||||
let context = renderer.context_id().erased();
|
||||
@@ -228,7 +228,7 @@ pub(super) fn window_tint_element(
|
||||
&mut resources.windows.entry(id).or_default().dim
|
||||
};
|
||||
let cached = buffers.contexts.entry(context).or_insert_with(|| CachedBorder {
|
||||
element: PixelShaderElement::new(
|
||||
element: SharedPixelShaderElement::new(
|
||||
program.0,
|
||||
geometry,
|
||||
None,
|
||||
@@ -293,7 +293,7 @@ pub(super) fn window_shadow_element(
|
||||
let context = renderer.context_id().erased();
|
||||
let buffers = &mut resources.windows.entry(id).or_default().shadow;
|
||||
if !buffers.contexts.contains_key(&context) {
|
||||
let element = PixelShaderElement::new(
|
||||
let element = SharedPixelShaderElement::new(
|
||||
programs.shadow.clone(),
|
||||
bounds,
|
||||
None,
|
||||
@@ -331,11 +331,11 @@ pub(super) fn window_shadow_element(
|
||||
|
||||
pub(super) fn shadow_uniforms(parameters: &ShadowParameters) -> Vec<Uniform<'static>> {
|
||||
vec![
|
||||
Uniform::new("shadow_rect", parameters.shadow_rect).into_owned(),
|
||||
Uniform::new("radius", parameters.radius).into_owned(),
|
||||
Uniform::new("blur", parameters.blur).into_owned(),
|
||||
Uniform::new("opacity", parameters.opacity).into_owned(),
|
||||
Uniform::new("shadow_color", parameters.color).into_owned(),
|
||||
Uniform::new("shadow_rect", parameters.shadow_rect),
|
||||
Uniform::new("radius", parameters.radius),
|
||||
Uniform::new("blur", parameters.blur),
|
||||
Uniform::new("opacity", parameters.opacity),
|
||||
Uniform::new("shadow_color", parameters.color),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ pub(super) fn material_element(
|
||||
capture.dirty.clone(),
|
||||
))
|
||||
} else {
|
||||
MaterialElement::Fill(PixelShaderElement::new(
|
||||
MaterialElement::Fill(SharedPixelShaderElement::new(
|
||||
program.0.clone(),
|
||||
geometry,
|
||||
parameters.opaque.then(|| vec![Rectangle::from_size(geometry.size)]),
|
||||
@@ -264,7 +264,7 @@ pub(super) fn material_element(
|
||||
.or_insert_with(|| CachedMaterial {
|
||||
element: make_element(),
|
||||
parameters: parameters.clone(),
|
||||
shadow: PixelShaderElement::new(
|
||||
shadow: SharedPixelShaderElement::new(
|
||||
program.0.clone(),
|
||||
parameters.shadow_bounds,
|
||||
None,
|
||||
@@ -356,14 +356,14 @@ pub(super) fn blur_uniform_names() -> [UniformName<'static>; 8] {
|
||||
|
||||
pub(super) fn blur_uniforms(p: &MaterialParameters) -> Vec<Uniform<'static>> {
|
||||
vec![
|
||||
Uniform::new("visible_rect", p.visible_framebuffer).into_owned(),
|
||||
Uniform::new("material_radius", p.radius).into_owned(),
|
||||
Uniform::new("texture_size", [p.sample_framebuffer[2], p.sample_framebuffer[3]]).into_owned(),
|
||||
Uniform::new("capture_origin", [p.sample_framebuffer[0], p.sample_framebuffer[1]]).into_owned(),
|
||||
Uniform::new("blur_radius", p.blur).into_owned(),
|
||||
Uniform::new("presentation_alpha", p.presentation_alpha).into_owned(),
|
||||
Uniform::new("background_opacity", p.background_opacity).into_owned(),
|
||||
Uniform::new("tint", p.tint).into_owned(),
|
||||
Uniform::new("visible_rect", p.visible_framebuffer),
|
||||
Uniform::new("material_radius", p.radius),
|
||||
Uniform::new("texture_size", [p.sample_framebuffer[2], p.sample_framebuffer[3]]),
|
||||
Uniform::new("capture_origin", [p.sample_framebuffer[0], p.sample_framebuffer[1]]),
|
||||
Uniform::new("blur_radius", p.blur),
|
||||
Uniform::new("presentation_alpha", p.presentation_alpha),
|
||||
Uniform::new("background_opacity", p.background_opacity),
|
||||
Uniform::new("tint", p.tint),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -426,12 +426,12 @@ pub(super) fn material_uniforms(parameters: &MaterialParameters) -> Vec<Uniform<
|
||||
|
||||
pub(super) fn decoration_uniforms(parameters: &MaterialParameters, paint_mode: f32) -> Vec<Uniform<'static>> {
|
||||
vec![
|
||||
Uniform::new("paint_mode", paint_mode).into_owned(),
|
||||
Uniform::new("shadow_rect", parameters.shadow_rect).into_owned(),
|
||||
Uniform::new("shadow_values", parameters.shadow_values).into_owned(),
|
||||
Uniform::new("visible_rect", parameters.visible_framebuffer).into_owned(),
|
||||
Uniform::new("material_radius", parameters.radius).into_owned(),
|
||||
Uniform::new("tint", parameters.tint).into_owned(),
|
||||
Uniform::new("paint_mode", paint_mode),
|
||||
Uniform::new("shadow_rect", parameters.shadow_rect),
|
||||
Uniform::new("shadow_values", parameters.shadow_values),
|
||||
Uniform::new("visible_rect", parameters.visible_framebuffer),
|
||||
Uniform::new("material_radius", parameters.radius),
|
||||
Uniform::new("tint", parameters.tint),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ mod materials;
|
||||
mod overview;
|
||||
mod resources;
|
||||
mod scene;
|
||||
mod shader;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -18,6 +19,7 @@ use scene::cursor_elements;
|
||||
pub(crate) use scene::{
|
||||
animated_window_elements, frame_effect_metrics, layer_surfaces, output_elements, sampled_output_elements,
|
||||
};
|
||||
pub(crate) use shader::SharedPixelShaderElement;
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
|
||||
use smithay::backend::renderer::element::solid::SolidColorRenderElement;
|
||||
@@ -31,7 +33,6 @@ use smithay::backend::renderer::element::utils::{
|
||||
use smithay::backend::renderer::element::{
|
||||
Element, Id, Kind as RenderElementKind, RenderElement, UnderlyingStorage, render_elements,
|
||||
};
|
||||
use smithay::backend::renderer::gles::element::PixelShaderElement;
|
||||
use smithay::backend::renderer::gles::{
|
||||
GlesError, GlesFrame, GlesPixelProgram, GlesRenderer, GlesTexProgram, GlesTexture, Uniform, UniformName,
|
||||
UniformType,
|
||||
@@ -66,7 +67,7 @@ render_elements! {
|
||||
Memory=MemoryRenderElement,
|
||||
Solid=SolidColorRenderElement,
|
||||
LockSurface=WaylandSurfaceRenderElement<GlesRenderer>,
|
||||
Border=PixelShaderElement,
|
||||
Border=SharedPixelShaderElement,
|
||||
Blur=BlurRenderElement,
|
||||
Effect=PhysicalShaderElement,
|
||||
Native=NativeTextureElement,
|
||||
@@ -132,7 +133,7 @@ struct BlurRenderElement {
|
||||
commit: CommitCounter,
|
||||
geometry: Rectangle<i32, Logical>,
|
||||
capture_rect: [i32; 4],
|
||||
uniforms: Vec<Uniform<'static>>,
|
||||
uniforms: Arc<[Uniform<'static>]>,
|
||||
}
|
||||
|
||||
impl BlurRenderElement {
|
||||
@@ -150,7 +151,7 @@ impl BlurRenderElement {
|
||||
commit: CommitCounter::default(),
|
||||
geometry: parameters.sample_geometry,
|
||||
capture_rect: framebuffer_capture_rect(parameters.sample_framebuffer),
|
||||
uniforms: blur_uniforms(parameters),
|
||||
uniforms: blur_uniforms(parameters).into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +159,7 @@ impl BlurRenderElement {
|
||||
self.capture_dirty.store(true, Ordering::Relaxed);
|
||||
self.geometry = parameters.sample_geometry;
|
||||
self.capture_rect = framebuffer_capture_rect(parameters.sample_framebuffer);
|
||||
self.uniforms = blur_uniforms(parameters);
|
||||
self.uniforms = blur_uniforms(parameters).into();
|
||||
self.commit.increment();
|
||||
}
|
||||
}
|
||||
@@ -327,7 +328,7 @@ struct MaterialParameters {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum MaterialElement {
|
||||
Fill(PixelShaderElement),
|
||||
Fill(SharedPixelShaderElement),
|
||||
Blur(BlurRenderElement),
|
||||
}
|
||||
|
||||
@@ -335,7 +336,7 @@ enum MaterialElement {
|
||||
struct CachedMaterial {
|
||||
element: MaterialElement,
|
||||
parameters: MaterialParameters,
|
||||
shadow: PixelShaderElement,
|
||||
shadow: SharedPixelShaderElement,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -361,7 +362,7 @@ struct BorderParameters {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CachedBorder {
|
||||
element: PixelShaderElement,
|
||||
element: SharedPixelShaderElement,
|
||||
parameters: BorderParameters,
|
||||
}
|
||||
|
||||
@@ -382,7 +383,7 @@ struct ShadowParameters {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CachedShadow {
|
||||
element: PixelShaderElement,
|
||||
element: SharedPixelShaderElement,
|
||||
parameters: ShadowParameters,
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@ pub(super) fn overview_chrome_element(
|
||||
border_uniforms(p)
|
||||
} else {
|
||||
vec![
|
||||
Uniform::new("visible_rect", p.clip_rect).into_owned(),
|
||||
Uniform::new("material_radius", p.radius).into_owned(),
|
||||
Uniform::new("tint", p.color).into_owned(),
|
||||
Uniform::new("paint_mode", 0.0_f32).into_owned(),
|
||||
Uniform::new("shadow_rect", p.clip_rect).into_owned(),
|
||||
Uniform::new("shadow_values", [0.0_f32; 2]).into_owned(),
|
||||
Uniform::new("visible_rect", p.clip_rect),
|
||||
Uniform::new("material_radius", p.radius),
|
||||
Uniform::new("tint", p.color),
|
||||
Uniform::new("paint_mode", 0.0_f32),
|
||||
Uniform::new("shadow_rect", p.clip_rect),
|
||||
Uniform::new("shadow_values", [0.0_f32; 2]),
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -61,7 +61,7 @@ pub(super) fn overview_chrome_element(
|
||||
.or_default()
|
||||
.entry(context)
|
||||
.or_insert_with(|| CachedBorder {
|
||||
element: PixelShaderElement::new(
|
||||
element: SharedPixelShaderElement::new(
|
||||
program,
|
||||
geometry,
|
||||
None,
|
||||
@@ -119,33 +119,31 @@ pub(super) fn overview_strip_elements(
|
||||
.opacity;
|
||||
let mut elements = Vec::new();
|
||||
let programs = rounded_clip_program(&mut state.render, renderer);
|
||||
// Resolve IDs once per strip, rather than scanning all managed windows
|
||||
// separately for every miniature. Own the handles so rendering can mutate state.
|
||||
let windows_by_id: std::collections::HashMap<_, _> = state
|
||||
.windows
|
||||
.ids()
|
||||
state.retain_overview_labels();
|
||||
|
||||
let card_ids = cards
|
||||
.iter()
|
||||
.map(|(window, id)| (*id, window.clone()))
|
||||
.collect();
|
||||
.map(|card| card.workspace.0)
|
||||
.collect::<std::collections::HashSet<_>>();
|
||||
if let Some(output_id) = state.output_id(output)
|
||||
&& let Some(cache) = state.render.outputs.get_mut(&output_id)
|
||||
{
|
||||
cache.chrome.retain(|(id, part), _| match part {
|
||||
OverviewChromePart::Caption => windows_by_id.keys().any(|window| window.0 == *id),
|
||||
OverviewChromePart::Card | OverviewChromePart::Outline => cards.iter().any(|card| card.workspace.0 == *id),
|
||||
OverviewChromePart::Caption => state.windows.window(ferese_layout::WindowId(*id)).is_some(),
|
||||
OverviewChromePart::Card | OverviewChromePart::Outline => card_ids.contains(id),
|
||||
OverviewChromePart::Strip => true,
|
||||
});
|
||||
}
|
||||
// Cached title textures are independent of window content and stay readable
|
||||
// when thumbnails are small. Their pills use the shell's material and radius.
|
||||
for (id, window) in &windows_by_id {
|
||||
for id in frame.windows.keys() {
|
||||
if !state.window_belongs_to_output(*id, output) {
|
||||
continue;
|
||||
}
|
||||
let Some(rect) = frame.windows.get(id).map(|sample| sample.rect) else {
|
||||
continue;
|
||||
};
|
||||
let Some((buffer, size)) = state.overview_window_label(window, scale, rect.width) else {
|
||||
let Some((buffer, size)) = state.overview_window_label(*id, scale, rect.width) else {
|
||||
continue;
|
||||
};
|
||||
let width = (f64::from(size.w) / scale + 16.0).min(rect.width);
|
||||
@@ -222,7 +220,7 @@ pub(super) fn overview_strip_elements(
|
||||
}
|
||||
if let Some(programs) = &programs {
|
||||
for (id, rect) in &card.windows {
|
||||
if let Some(window) = windows_by_id.get(id) {
|
||||
if let Some(window) = state.windows.window(*id) {
|
||||
elements.extend(rounded_window_elements(
|
||||
renderer,
|
||||
window,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use smithay::desktop::Window;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub(crate) fn animated_window_elements(
|
||||
@@ -109,39 +111,42 @@ pub(crate) fn sampled_output_elements(
|
||||
frame,
|
||||
));
|
||||
}
|
||||
let mut candidates = if state.overview.is_active() {
|
||||
state.windows.ids().keys().cloned().collect::<Vec<_>>()
|
||||
let prepare_window = |window: &Window| {
|
||||
// Configure immediately, but present the frame/shadow only after
|
||||
// the first buffer commit has settled the actual client geometry.
|
||||
if !state.window_content_ready(window) {
|
||||
return None;
|
||||
}
|
||||
let id = *state.windows.ids().get(window)?;
|
||||
// Scrolling columns may sit outside their monitor's rectangle.
|
||||
// They must not reappear on a neighboring output just because
|
||||
// their global animated coordinates overlap it.
|
||||
if !state.window_belongs_to_output(id, output) {
|
||||
return None;
|
||||
}
|
||||
let sample = frame.windows.get(&id)?;
|
||||
let visual = scaled_visual_rect(sample.rect, sample.close_scale);
|
||||
let close_alpha = sample.close_alpha;
|
||||
let decoration_progress = sample.geometry.decorations.clamp(0.0, 1.0);
|
||||
|
||||
Some((window.clone(), id, sample, visual, decoration_progress, close_alpha))
|
||||
};
|
||||
let windows = if state.overview.is_active() {
|
||||
state
|
||||
.windows
|
||||
.overview_windows()
|
||||
.filter_map(prepare_window)
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
state.space.elements().rev().cloned().collect::<Vec<_>>()
|
||||
state
|
||||
.space
|
||||
.elements()
|
||||
.rev()
|
||||
.filter_map(prepare_window)
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
if state.overview.is_active() {
|
||||
candidates.sort_by_key(|window| std::cmp::Reverse(state.windows.ids().get(window).map_or(0, |id| id.0)));
|
||||
}
|
||||
let windows = candidates
|
||||
.iter()
|
||||
.filter_map(|window| {
|
||||
// Configure immediately, but present the frame/shadow only after
|
||||
// the first buffer commit has settled the actual client geometry.
|
||||
if !state.window_content_ready(window) {
|
||||
return None;
|
||||
}
|
||||
let id = *state.windows.ids().get(window)?;
|
||||
// Scrolling columns may sit outside their monitor's rectangle.
|
||||
// They must not reappear on a neighboring output just because
|
||||
// their global animated coordinates overlap it.
|
||||
if !state.window_belongs_to_output(id, output) {
|
||||
return None;
|
||||
}
|
||||
let sample = frame.windows.get(&id)?;
|
||||
let visual = scaled_visual_rect(sample.rect, sample.close_scale);
|
||||
let close_alpha = sample.close_alpha;
|
||||
let decoration_progress = sample.geometry.decorations.clamp(0.0, 1.0);
|
||||
|
||||
Some((window.clone(), id, visual, decoration_progress, close_alpha))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (window, id, visual, decoration_progress, close_alpha) in windows {
|
||||
for (window, id, sample, visual, decoration_progress, close_alpha) in windows {
|
||||
let constrain = rounded_visual_rect(visual, output_geometry.loc);
|
||||
let material_surface = window
|
||||
.toplevel()
|
||||
@@ -158,10 +163,10 @@ pub(crate) fn sampled_output_elements(
|
||||
let corners = RoundedRect::new(visual, output_geometry.loc, scale, window_radius);
|
||||
let pixels = corners.rect;
|
||||
// Only overview/close intentionally scale the complete application.
|
||||
let scale_content = frame.overview.is_presenting() || frame.windows[&id].close_scale != 1.0;
|
||||
let scale_content = frame.overview.is_presenting() || sample.close_scale != 1.0;
|
||||
let behavior = resize_content_behavior(scale_content);
|
||||
|
||||
let dim = frame.windows[&id].dim;
|
||||
let dim = sample.dim;
|
||||
if let Some(overlay) = window_tint_element(
|
||||
&mut state.render,
|
||||
renderer,
|
||||
@@ -182,7 +187,7 @@ pub(crate) fn sampled_output_elements(
|
||||
let shadow_blur = state.theme_settings.shadow_blur;
|
||||
let shadow_opacity = state.theme_settings.shadow_opacity;
|
||||
let shadow_color = state.theme_settings.shadow_color.0;
|
||||
let focus = frame.windows[&id].focus;
|
||||
let focus = sample.focus;
|
||||
let border_width = state.theme_settings.border_width
|
||||
+ (state.theme_settings.focus_ring_width - state.theme_settings.border_width) * focus;
|
||||
let border_color = state.theme_settings.border_color.0;
|
||||
@@ -245,10 +250,7 @@ pub(crate) fn sampled_output_elements(
|
||||
))),
|
||||
alpha: crate::presentation::handoff_alpha(snapshot.elapsed) * close_alpha,
|
||||
program: Some(programs.texture.clone()),
|
||||
uniforms: vec![
|
||||
Uniform::new("clip_rect", clip).into_owned(),
|
||||
Uniform::new("radius", corners.radius).into_owned(),
|
||||
],
|
||||
uniforms: vec![Uniform::new("clip_rect", clip), Uniform::new("radius", corners.radius)],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
@@ -260,7 +262,7 @@ pub(crate) fn sampled_output_elements(
|
||||
corners,
|
||||
scale,
|
||||
close_alpha,
|
||||
frame.windows[&id].geometry.presentation_changed,
|
||||
sample.geometry.presentation_changed,
|
||||
output,
|
||||
programs.clone(),
|
||||
behavior,
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
//! Static uniform names stay borrowed; cached frame elements share their state.
|
||||
//! Copy on write preserves the ID and commit seen by an already sampled frame.
|
||||
use std::sync::Arc;
|
||||
|
||||
use smithay::backend::renderer::element::{Element, Id, Kind, RenderElement};
|
||||
use smithay::backend::renderer::gles::{GlesError, GlesFrame, GlesPixelProgram, GlesRenderer, Uniform};
|
||||
use smithay::backend::renderer::utils::{CommitCounter, OpaqueRegions};
|
||||
use smithay::utils::{Buffer, Logical, Physical, Rectangle, Scale, Transform};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SharedPixelShaderElement {
|
||||
shader: GlesPixelProgram,
|
||||
state: Arc<ShaderState>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ShaderState {
|
||||
id: Id,
|
||||
commit: CommitCounter,
|
||||
area: Rectangle<i32, Logical>,
|
||||
opaque: Vec<Rectangle<i32, Logical>>,
|
||||
alpha: f32,
|
||||
uniforms: Vec<Uniform<'static>>,
|
||||
kind: Kind,
|
||||
}
|
||||
|
||||
impl SharedPixelShaderElement {
|
||||
pub(crate) fn new(
|
||||
shader: GlesPixelProgram,
|
||||
area: Rectangle<i32, Logical>,
|
||||
opaque: Option<Vec<Rectangle<i32, Logical>>>,
|
||||
alpha: f32,
|
||||
uniforms: Vec<Uniform<'static>>,
|
||||
kind: Kind,
|
||||
) -> Self {
|
||||
Self {
|
||||
shader,
|
||||
state: Arc::new(ShaderState {
|
||||
id: Id::new(),
|
||||
commit: CommitCounter::default(),
|
||||
area,
|
||||
opaque: opaque.unwrap_or_default(),
|
||||
alpha,
|
||||
uniforms,
|
||||
kind,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resize(&mut self, area: Rectangle<i32, Logical>, opaque: Option<Vec<Rectangle<i32, Logical>>>) {
|
||||
let opaque = opaque.unwrap_or_default();
|
||||
|
||||
if self.state.area != area || self.state.opaque != opaque {
|
||||
let state = Arc::make_mut(&mut self.state);
|
||||
state.area = area;
|
||||
state.opaque = opaque;
|
||||
state.commit.increment();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_uniforms(&mut self, uniforms: Vec<Uniform<'static>>) {
|
||||
let state = Arc::make_mut(&mut self.state);
|
||||
state.uniforms = uniforms;
|
||||
state.commit.increment();
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for SharedPixelShaderElement {
|
||||
fn id(&self) -> &Id {
|
||||
&self.state.id
|
||||
}
|
||||
|
||||
fn current_commit(&self) -> CommitCounter {
|
||||
self.state.commit
|
||||
}
|
||||
|
||||
fn src(&self) -> Rectangle<f64, Buffer> {
|
||||
Rectangle::from_size(self.state.area.size.to_f64().to_buffer(1.0, Transform::Normal))
|
||||
}
|
||||
|
||||
fn geometry(&self, scale: Scale<f64>) -> Rectangle<i32, Physical> {
|
||||
self.state.area.to_physical_precise_round(scale)
|
||||
}
|
||||
|
||||
fn opaque_regions(&self, scale: Scale<f64>) -> OpaqueRegions<i32, Physical> {
|
||||
self.state
|
||||
.opaque
|
||||
.iter()
|
||||
.map(|region| region.to_physical_precise_round(scale))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn alpha(&self) -> f32 {
|
||||
self.state.alpha
|
||||
}
|
||||
|
||||
fn kind(&self) -> Kind {
|
||||
self.state.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderElement<GlesRenderer> for SharedPixelShaderElement {
|
||||
fn draw(
|
||||
&self,
|
||||
frame: &mut GlesFrame<'_, '_>,
|
||||
src: Rectangle<f64, Buffer>,
|
||||
dst: Rectangle<i32, Physical>,
|
||||
damage: &[Rectangle<i32, Physical>],
|
||||
_opaque: &[Rectangle<i32, Physical>],
|
||||
) -> Result<(), GlesError> {
|
||||
frame.render_pixel_shader_to(
|
||||
&self.shader,
|
||||
src,
|
||||
dst,
|
||||
self.state.area.size.to_buffer(1, Transform::Normal),
|
||||
Some(damage),
|
||||
self.state.alpha,
|
||||
&self.state.uniforms,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::egl::{EGLContext, EGLDevice, EGLDisplay};
|
||||
use smithay::backend::renderer::gles::element::PixelShaderElement;
|
||||
use smithay::backend::renderer::gles::{GlesTexture, UniformName, UniformType};
|
||||
use smithay::backend::renderer::{Bind, Color32F, ExportMem, Frame, Offscreen, Renderer};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn pixels(renderer: &mut GlesRenderer, element: &impl RenderElement<GlesRenderer>) -> Vec<u8> {
|
||||
let size = (32, 32).into();
|
||||
let mut texture: GlesTexture = renderer.create_buffer(Fourcc::Abgr8888, size).unwrap();
|
||||
let rect = Rectangle::from_size((32, 32).into());
|
||||
let mut target = renderer.bind(&mut texture).unwrap();
|
||||
|
||||
{
|
||||
let mut frame = renderer
|
||||
.render(&mut target, (32, 32).into(), Transform::Normal)
|
||||
.unwrap();
|
||||
frame.clear(Color32F::TRANSPARENT, &[rect]).unwrap();
|
||||
element.draw(&mut frame, element.src(), rect, &[rect], &[]).unwrap();
|
||||
let _ = frame.finish().unwrap();
|
||||
}
|
||||
|
||||
let mapping = renderer
|
||||
.copy_framebuffer(&target, Rectangle::from_size(size), Fourcc::Abgr8888)
|
||||
.unwrap();
|
||||
renderer.map_texture(&mapping).unwrap().to_vec()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "requires an EGL rendering device"]
|
||||
fn shared_shader_matches_smithay_and_keeps_old_frames_immutable() {
|
||||
let device = EGLDevice::enumerate().unwrap().last().expect("an EGL device");
|
||||
let display = unsafe { EGLDisplay::new(device).unwrap() };
|
||||
let mut renderer = unsafe { GlesRenderer::new(EGLContext::new(&display).unwrap()).unwrap() };
|
||||
let program = renderer
|
||||
.compile_custom_pixel_shader(
|
||||
super::super::corner_shader(super::super::ROUNDED_SOLID_SHADER),
|
||||
&[
|
||||
UniformName::new("clip_rect", UniformType::_4f),
|
||||
UniformName::new("radius", UniformType::_1f),
|
||||
UniformName::new("color", UniformType::_4f),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
let area = Rectangle::new((2, 3).into(), (32, 32).into());
|
||||
let uniforms = |color| {
|
||||
vec![
|
||||
Uniform::new("clip_rect", [0.0_f32, 0.0, 32.0, 32.0]),
|
||||
Uniform::new("radius", 8.0_f32),
|
||||
Uniform::new("color", color),
|
||||
]
|
||||
};
|
||||
let red = [0.5_f32, 0.0, 0.0, 0.5];
|
||||
let green = [0.0_f32, 0.5, 0.0, 0.5];
|
||||
let opaque = Some(vec![Rectangle::from_size((20, 20).into())]);
|
||||
let baseline = PixelShaderElement::new(
|
||||
program.clone(),
|
||||
area,
|
||||
opaque.clone(),
|
||||
0.5,
|
||||
uniforms(red),
|
||||
Kind::Unspecified,
|
||||
);
|
||||
let mut shared = SharedPixelShaderElement::new(program, area, opaque, 0.5, uniforms(red), Kind::Unspecified);
|
||||
let old = shared.clone();
|
||||
let old_commit = old.current_commit();
|
||||
|
||||
assert!(Arc::ptr_eq(&shared.state, &old.state));
|
||||
assert!(
|
||||
shared
|
||||
.state
|
||||
.uniforms
|
||||
.iter()
|
||||
.all(|uniform| matches!(uniform.name, Cow::Borrowed(_)))
|
||||
);
|
||||
|
||||
for scale in [1.0, 1.25, 2.0] {
|
||||
assert_eq!(shared.geometry(scale.into()), baseline.geometry(scale.into()));
|
||||
assert_eq!(
|
||||
&*shared.opaque_regions(scale.into()),
|
||||
&*baseline.opaque_regions(scale.into())
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(pixels(&mut renderer, &shared), pixels(&mut renderer, &baseline));
|
||||
shared.resize(area, Some(vec![Rectangle::from_size((20, 20).into())]));
|
||||
assert!(Arc::ptr_eq(&shared.state, &old.state));
|
||||
shared.update_uniforms(uniforms(green));
|
||||
assert!(!Arc::ptr_eq(&shared.state, &old.state));
|
||||
assert_eq!(shared.id(), old.id());
|
||||
assert_eq!(old.current_commit(), old_commit);
|
||||
assert_ne!(shared.current_commit(), old_commit);
|
||||
assert_eq!(pixels(&mut renderer, &old), pixels(&mut renderer, &baseline));
|
||||
assert_ne!(pixels(&mut renderer, &shared), pixels(&mut renderer, &baseline));
|
||||
|
||||
let retained = shared.clone();
|
||||
shared.resize(Rectangle::from_size((16, 16).into()), None);
|
||||
assert_eq!(retained.geometry(1.0.into()), area.to_physical_precise_round(1.0));
|
||||
assert_eq!(shared.geometry(1.0.into()).size, (16, 16).into());
|
||||
assert!(shared.opaque_regions(1.0.into()).is_empty());
|
||||
assert_eq!(shared.alpha(), baseline.alpha());
|
||||
assert_eq!(shared.kind(), baseline.kind());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user