diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 29eb021..4ce4225 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -108,7 +108,7 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[ const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888]; /// A [`MultiRenderer`] that uses the [`GbmGlesBackend`]. -type UdevRenderer<'a> = MultiRenderer< +pub type UdevRenderer<'a> = MultiRenderer< 'a, 'a, GbmGlesBackend, @@ -866,6 +866,12 @@ fn render_frame<'a>( } impl Udev { + pub fn renderer(&mut self) -> UdevRenderer<'_> { + self.gpu_manager + .single_renderer(&self.primary_gpu) + .expect("failed to create multirenderer") + } + /// A GPU was plugged in. fn device_added( &mut self, diff --git a/src/layout.rs b/src/layout.rs index 2815ae8..9c39c67 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later +pub mod transaction; + use std::{collections::HashMap, time::Duration}; use pinnacle_api_defs::pinnacle::layout::v0alpha1::{layout_request::Geometries, LayoutResponse}; diff --git a/src/layout/transaction.rs b/src/layout/transaction.rs new file mode 100644 index 0000000..db85db8 --- /dev/null +++ b/src/layout/transaction.rs @@ -0,0 +1,18 @@ +use std::collections::HashMap; + +use smithay::{ + backend::renderer::gles::GlesTexture, + utils::{Logical, Point, Serial}, +}; + +use crate::window::WindowElement; + +pub struct LayoutTransaction { + from: Vec<(GlesTexture)>, + to: HashMap, +} + +pub struct PendingLayoutState { + serial: Serial, + loc: Point, +} diff --git a/src/render.rs b/src/render.rs index 08a0e60..49ad920 100644 --- a/src/render.rs +++ b/src/render.rs @@ -4,7 +4,10 @@ use std::{ops::Deref, sync::Mutex}; use smithay::{ backend::renderer::{ - element::{surface::WaylandSurfaceRenderElement, AsRenderElements, RenderElementStates}, + element::{ + surface::WaylandSurfaceRenderElement, AsRenderElements, Element, RenderElementStates, + }, + gles::{GlesRenderer, GlesTexture}, ImportAll, ImportMem, Renderer, Texture, }, desktop::{ @@ -26,21 +29,35 @@ use smithay::{ use crate::{ backend::Backend, + pinnacle_render_elements, state::{State, WithState}, window::WindowElement, }; -use self::pointer::{PointerElement, PointerRenderElement}; +use self::{ + pointer::{PointerElement, PointerRenderElement}, + texture::CommonTextureRenderElement, +}; pub mod pointer; +pub mod render_elements; +pub mod texture; pub const CLEAR_COLOR: [f32; 4] = [0.6, 0.6, 0.6, 1.0]; pub const CLEAR_COLOR_LOCKED: [f32; 4] = [0.2, 0.0, 0.3, 1.0]; -render_elements! { - pub OutputRenderElement where R: ImportAll + ImportMem; - Surface = WaylandSurfaceRenderElement, - Pointer = PointerRenderElement, +// render_elements! { +// pub OutputRenderElement where R: ImportAll + ImportMem; +// Surface = WaylandSurfaceRenderElement, +// Pointer = PointerRenderElement, +// } + +pinnacle_render_elements! { + #[derive(Debug)] + pub enum OutputRenderElement { + Surface = WaylandSurfaceRenderElement, + Pointer = PointerRenderElement, + } } impl AsRenderElements for WindowElement @@ -173,7 +190,7 @@ pub fn pointer_render_elements( pointer_element: &PointerElement<::TextureId>, ) -> Vec> where - R: Renderer + ImportAll, + R: Renderer + ImportAll + ImportMem, ::TextureId: Clone + 'static, { let mut output_render_elements = Vec::new(); @@ -349,3 +366,32 @@ impl State { } } } + +impl Backend { + pub fn render_to_texture( + &mut self, + window: &WindowElement, + scale: f64, + ) -> Vec<(GlesTexture, Point)> { + let render_to_texture = |renderer: &mut GlesRenderer, window: &WindowElement| { + let elements = window.render_elements::>( + renderer, + (0, 0).into(), + scale.into(), + 1.0, + ); + + elements + .into_iter() + .map(|elem| (elem.texture().clone(), elem.location(scale.into()))) + .collect() + }; + + match self { + Backend::Winit(winit) => render_to_texture(winit.backend.renderer(), window), + Backend::Udev(udev) => render_to_texture(udev.renderer().as_mut(), window), + #[cfg(feature = "testing")] + Backend::Dummy(_) => Vec::new(), + } + } +} diff --git a/src/render/pointer.rs b/src/render/pointer.rs index 79dce35..ddf4127 100644 --- a/src/render/pointer.rs +++ b/src/render/pointer.rs @@ -50,6 +50,7 @@ impl PointerElement { } render_elements! { + #[derive(Debug)] pub PointerRenderElement where R: ImportAll; Surface=WaylandSurfaceRenderElement, Texture=TextureRenderElement<::TextureId>, diff --git a/src/render/render_elements.rs b/src/render/render_elements.rs new file mode 100644 index 0000000..7f8ae6e --- /dev/null +++ b/src/render/render_elements.rs @@ -0,0 +1,229 @@ +/// A custom implementation of [`smithay::render_elements`] that is not generic but rather +/// implements over the three used renderers. +/// +/// This is needed to allow GlesTextures to be easily rendered on winit and udev. +/// +/// Also idea from Niri. Ya know this whole compositor is slowly inching towards +/// being a Niri clone lol +#[macro_export] +macro_rules! pinnacle_render_elements { + ( + $(#[$attr:meta])* + $vis:vis enum $name:ident { + $($variant:ident = $type:ty),+ $(,)? + } + ) => { + $(#[$attr])* + $vis enum $name { + $($variant($type)),+ + } + + $(impl From<$type> for $name { + fn from(x: $type) -> Self { + Self::$variant(x) + } + })+ + + $crate::pinnacle_render_elements! { + @impl $name ($name) () => { $($variant = $type),+ } + } + }; + + ( + $(#[$attr:meta])* + $vis:vis enum $name:ident<$generic_name:ident> { + $($variant:ident = $type:ty),+ $(,)? + } + ) => { + $(#[$attr])* + $vis enum $name<$generic_name> + where + $generic_name: ::smithay::backend::renderer::Renderer + ::smithay::backend::renderer::ImportAll + ::smithay::backend::renderer::ImportMem, + $generic_name::TextureId: 'static, + { + $($variant($type)),+ + } + + $(impl<$generic_name> From<$type> for $name<$generic_name> + where + $generic_name: ::smithay::backend::renderer::Renderer + ::smithay::backend::renderer::ImportAll + ::smithay::backend::renderer::ImportMem, + $generic_name::TextureId: 'static, + { + fn from(x: $type) -> Self { + Self::$variant(x) + } + })+ + + $crate::pinnacle_render_elements! { + @impl $name () ($name<$generic_name>) => { $($variant = $type),+ } + } + }; + + (@impl $name:ident ($($name_no_generic:ident)?) ($($name_generic:ident<$generic:ident>)?) => { + $($variant:ident = $type:ty),+ + }) => { + impl$(<$generic>)? ::smithay::backend::renderer::element::Element for $name$(<$generic>)? + $(where + $generic: ::smithay::backend::renderer::Renderer + ::smithay::backend::renderer::ImportAll + ::smithay::backend::renderer::ImportMem, + $generic::TextureId: 'static,)? + { + fn id(&self) -> &::smithay::backend::renderer::element::Id { + match self { + $($name::$variant(elem) => elem.id()),+ + } + } + + fn current_commit(&self) -> ::smithay::backend::renderer::utils::CommitCounter { + match self { + $($name::$variant(elem) => elem.current_commit()),+ + } + } + + fn geometry( + &self, + scale: ::smithay::utils::Scale + ) -> ::smithay::utils::Rectangle { + match self { + $($name::$variant(elem) => elem.geometry(scale)),+ + } + } + + fn transform(&self) -> ::smithay::utils::Transform { + match self { + $($name::$variant(elem) => elem.transform()),+ + } + } + + fn src(&self) -> ::smithay::utils::Rectangle { + match self { + $($name::$variant(elem) => elem.src()),+ + } + } + + fn damage_since( + &self, + scale: ::smithay::utils::Scale, + commit: ::std::option::Option<::smithay::backend::renderer::utils::CommitCounter>, + ) -> ::smithay::backend::renderer::utils::DamageSet { + match self { + $($name::$variant(elem) => elem.damage_since(scale, commit)),+ + } + } + + fn opaque_regions( + &self, + scale: ::smithay::utils::Scale, + ) -> ::smithay::backend::renderer::utils::OpaqueRegions { + match self { + $($name::$variant(elem) => elem.opaque_regions(scale)),+ + } + } + + fn alpha(&self) -> f32 { + match self { + $($name::$variant(elem) => elem.alpha()),+ + } + } + + fn kind(&self) -> ::smithay::backend::renderer::element::Kind { + match self { + $($name::$variant(elem) => elem.kind()),+ + } + } + } + + impl ::smithay::backend::renderer::element::RenderElement<::smithay::backend::renderer::gles::GlesRenderer> + for $($name_generic<::smithay::backend::renderer::gles::GlesRenderer>)? $($name_no_generic)? + { + fn draw( + &self, + frame: &mut ::smithay::backend::renderer::gles::GlesFrame<'_>, + src: ::smithay::utils::Rectangle, + dst: ::smithay::utils::Rectangle, + damage: &[::smithay::utils::Rectangle], + ) -> ::std::result::Result<(), ::smithay::backend::renderer::gles::GlesError> { + match self { + $($name::$variant(elem) => { + ::smithay::backend::renderer::element::RenderElement::< + ::smithay::backend::renderer::gles::GlesRenderer + >::draw(elem, frame, src, dst, damage) + })+ + } + } + + fn underlying_storage( + &self, + renderer: &mut ::smithay::backend::renderer::gles::GlesRenderer + ) -> ::std::option::Option<::smithay::backend::renderer::element::UnderlyingStorage> { + match self { + $($name::$variant(elem) => elem.underlying_storage(renderer)),+ + } + } + } + + impl<'a> ::smithay::backend::renderer::element::RenderElement<$crate::backend::udev::UdevRenderer<'a>> + for $($name_generic<$crate::backend::udev::UdevRenderer<'a>>)? $($name_no_generic)? + { + fn draw( + &self, + frame: &mut <$crate::backend::udev::UdevRenderer<'a> as ::smithay::backend::renderer::Renderer>::Frame<'_>, + src: ::smithay::utils::Rectangle, + dst: ::smithay::utils::Rectangle, + damage: &[::smithay::utils::Rectangle], + ) -> ::std::result::Result< + (), + <$crate::backend::udev::UdevRenderer as ::smithay::backend::renderer::Renderer>::Error, + > { + match self { + $($name::$variant(elem) => { + ::smithay::backend::renderer::element::RenderElement::< + $crate::backend::udev::UdevRenderer + >::draw(elem, frame, src, dst, damage) + })+ + } + } + + fn underlying_storage( + &self, + renderer: &mut $crate::backend::udev::UdevRenderer<'a>, + ) -> ::std::option::Option<::smithay::backend::renderer::element::UnderlyingStorage> { + match self { + $($name::$variant(elem) => elem.underlying_storage(renderer)),+ + } + } + } + + #[cfg(feature = "testing")] + impl ::smithay::backend::renderer::element::RenderElement<::smithay::backend::renderer::test::DummyRenderer> + for $($name_generic<::smithay::backend::renderer::test::DummyRenderer>)? $($name_no_generic)? + { + fn draw( + &self, + frame: &mut <::smithay::backend::renderer::test::DummyRenderer as ::smithay::backend::renderer::Renderer>::Frame<'_>, + src: ::smithay::utils::Rectangle, + dst: ::smithay::utils::Rectangle, + damage: &[::smithay::utils::Rectangle], + ) -> ::std::result::Result< + (), + <::smithay::backend::renderer::test::DummyRenderer as ::smithay::backend::renderer::Renderer>::Error, + > { + match self { + $($name::$variant(elem) => { + ::smithay::backend::renderer::element::RenderElement::< + ::smithay::backend::renderer::test::DummyRenderer + >::draw(elem, frame, src, dst, damage) + })+ + } + } + + fn underlying_storage( + &self, + renderer: &mut ::smithay::backend::renderer::test::DummyRenderer, + ) -> ::std::option::Option<::smithay::backend::renderer::element::UnderlyingStorage> { + match self { + $($name::$variant(elem) => elem.underlying_storage(renderer)),+ + } + } + } + } +} diff --git a/src/render/texture.rs b/src/render/texture.rs new file mode 100644 index 0000000..81b65eb --- /dev/null +++ b/src/render/texture.rs @@ -0,0 +1,101 @@ +use smithay::{ + backend::renderer::{ + element::{self, texture::TextureRenderElement, Element, RenderElement}, + gles::{GlesRenderer, GlesTexture}, + utils::{CommitCounter, DamageSet, OpaqueRegions}, + Renderer, + }, + utils::{Buffer, Physical, Rectangle, Scale}, +}; + +use crate::backend::udev::UdevRenderer; + +/// TODO: docs +pub struct CommonTextureRenderElement(TextureRenderElement); + +impl Element for CommonTextureRenderElement { + fn id(&self) -> &element::Id { + self.0.id() + } + + fn current_commit(&self) -> CommitCounter { + self.0.current_commit() + } + + fn src(&self) -> Rectangle { + self.0.src() + } + + fn geometry(&self, scale: Scale) -> Rectangle { + self.0.geometry(scale) + } + + fn location(&self, scale: Scale) -> smithay::utils::Point { + self.0.location(scale) + } + + fn transform(&self) -> smithay::utils::Transform { + self.0.transform() + } + + fn damage_since( + &self, + scale: Scale, + commit: Option, + ) -> DamageSet { + self.0.damage_since(scale, commit) + } + + fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { + self.0.opaque_regions(scale) + } + + fn alpha(&self) -> f32 { + self.0.alpha() + } + + fn kind(&self) -> element::Kind { + self.0.kind() + } +} + +impl RenderElement for CommonTextureRenderElement { + fn draw( + &self, + frame: &mut ::Frame<'_>, + src: Rectangle, + dst: Rectangle, + damage: &[Rectangle], + ) -> Result<(), ::Error> { + RenderElement::::draw(&self.0, frame, src, dst, damage) + } + + fn underlying_storage( + &self, + renderer: &mut GlesRenderer, + ) -> Option> { + let _ = renderer; + None + } +} + +impl<'a> RenderElement> for CommonTextureRenderElement { + fn draw( + &self, + frame: &mut as Renderer>::Frame<'_>, + src: Rectangle, + dst: Rectangle, + damage: &[Rectangle], + ) -> Result<(), as Renderer>::Error> { + RenderElement::::draw(&self.0, frame.as_mut(), src, dst, damage)?; + Ok(()) + } + + fn underlying_storage( + &self, + renderer: &mut UdevRenderer<'a>, + ) -> Option> { + let _ = renderer; + None + } +}