kms: Refactor out postprocessing helpers
This commit is contained in:
parent
a748ea885e
commit
18335c6758
4 changed files with 236 additions and 118 deletions
|
|
@ -3,7 +3,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::{
|
backend::render::{
|
||||||
element::{CosmicElement, DamageElement},
|
element::{CosmicElement, DamageElement},
|
||||||
init_shaders, output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR,
|
init_shaders, output_elements, CursorMode, GlMultiRenderer, PostprocessOutputConfig,
|
||||||
|
PostprocessShader, PostprocessState, CLEAR_COLOR,
|
||||||
},
|
},
|
||||||
config::AdaptiveSync,
|
config::AdaptiveSync,
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
|
|
@ -24,7 +25,6 @@ use smithay::{
|
||||||
allocator::{
|
allocator::{
|
||||||
format::FormatSet,
|
format::FormatSet,
|
||||||
gbm::{GbmAllocator, GbmDevice},
|
gbm::{GbmAllocator, GbmDevice},
|
||||||
Fourcc,
|
|
||||||
},
|
},
|
||||||
drm::{
|
drm::{
|
||||||
compositor::{BlitFrameResultError, FrameError, FrameFlags, PrimaryPlaneElement},
|
compositor::{BlitFrameResultError, FrameError, FrameFlags, PrimaryPlaneElement},
|
||||||
|
|
@ -34,9 +34,9 @@ use smithay::{
|
||||||
egl::EGLContext,
|
egl::EGLContext,
|
||||||
renderer::{
|
renderer::{
|
||||||
buffer_dimensions,
|
buffer_dimensions,
|
||||||
damage::{Error as RenderError, OutputDamageTracker},
|
damage::Error as RenderError,
|
||||||
element::{
|
element::{
|
||||||
texture::{TextureRenderBuffer, TextureRenderElement},
|
texture::TextureRenderElement,
|
||||||
utils::{constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior},
|
utils::{constrain_render_elements, ConstrainAlign, ConstrainScaleBehavior},
|
||||||
Element, Kind, RenderElementStates,
|
Element, Kind, RenderElementStates,
|
||||||
},
|
},
|
||||||
|
|
@ -63,7 +63,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Size, Transform},
|
utils::{Buffer as BufferCoords, Clock, Monotonic, Physical, Rectangle, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
dmabuf::{get_dmabuf, DmabufFeedbackBuilder},
|
||||||
presentation::Refresh,
|
presentation::Refresh,
|
||||||
|
|
@ -129,7 +129,7 @@ pub struct SurfaceThreadState {
|
||||||
|
|
||||||
output: Output,
|
output: Output,
|
||||||
mirroring: Option<Output>,
|
mirroring: Option<Output>,
|
||||||
mirroring_textures: HashMap<DrmNode, MirroringState>,
|
postprocess_textures: HashMap<DrmNode, PostprocessState>,
|
||||||
|
|
||||||
shell: Arc<RwLock<Shell>>,
|
shell: Arc<RwLock<Shell>>,
|
||||||
|
|
||||||
|
|
@ -140,76 +140,6 @@ pub struct SurfaceThreadState {
|
||||||
egui: EguiState,
|
egui: EguiState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
struct MirroringOutputConfig {
|
|
||||||
size: Size<i32, Physical>,
|
|
||||||
fractional_scale: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MirroringOutputConfig {
|
|
||||||
fn for_output_untransformed(output: &Output) -> Self {
|
|
||||||
Self {
|
|
||||||
// Apply inverse of output transform to mode size to get correct size
|
|
||||||
// for an untransformed render.
|
|
||||||
size: output.current_transform().invert().transform_size(
|
|
||||||
output
|
|
||||||
.current_mode()
|
|
||||||
.map(|mode| mode.size)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
),
|
|
||||||
fractional_scale: output.current_scale().fractional_scale(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn for_output(output: &Output) -> Self {
|
|
||||||
Self {
|
|
||||||
size: output
|
|
||||||
.current_mode()
|
|
||||||
.map(|mode| mode.size)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
fractional_scale: output.current_scale().fractional_scale(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct MirroringState {
|
|
||||||
texture: TextureRenderBuffer<GlesTexture>,
|
|
||||||
damage_tracker: OutputDamageTracker,
|
|
||||||
output_config: MirroringOutputConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MirroringState {
|
|
||||||
fn new_with_renderer(
|
|
||||||
renderer: &mut GlMultiRenderer,
|
|
||||||
format: Fourcc,
|
|
||||||
output_config: MirroringOutputConfig,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let size = output_config.size;
|
|
||||||
let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal);
|
|
||||||
let opaque_regions = vec![Rectangle::from_size(buffer_size)];
|
|
||||||
|
|
||||||
let texture = Offscreen::<GlesTexture>::create_buffer(renderer, format, buffer_size)?;
|
|
||||||
let texture_buffer = TextureRenderBuffer::from_texture(
|
|
||||||
renderer,
|
|
||||||
texture,
|
|
||||||
1,
|
|
||||||
Transform::Normal,
|
|
||||||
Some(opaque_regions),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Don't use `from_output` to avoid applying output transform
|
|
||||||
let damage_tracker =
|
|
||||||
OutputDamageTracker::new(size, output_config.fractional_scale, Transform::Normal);
|
|
||||||
|
|
||||||
Ok(MirroringState {
|
|
||||||
texture: texture_buffer,
|
|
||||||
damage_tracker,
|
|
||||||
output_config,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type GbmDrmOutput = DrmOutput<
|
pub type GbmDrmOutput = DrmOutput<
|
||||||
GbmAllocator<DrmDeviceFd>,
|
GbmAllocator<DrmDeviceFd>,
|
||||||
GbmDevice<DrmDeviceFd>,
|
GbmDevice<DrmDeviceFd>,
|
||||||
|
|
@ -560,7 +490,7 @@ fn surface_thread(
|
||||||
|
|
||||||
output,
|
output,
|
||||||
mirroring: None,
|
mirroring: None,
|
||||||
mirroring_textures: HashMap::new(),
|
postprocess_textures: HashMap::new(),
|
||||||
|
|
||||||
shell,
|
shell,
|
||||||
loop_handle: event_loop.handle(),
|
loop_handle: event_loop.handle(),
|
||||||
|
|
@ -1056,40 +986,45 @@ impl SurfaceThreadState {
|
||||||
}).unwrap_or_default();
|
}).unwrap_or_default();
|
||||||
|
|
||||||
// actual rendering
|
// actual rendering
|
||||||
let res = if let Some(mirrored_output) = self.mirroring.as_ref().filter(|mirrored_output| {
|
let source_output = self
|
||||||
MirroringOutputConfig::for_output_untransformed(mirrored_output)
|
.mirroring
|
||||||
!= MirroringOutputConfig::for_output(&self.output)
|
.as_ref()
|
||||||
}) {
|
.filter(|output| {
|
||||||
let mirrored_output_config =
|
PostprocessOutputConfig::for_output_untransformed(output)
|
||||||
MirroringOutputConfig::for_output_untransformed(mirrored_output);
|
!= PostprocessOutputConfig::for_output(&self.output)
|
||||||
let mirroring_state = match self.mirroring_textures.entry(self.target_node) {
|
});
|
||||||
|
|
||||||
|
let res = if let Some(source_output) = source_output {
|
||||||
|
let offscreen_output_config =
|
||||||
|
PostprocessOutputConfig::for_output_untransformed(source_output);
|
||||||
|
let postprocess_state = match self.postprocess_textures.entry(self.target_node) {
|
||||||
hash_map::Entry::Occupied(occupied) => {
|
hash_map::Entry::Occupied(occupied) => {
|
||||||
let mirroring_state = occupied.into_mut();
|
let postprocess_state = occupied.into_mut();
|
||||||
// If output config is different, re-create offscreen state
|
// If output config is different, re-create offscreen state
|
||||||
if mirroring_state.output_config != mirrored_output_config {
|
if postprocess_state.output_config != offscreen_output_config {
|
||||||
*mirroring_state = MirroringState::new_with_renderer(
|
*postprocess_state = PostprocessState::new_with_renderer(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
compositor.format(),
|
compositor.format(),
|
||||||
mirrored_output_config,
|
offscreen_output_config,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
mirroring_state
|
postprocess_state
|
||||||
}
|
}
|
||||||
hash_map::Entry::Vacant(vacant) => {
|
hash_map::Entry::Vacant(vacant) => {
|
||||||
vacant.insert(MirroringState::new_with_renderer(
|
vacant.insert(PostprocessState::new_with_renderer(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
compositor.format(),
|
compositor.format(),
|
||||||
mirrored_output_config,
|
offscreen_output_config,
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mirroring_state
|
postprocess_state
|
||||||
.texture
|
.texture
|
||||||
.render()
|
.render()
|
||||||
.draw::<_, <GlMultiRenderer as RendererSuper>::Error>(|tex| {
|
.draw::<_, <GlMultiRenderer as RendererSuper>::Error>(|tex| {
|
||||||
let mut fb = renderer.bind(tex)?;
|
let mut fb = renderer.bind(tex)?;
|
||||||
let res = match mirroring_state.damage_tracker.render_output(
|
let res = match postprocess_state.damage_tracker.render_output(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&mut fb,
|
&mut fb,
|
||||||
1,
|
1,
|
||||||
|
|
@ -1103,7 +1038,7 @@ impl SurfaceThreadState {
|
||||||
renderer.wait(&res.sync)?;
|
renderer.wait(&res.sync)?;
|
||||||
std::mem::drop(fb);
|
std::mem::drop(fb);
|
||||||
|
|
||||||
let transform = mirrored_output.current_transform();
|
let transform = source_output.current_transform();
|
||||||
let area = tex.size().to_logical(1, transform);
|
let area = tex.size().to_logical(1, transform);
|
||||||
|
|
||||||
Ok(res
|
Ok(res
|
||||||
|
|
@ -1120,7 +1055,7 @@ impl SurfaceThreadState {
|
||||||
|
|
||||||
let texture_elem = TextureRenderElement::from_texture_render_buffer(
|
let texture_elem = TextureRenderElement::from_texture_render_buffer(
|
||||||
(0., 0.),
|
(0., 0.),
|
||||||
&mirroring_state.texture,
|
&postprocess_state.texture,
|
||||||
Some(1.0),
|
Some(1.0),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|
@ -1145,7 +1080,7 @@ impl SurfaceThreadState {
|
||||||
ConstrainAlign::CENTER,
|
ConstrainAlign::CENTER,
|
||||||
1.0,
|
1.0,
|
||||||
)
|
)
|
||||||
.map(CosmicElement::Mirror)
|
.map(CosmicElement::Postprocess)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
renderer = self.api.single_renderer(&self.target_node).unwrap();
|
||||||
|
|
@ -1448,7 +1383,7 @@ impl SurfaceThreadState {
|
||||||
|
|
||||||
fn update_mirroring(&mut self, mirroring_output: Option<Output>) {
|
fn update_mirroring(&mut self, mirroring_output: Option<Output>) {
|
||||||
self.mirroring = mirroring_output;
|
self.mirroring = mirroring_output;
|
||||||
self.mirroring_textures.clear();
|
self.postprocess_textures.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_frame_callbacks(&mut self) {
|
fn send_frame_callbacks(&mut self) {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement};
|
use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement};
|
||||||
|
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{
|
element::{
|
||||||
memory::MemoryRenderBufferRenderElement,
|
memory::MemoryRenderBufferRenderElement,
|
||||||
surface::WaylandSurfaceRenderElement,
|
surface::WaylandSurfaceRenderElement,
|
||||||
texture::TextureRenderElement,
|
|
||||||
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
|
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
|
||||||
Element, Id, Kind, RenderElement, UnderlyingStorage,
|
Element, Id, Kind, RenderElement, UnderlyingStorage,
|
||||||
},
|
},
|
||||||
gles::{GlesError, GlesTexture},
|
gles::{element::TextureShaderElement, GlesError},
|
||||||
glow::{GlowFrame, GlowRenderer},
|
glow::{GlowFrame, GlowRenderer},
|
||||||
utils::{CommitCounter, DamageSet, OpaqueRegions},
|
utils::{CommitCounter, DamageSet, OpaqueRegions},
|
||||||
ImportAll, ImportMem, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
|
|
@ -32,10 +33,8 @@ where
|
||||||
Dnd(WaylandSurfaceRenderElement<R>),
|
Dnd(WaylandSurfaceRenderElement<R>),
|
||||||
MoveGrab(RescaleRenderElement<CosmicMappedRenderElement<R>>),
|
MoveGrab(RescaleRenderElement<CosmicMappedRenderElement<R>>),
|
||||||
AdditionalDamage(DamageElement),
|
AdditionalDamage(DamageElement),
|
||||||
Mirror(
|
Postprocess(
|
||||||
CropRenderElement<
|
CropRenderElement<RelocateRenderElement<RescaleRenderElement<TextureShaderElement>>>,
|
||||||
RelocateRenderElement<RescaleRenderElement<TextureRenderElement<GlesTexture>>>,
|
|
||||||
>,
|
|
||||||
),
|
),
|
||||||
Zoom(MemoryRenderBufferRenderElement<R>),
|
Zoom(MemoryRenderBufferRenderElement<R>),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
|
@ -55,7 +54,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.id(),
|
CosmicElement::Dnd(elem) => elem.id(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.id(),
|
CosmicElement::MoveGrab(elem) => elem.id(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.id(),
|
CosmicElement::AdditionalDamage(elem) => elem.id(),
|
||||||
CosmicElement::Mirror(elem) => elem.id(),
|
CosmicElement::Postprocess(elem) => elem.id(),
|
||||||
CosmicElement::Zoom(elem) => elem.id(),
|
CosmicElement::Zoom(elem) => elem.id(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.id(),
|
CosmicElement::Egui(elem) => elem.id(),
|
||||||
|
|
@ -69,7 +68,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.current_commit(),
|
CosmicElement::Dnd(elem) => elem.current_commit(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.current_commit(),
|
CosmicElement::MoveGrab(elem) => elem.current_commit(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.current_commit(),
|
CosmicElement::AdditionalDamage(elem) => elem.current_commit(),
|
||||||
CosmicElement::Mirror(elem) => elem.current_commit(),
|
CosmicElement::Postprocess(elem) => elem.current_commit(),
|
||||||
CosmicElement::Zoom(elem) => elem.current_commit(),
|
CosmicElement::Zoom(elem) => elem.current_commit(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.current_commit(),
|
CosmicElement::Egui(elem) => elem.current_commit(),
|
||||||
|
|
@ -83,7 +82,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.src(),
|
CosmicElement::Dnd(elem) => elem.src(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.src(),
|
CosmicElement::MoveGrab(elem) => elem.src(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.src(),
|
CosmicElement::AdditionalDamage(elem) => elem.src(),
|
||||||
CosmicElement::Mirror(elem) => elem.src(),
|
CosmicElement::Postprocess(elem) => elem.src(),
|
||||||
CosmicElement::Zoom(elem) => elem.src(),
|
CosmicElement::Zoom(elem) => elem.src(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.src(),
|
CosmicElement::Egui(elem) => elem.src(),
|
||||||
|
|
@ -97,7 +96,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.geometry(scale),
|
CosmicElement::Dnd(elem) => elem.geometry(scale),
|
||||||
CosmicElement::MoveGrab(elem) => elem.geometry(scale),
|
CosmicElement::MoveGrab(elem) => elem.geometry(scale),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.geometry(scale),
|
CosmicElement::AdditionalDamage(elem) => elem.geometry(scale),
|
||||||
CosmicElement::Mirror(elem) => elem.geometry(scale),
|
CosmicElement::Postprocess(elem) => elem.geometry(scale),
|
||||||
CosmicElement::Zoom(elem) => elem.geometry(scale),
|
CosmicElement::Zoom(elem) => elem.geometry(scale),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.geometry(scale),
|
CosmicElement::Egui(elem) => elem.geometry(scale),
|
||||||
|
|
@ -111,7 +110,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.location(scale),
|
CosmicElement::Dnd(elem) => elem.location(scale),
|
||||||
CosmicElement::MoveGrab(elem) => elem.location(scale),
|
CosmicElement::MoveGrab(elem) => elem.location(scale),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.location(scale),
|
CosmicElement::AdditionalDamage(elem) => elem.location(scale),
|
||||||
CosmicElement::Mirror(elem) => elem.location(scale),
|
CosmicElement::Postprocess(elem) => elem.location(scale),
|
||||||
CosmicElement::Zoom(elem) => elem.location(scale),
|
CosmicElement::Zoom(elem) => elem.location(scale),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.location(scale),
|
CosmicElement::Egui(elem) => elem.location(scale),
|
||||||
|
|
@ -125,7 +124,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.transform(),
|
CosmicElement::Dnd(elem) => elem.transform(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.transform(),
|
CosmicElement::MoveGrab(elem) => elem.transform(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.transform(),
|
CosmicElement::AdditionalDamage(elem) => elem.transform(),
|
||||||
CosmicElement::Mirror(elem) => elem.transform(),
|
CosmicElement::Postprocess(elem) => elem.transform(),
|
||||||
CosmicElement::Zoom(elem) => elem.transform(),
|
CosmicElement::Zoom(elem) => elem.transform(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.transform(),
|
CosmicElement::Egui(elem) => elem.transform(),
|
||||||
|
|
@ -143,7 +142,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.damage_since(scale, commit),
|
CosmicElement::Dnd(elem) => elem.damage_since(scale, commit),
|
||||||
CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit),
|
CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.damage_since(scale, commit),
|
CosmicElement::AdditionalDamage(elem) => elem.damage_since(scale, commit),
|
||||||
CosmicElement::Mirror(elem) => elem.damage_since(scale, commit),
|
CosmicElement::Postprocess(elem) => elem.damage_since(scale, commit),
|
||||||
CosmicElement::Zoom(elem) => elem.damage_since(scale, commit),
|
CosmicElement::Zoom(elem) => elem.damage_since(scale, commit),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.damage_since(scale, commit),
|
CosmicElement::Egui(elem) => elem.damage_since(scale, commit),
|
||||||
|
|
@ -157,7 +156,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.opaque_regions(scale),
|
CosmicElement::Dnd(elem) => elem.opaque_regions(scale),
|
||||||
CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale),
|
CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.opaque_regions(scale),
|
CosmicElement::AdditionalDamage(elem) => elem.opaque_regions(scale),
|
||||||
CosmicElement::Mirror(elem) => elem.opaque_regions(scale),
|
CosmicElement::Postprocess(elem) => elem.opaque_regions(scale),
|
||||||
CosmicElement::Zoom(elem) => elem.opaque_regions(scale),
|
CosmicElement::Zoom(elem) => elem.opaque_regions(scale),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.opaque_regions(scale),
|
CosmicElement::Egui(elem) => elem.opaque_regions(scale),
|
||||||
|
|
@ -171,7 +170,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.alpha(),
|
CosmicElement::Dnd(elem) => elem.alpha(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.alpha(),
|
CosmicElement::MoveGrab(elem) => elem.alpha(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.alpha(),
|
CosmicElement::AdditionalDamage(elem) => elem.alpha(),
|
||||||
CosmicElement::Mirror(elem) => elem.alpha(),
|
CosmicElement::Postprocess(elem) => elem.alpha(),
|
||||||
CosmicElement::Zoom(elem) => elem.alpha(),
|
CosmicElement::Zoom(elem) => elem.alpha(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.alpha(),
|
CosmicElement::Egui(elem) => elem.alpha(),
|
||||||
|
|
@ -185,7 +184,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.kind(),
|
CosmicElement::Dnd(elem) => elem.kind(),
|
||||||
CosmicElement::MoveGrab(elem) => elem.kind(),
|
CosmicElement::MoveGrab(elem) => elem.kind(),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.kind(),
|
CosmicElement::AdditionalDamage(elem) => elem.kind(),
|
||||||
CosmicElement::Mirror(elem) => elem.kind(),
|
CosmicElement::Postprocess(elem) => elem.kind(),
|
||||||
CosmicElement::Zoom(elem) => elem.kind(),
|
CosmicElement::Zoom(elem) => elem.kind(),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
CosmicElement::Egui(elem) => elem.kind(),
|
CosmicElement::Egui(elem) => elem.kind(),
|
||||||
|
|
@ -216,7 +215,7 @@ where
|
||||||
CosmicElement::AdditionalDamage(elem) => {
|
CosmicElement::AdditionalDamage(elem) => {
|
||||||
RenderElement::<R>::draw(elem, frame, src, dst, damage, opaque_regions)
|
RenderElement::<R>::draw(elem, frame, src, dst, damage, opaque_regions)
|
||||||
}
|
}
|
||||||
CosmicElement::Mirror(elem) => {
|
CosmicElement::Postprocess(elem) => {
|
||||||
let glow_frame = R::glow_frame_mut(frame);
|
let glow_frame = R::glow_frame_mut(frame);
|
||||||
RenderElement::<GlowRenderer>::draw(
|
RenderElement::<GlowRenderer>::draw(
|
||||||
elem,
|
elem,
|
||||||
|
|
@ -252,7 +251,7 @@ where
|
||||||
CosmicElement::Dnd(elem) => elem.underlying_storage(renderer),
|
CosmicElement::Dnd(elem) => elem.underlying_storage(renderer),
|
||||||
CosmicElement::MoveGrab(elem) => elem.underlying_storage(renderer),
|
CosmicElement::MoveGrab(elem) => elem.underlying_storage(renderer),
|
||||||
CosmicElement::AdditionalDamage(elem) => elem.underlying_storage(renderer),
|
CosmicElement::AdditionalDamage(elem) => elem.underlying_storage(renderer),
|
||||||
CosmicElement::Mirror(elem) => {
|
CosmicElement::Postprocess(elem) => {
|
||||||
let glow_renderer = renderer.glow_renderer_mut();
|
let glow_renderer = renderer.glow_renderer_mut();
|
||||||
elem.underlying_storage(glow_renderer)
|
elem.underlying_storage(glow_renderer)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use std::{
|
||||||
use crate::debug::fps_ui;
|
use crate::debug::fps_ui;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement},
|
backend::{kms::render::gles::GbmGlowBackend, render::element::DamageElement},
|
||||||
|
config::ScreenFilter,
|
||||||
shell::{
|
shell::{
|
||||||
element::CosmicMappedKey,
|
element::CosmicMappedKey,
|
||||||
focus::{render_input_order, target::WindowGroup, Stage},
|
focus::{render_input_order, target::WindowGroup, Stage},
|
||||||
|
|
@ -36,7 +37,7 @@ use cosmic::Theme;
|
||||||
use element::FromGlesError;
|
use element::FromGlesError;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::dmabuf::Dmabuf,
|
allocator::{dmabuf::Dmabuf, Fourcc},
|
||||||
drm::{DrmDeviceFd, DrmNode},
|
drm::{DrmDeviceFd, DrmNode},
|
||||||
renderer::{
|
renderer::{
|
||||||
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
|
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
|
||||||
|
|
@ -52,13 +53,15 @@ use smithay::{
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
multigpu::{Error as MultiError, MultiFrame, MultiRenderer},
|
multigpu::{Error as MultiError, MultiFrame, MultiRenderer},
|
||||||
sync::SyncPoint,
|
sync::SyncPoint,
|
||||||
Bind, Blit, Color32F, ExportMem, ImportAll, ImportMem, Offscreen, Renderer,
|
Bind, Blit, Color32F, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, Texture,
|
||||||
TextureFilter,
|
TextureFilter,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input::Seat,
|
input::Seat,
|
||||||
output::{Output, OutputNoMode},
|
output::{Output, OutputNoMode},
|
||||||
utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform},
|
utils::{
|
||||||
|
IsAlive, Logical, Monotonic, Physical, Point, Rectangle, Scale, Size, Time, Transform,
|
||||||
|
},
|
||||||
wayland::{dmabuf::get_dmabuf, session_lock::LockSurface},
|
wayland::{dmabuf::get_dmabuf, session_lock::LockSurface},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -105,6 +108,7 @@ impl<'a> AsMut<GlowRenderer> for RendererRef<'a> {
|
||||||
pub static CLEAR_COLOR: Color32F = Color32F::new(0.153, 0.161, 0.165, 1.0);
|
pub static CLEAR_COLOR: Color32F = Color32F::new(0.153, 0.161, 0.165, 1.0);
|
||||||
pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag");
|
pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag");
|
||||||
pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag");
|
pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag");
|
||||||
|
pub static POSTPROCESS_SHADER: &str = include_str!("./shaders/offscreen.frag");
|
||||||
pub static GROUP_COLOR: [f32; 3] = [0.788, 0.788, 0.788];
|
pub static GROUP_COLOR: [f32; 3] = [0.788, 0.788, 0.788];
|
||||||
pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.58, 0.922, 0.922];
|
pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.58, 0.922, 0.922];
|
||||||
|
|
||||||
|
|
@ -346,11 +350,14 @@ impl BackdropShader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PostprocessShader(pub GlesTexProgram);
|
||||||
|
|
||||||
pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
|
pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
|
||||||
{
|
{
|
||||||
let egl_context = renderer.egl_context();
|
let egl_context = renderer.egl_context();
|
||||||
if egl_context.user_data().get::<IndicatorShader>().is_some()
|
if egl_context.user_data().get::<IndicatorShader>().is_some()
|
||||||
&& egl_context.user_data().get::<BackdropShader>().is_some()
|
&& egl_context.user_data().get::<BackdropShader>().is_some()
|
||||||
|
&& egl_context.user_data().get::<PostprocessShader>().is_some()
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -371,6 +378,13 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
|
||||||
UniformName::new("radius", UniformType::_1f),
|
UniformName::new("radius", UniformType::_1f),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
let postprocess_shader = renderer.compile_custom_texture_shader(
|
||||||
|
POSTPROCESS_SHADER,
|
||||||
|
&[
|
||||||
|
UniformName::new("invert", UniformType::_1f),
|
||||||
|
UniformName::new("color_mode", UniformType::_1f),
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
|
||||||
let egl_context = renderer.egl_context();
|
let egl_context = renderer.egl_context();
|
||||||
egl_context
|
egl_context
|
||||||
|
|
@ -379,6 +393,9 @@ pub fn init_shaders(renderer: &mut GlesRenderer) -> Result<(), GlesError> {
|
||||||
egl_context
|
egl_context
|
||||||
.user_data()
|
.user_data()
|
||||||
.insert_if_missing(|| BackdropShader(rectangle_shader));
|
.insert_if_missing(|| BackdropShader(rectangle_shader));
|
||||||
|
egl_context
|
||||||
|
.user_data()
|
||||||
|
.insert_if_missing(|| PostprocessShader(postprocess_shader));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -976,6 +993,83 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for mirroring and postprocessing
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PostprocessState {
|
||||||
|
pub texture: TextureRenderBuffer<GlesTexture>,
|
||||||
|
pub damage_tracker: OutputDamageTracker,
|
||||||
|
pub output_config: PostprocessOutputConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PostprocessState {
|
||||||
|
pub fn new_with_renderer<R: Renderer + Offscreen<GlesTexture>>(
|
||||||
|
renderer: &mut R,
|
||||||
|
format: Fourcc,
|
||||||
|
output_config: PostprocessOutputConfig,
|
||||||
|
) -> Result<Self, R::Error> {
|
||||||
|
let size = output_config.size;
|
||||||
|
let buffer_size = size.to_logical(1).to_buffer(1, Transform::Normal);
|
||||||
|
let opaque_regions = vec![Rectangle::from_size(buffer_size)];
|
||||||
|
|
||||||
|
let texture = Offscreen::<GlesTexture>::create_buffer(renderer, format, buffer_size)?;
|
||||||
|
let texture_buffer = TextureRenderBuffer::from_texture(
|
||||||
|
renderer,
|
||||||
|
texture,
|
||||||
|
1,
|
||||||
|
Transform::Normal,
|
||||||
|
Some(opaque_regions),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Don't use `from_output` to avoid applying output transform
|
||||||
|
let damage_tracker =
|
||||||
|
OutputDamageTracker::new(size, output_config.fractional_scale, Transform::Normal);
|
||||||
|
|
||||||
|
Ok(PostprocessState {
|
||||||
|
texture: texture_buffer,
|
||||||
|
damage_tracker,
|
||||||
|
output_config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct PostprocessOutputConfig {
|
||||||
|
pub size: Size<i32, Physical>,
|
||||||
|
pub fractional_scale: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PostprocessOutputConfig {
|
||||||
|
pub fn for_output_untransformed(output: &Output) -> Self {
|
||||||
|
Self {
|
||||||
|
// Apply inverse of output transform to mode size to get correct size
|
||||||
|
// for an untransformed render.
|
||||||
|
size: output.current_transform().invert().transform_size(
|
||||||
|
output
|
||||||
|
.current_mode()
|
||||||
|
.map(|mode| mode.size)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
|
fractional_scale: output.current_scale().fractional_scale(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_output(output: &Output) -> Self {
|
||||||
|
Self {
|
||||||
|
size: output
|
||||||
|
.current_mode()
|
||||||
|
.map(|mode| mode.size)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
fractional_scale: output.current_scale().fractional_scale(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ScreenFilterStorage {
|
||||||
|
pub filter: ScreenFilter,
|
||||||
|
pub state: Option<PostprocessState>,
|
||||||
|
}
|
||||||
|
|
||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn render_output<'d, R, OffTarget>(
|
pub fn render_output<'d, R, OffTarget>(
|
||||||
gpu: Option<&DrmNode>,
|
gpu: Option<&DrmNode>,
|
||||||
|
|
|
||||||
90
src/backend/render/shaders/offscreen.frag
Normal file
90
src/backend/render/shaders/offscreen.frag
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#version 100
|
||||||
|
|
||||||
|
//_DEFINES_
|
||||||
|
|
||||||
|
#if defined(EXTERNAL)
|
||||||
|
#extension GL_OES_EGL_image_external : require
|
||||||
|
#endif
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
#if defined(EXTERNAL)
|
||||||
|
uniform samplerExternalOES tex;
|
||||||
|
#else
|
||||||
|
uniform sampler2D tex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform float alpha;
|
||||||
|
varying vec2 v_coords;
|
||||||
|
|
||||||
|
#if defined(DEBUG_FLAGS)
|
||||||
|
uniform float tint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform float invert;
|
||||||
|
uniform float color_mode;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 color = texture2D(tex, v_coords);
|
||||||
|
|
||||||
|
#if defined(NO_ALPHA)
|
||||||
|
color = vec4(color.rgb, 1.0) * alpha;
|
||||||
|
#else
|
||||||
|
color = color * alpha;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// un-multiply
|
||||||
|
color.rgb /= color.a;
|
||||||
|
|
||||||
|
// First invert then filter
|
||||||
|
|
||||||
|
if (invert == 1.0) {
|
||||||
|
color.rgb = 1.0 - color.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color_mode == 1.0) { // greyscale
|
||||||
|
float value = (color.r + color.g + color.b) / 3.0;
|
||||||
|
color = vec4(value, value, value, color.a);
|
||||||
|
} else if (color_mode >= 2.0) {
|
||||||
|
float L = (17.8824 * color.r) + (43.5161 * color.g) + (4.11935 * color.b);
|
||||||
|
float M = (3.45565 * color.r) + (27.1554 * color.g) + (3.86714 * color.b);
|
||||||
|
float S = (0.0299566 * color.r) + (0.184309 * color.g) + (1.46709 * color.b);
|
||||||
|
|
||||||
|
float l, m, s;
|
||||||
|
if (color_mode == 2.0) { // Protanopia
|
||||||
|
l = 0.0 * L + 2.02344 * M + -2.52581 * S;
|
||||||
|
m = 0.0 * L + 1.0 * M + 0.0 * S;
|
||||||
|
s = 0.0 * L + 0.0 * M + 1.0 * S;
|
||||||
|
} else if (color_mode == 3.0) { // Deuteranopia
|
||||||
|
l = 1.0 * L + 0.0 * M + 0.0 * S;
|
||||||
|
m = 0.494207 * L + 0.0 * M + 1.24827 * S;
|
||||||
|
s = 0.0 * L + 0.0 * M + 1.0 * S;
|
||||||
|
} else if (color_mode == 4.0) { // Tritanopia
|
||||||
|
l = 1.0 * L + 0.0 * M + 0.0 * S;
|
||||||
|
m = 0.0 * L + 1.0 * M + 0.0 * S;
|
||||||
|
s = -0.395913 * L + 0.801109 * M + 0.0 * S;
|
||||||
|
} else {
|
||||||
|
// unknown
|
||||||
|
l = L;
|
||||||
|
m = M;
|
||||||
|
s = S;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 error;
|
||||||
|
error.r = (0.0809444479 * l) + (-0.130504409 * m) + (0.116721066 * s);
|
||||||
|
error.g = (-0.0102485335 * l) + (0.0540193266 * m) + (-0.113614708 * s);
|
||||||
|
error.b = (-0.000365296938 * l) + (-0.00412161469 * m) + (0.693511405 * s);
|
||||||
|
|
||||||
|
vec3 diff = color.rgb - error;
|
||||||
|
vec3 correction;
|
||||||
|
correction.r = 0.0;
|
||||||
|
correction.g = (diff.r * 0.7) + (diff.g * 1.0);
|
||||||
|
correction.b = (diff.r * 0.7) + (diff.b * 1.0);
|
||||||
|
|
||||||
|
color.rgb += correction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-multiply
|
||||||
|
color.rgb *= color.a;
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue