2022-02-04 21:04:17 +01:00
// SPDX-License-Identifier: GPL-3.0-only
#[ cfg(feature = " debug " ) ]
2022-11-17 20:32:54 +01:00
use crate ::{ debug ::fps_ui , state ::Fps , utils ::prelude ::* } ;
2022-02-04 21:04:17 +01:00
use crate ::{
2022-11-17 20:32:54 +01:00
shell ::{ layout ::floating ::SeatMoveGrabState , CosmicMappedRenderElement } ,
2022-10-26 15:26:07 +02:00
state ::Common ,
2022-11-03 18:51:27 +01:00
wayland ::{
2022-11-17 20:32:54 +01:00
handlers ::{ data_device ::get_dnd_icon , screencopy ::render_session } ,
2022-11-03 18:51:27 +01:00
protocols ::{
2022-11-04 17:34:17 +01:00
screencopy ::{
BufferParams , CursorMode as ScreencopyCursorMode , Session as ScreencopySession ,
} ,
2022-11-03 18:51:27 +01:00
workspace ::WorkspaceHandle ,
} ,
} ,
2022-08-30 13:28:36 +02:00
} ;
2022-02-04 21:04:17 +01:00
2022-11-03 18:51:27 +01:00
use cosmic_protocols ::screencopy ::v1 ::server ::zcosmic_screencopy_session_v1 ::FailureReason ;
2022-02-04 21:04:17 +01:00
use smithay ::{
2022-03-22 12:36:03 +01:00
backend ::{
2022-11-03 18:51:27 +01:00
allocator ::dmabuf ::Dmabuf ,
2022-03-22 12:36:03 +01:00
drm ::DrmNode ,
renderer ::{
2022-11-17 20:32:54 +01:00
buffer_dimensions ,
2022-09-28 12:01:29 +02:00
damage ::{
DamageTrackedRenderer , DamageTrackedRendererError as RenderError , OutputNoMode ,
} ,
2022-11-17 20:32:54 +01:00
element ::{ RenderElement , RenderElementStates } ,
gles2 ::{ Gles2Error , Gles2Renderbuffer } ,
glow ::GlowRenderer ,
2022-09-28 12:01:29 +02:00
multigpu ::{ egl ::EglGlesBackend , MultiFrame , MultiRenderer } ,
2022-11-03 18:51:27 +01:00
Bind , Blit , ExportMem , ImportAll , ImportMem , Offscreen , Renderer , TextureFilter ,
2022-03-22 12:36:03 +01:00
} ,
2022-03-16 20:05:24 +01:00
} ,
2022-09-09 20:00:00 -07:00
output ::Output ,
2022-11-04 17:34:17 +01:00
utils ::{ Physical , Rectangle } ,
2022-11-17 20:32:54 +01:00
wayland ::dmabuf ::get_dmabuf ,
2022-02-04 21:04:17 +01:00
} ;
2022-08-05 14:28:37 +02:00
pub mod cursor ;
2022-09-28 12:01:29 +02:00
use self ::cursor ::CursorRenderElement ;
2022-11-17 20:32:54 +01:00
pub mod element ;
use self ::element ::{ AsGles2Frame , AsGlowRenderer , CosmicElement } ;
2022-02-04 21:04:17 +01:00
2022-09-28 12:01:29 +02:00
pub type GlMultiRenderer < ' a > = MultiRenderer <
' a ,
' a ,
2022-11-17 20:32:54 +01:00
EglGlesBackend < GlowRenderer > ,
EglGlesBackend < GlowRenderer > ,
2022-09-28 12:01:29 +02:00
Gles2Renderbuffer ,
> ;
2022-11-17 20:32:54 +01:00
pub type GlMultiFrame = MultiFrame < EglGlesBackend < GlowRenderer > , EglGlesBackend < GlowRenderer > > ;
2022-03-16 20:06:31 +01:00
2022-11-03 18:51:27 +01:00
pub static CLEAR_COLOR : [ f32 ; 4 ] = [ 0.153 , 0.161 , 0.165 , 1.0 ] ;
2022-04-22 15:18:28 +02:00
2022-11-03 18:51:27 +01:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub enum CursorMode {
None ,
NotDefault ,
All ,
}
2022-09-28 12:01:29 +02:00
pub fn cursor_elements < E , R > (
2022-08-05 16:28:05 +02:00
renderer : & mut R ,
state : & Common ,
output : & Output ,
2022-11-03 18:51:27 +01:00
mode : CursorMode ,
2022-09-28 12:01:29 +02:00
) -> Vec < E >
2022-08-05 16:28:05 +02:00
where
2022-09-28 12:01:29 +02:00
R : Renderer + ImportAll + ImportMem ,
2022-11-17 20:32:54 +01:00
< R as Renderer > ::Frame : AsGles2Frame ,
2022-09-28 12:01:29 +02:00
< R as Renderer > ::TextureId : Clone + 'static ,
2022-10-26 15:26:07 +02:00
E : From < CursorRenderElement < R > > + From < CosmicMappedRenderElement < R > > ,
2022-08-05 16:28:05 +02:00
{
2022-09-28 12:01:29 +02:00
let scale = output . current_scale ( ) . fractional_scale ( ) ;
let mut elements = Vec ::new ( ) ;
2022-08-05 16:28:05 +02:00
2022-09-28 12:01:29 +02:00
for seat in state . seats ( ) {
2022-08-05 16:28:05 +02:00
let pointer = match seat . get_pointer ( ) {
Some ( ptr ) = > ptr ,
None = > continue ,
} ;
let location = state
. shell
2022-09-28 12:01:29 +02:00
. map_global_to_space ( pointer . current_location ( ) . to_i32_round ( ) , output ) ;
2022-08-05 16:28:05 +02:00
2022-11-03 18:51:27 +01:00
if mode ! = CursorMode ::None {
elements . extend (
cursor ::draw_cursor (
renderer ,
seat ,
location ,
scale . into ( ) ,
2022-11-17 20:32:54 +01:00
state . clock . now ( ) ,
2022-11-03 18:51:27 +01:00
mode ! = CursorMode ::NotDefault ,
)
. into_iter ( )
. map ( E ::from ) ,
) ;
}
2022-10-26 15:26:07 +02:00
if let Some ( wl_surface ) = get_dnd_icon ( seat ) {
elements . extend (
cursor ::draw_dnd_icon ( & wl_surface , location . to_i32_round ( ) , scale )
. into_iter ( )
. map ( E ::from ) ,
) ;
}
if let Some ( grab_elements ) = seat
. user_data ( )
. get ::< SeatMoveGrabState > ( )
. unwrap ( )
. borrow ( )
. as_ref ( )
. map ( | state | state . render ::< E , R > ( seat , output ) )
{
elements . extend ( grab_elements ) ;
}
2022-08-05 16:28:05 +02:00
}
2022-09-28 12:01:29 +02:00
elements
2022-08-05 16:28:05 +02:00
}
2022-11-17 20:32:54 +01:00
pub fn render_output < R , Target , OffTarget , Source > (
2022-04-22 15:18:28 +02:00
gpu : Option < & DrmNode > ,
2022-03-16 20:05:24 +01:00
renderer : & mut R ,
2022-11-17 20:32:54 +01:00
target : Target ,
2022-09-28 12:01:29 +02:00
damage_tracker : & mut DamageTrackedRenderer ,
age : usize ,
2022-02-04 21:04:17 +01:00
state : & mut Common ,
output : & Output ,
2022-11-03 18:51:27 +01:00
cursor_mode : CursorMode ,
screencopy : Option < ( Source , & [ ( ScreencopySession , BufferParams ) ] ) > ,
2022-11-17 20:32:54 +01:00
#[ cfg(feature = " debug " ) ] fps : Option < & mut Fps > ,
2022-11-03 18:51:27 +01:00
) -> Result < ( Option < Vec < Rectangle < i32 , Physical > > > , RenderElementStates ) , RenderError < R > >
2022-08-05 14:28:37 +02:00
where
2022-11-03 18:51:27 +01:00
R : Renderer
+ ImportAll
+ ImportMem
+ ExportMem
+ Bind < Dmabuf >
2022-11-17 20:32:54 +01:00
+ Bind < Target >
+ Offscreen < OffTarget >
+ Blit < Source >
+ AsGlowRenderer ,
< R as Renderer > ::Frame : AsGles2Frame ,
2022-08-05 14:28:37 +02:00
< R as Renderer > ::TextureId : Clone + 'static ,
2022-11-17 20:32:54 +01:00
< R as Renderer > ::Error : From < Gles2Error > ,
CosmicElement < R > : RenderElement < R > ,
2022-11-03 18:51:27 +01:00
Source : Clone ,
2022-08-05 14:28:37 +02:00
{
2022-11-03 18:51:27 +01:00
let handle = state . shell . workspaces . active ( output ) . handle ;
2022-08-05 14:28:37 +02:00
render_workspace (
gpu ,
renderer ,
2022-11-17 20:32:54 +01:00
target ,
2022-09-28 12:01:29 +02:00
damage_tracker ,
2022-08-05 14:28:37 +02:00
age ,
state ,
output ,
2022-11-03 18:51:27 +01:00
& handle ,
cursor_mode ,
screencopy ,
2022-11-17 20:32:54 +01:00
#[ cfg(feature = " debug " ) ]
fps ,
2022-08-05 14:28:37 +02:00
)
}
2022-11-17 20:32:54 +01:00
pub fn render_workspace < R , Target , OffTarget , Source > (
2022-11-03 18:51:27 +01:00
gpu : Option < & DrmNode > ,
2022-08-05 14:28:37 +02:00
renderer : & mut R ,
2022-11-17 20:32:54 +01:00
target : Target ,
2022-09-28 12:01:29 +02:00
damage_tracker : & mut DamageTrackedRenderer ,
age : usize ,
2022-08-05 14:28:37 +02:00
state : & mut Common ,
output : & Output ,
2022-11-03 18:51:27 +01:00
handle : & WorkspaceHandle ,
2022-11-04 17:34:17 +01:00
mut cursor_mode : CursorMode ,
2022-11-03 18:51:27 +01:00
screencopy : Option < ( Source , & [ ( ScreencopySession , BufferParams ) ] ) > ,
2022-08-05 14:28:37 +02:00
#[ cfg(feature = " debug " ) ] mut fps : Option < & mut Fps > ,
2022-11-03 18:51:27 +01:00
) -> Result < ( Option < Vec < Rectangle < i32 , Physical > > > , RenderElementStates ) , RenderError < R > >
2022-03-16 20:05:24 +01:00
where
2022-11-03 18:51:27 +01:00
R : Renderer
+ ImportAll
+ ImportMem
+ ExportMem
+ Bind < Dmabuf >
2022-11-17 20:32:54 +01:00
+ Bind < Target >
+ Offscreen < OffTarget >
+ Blit < Source >
+ AsGlowRenderer ,
< R as Renderer > ::Frame : AsGles2Frame ,
2022-03-16 20:05:24 +01:00
< R as Renderer > ::TextureId : Clone + 'static ,
2022-11-17 20:32:54 +01:00
< R as Renderer > ::Error : From < Gles2Error > ,
CosmicElement < R > : RenderElement < R > ,
Source : Clone ,
2022-03-16 20:05:24 +01:00
{
2022-02-04 21:04:17 +01:00
#[ cfg(feature = " debug " ) ]
2022-08-03 16:34:04 +02:00
if let Some ( ref mut fps ) = fps {
2022-02-04 21:04:17 +01:00
fps . start ( ) ;
}
2022-08-05 14:28:37 +02:00
2022-11-03 18:51:27 +01:00
let workspace = state . shell . space_for_handle ( & handle ) . ok_or ( OutputNoMode ) ? ;
2022-04-22 15:18:28 +02:00
2022-11-04 17:34:17 +01:00
let screencopy_contains_embedded = screencopy . as_ref ( ) . map_or ( false , | ( _ , sessions ) | {
sessions
. iter ( )
. any ( | ( s , _ ) | s . cursor_mode ( ) = = ScreencopyCursorMode ::Embedded )
} ) ;
// cursor handling without a cursor_plane in this case is horrible.
// because what if some session disagree and/or the backend wants to render with a different mode?
// It seems we would need to render to an offscreen buffer in those cases (and do multiple renders, which messes with damage tracking).
// So for now, we just pick the worst mode (embedded), if any requires it.
//
// Once we move to a cursor_plane, the default framebuffer will never contain a cursor and we can just composite the cursor for each session separately on top (or not).
if screencopy_contains_embedded {
cursor_mode = CursorMode ::All ;
} ;
2022-11-03 18:51:27 +01:00
let mut elements : Vec < CosmicElement < R > > = cursor_elements ( renderer , state , output , cursor_mode ) ;
2022-02-04 21:04:17 +01:00
#[ cfg(feature = " debug " ) ]
{
2022-11-17 20:32:54 +01:00
let output_geo = output . geometry ( ) ;
2022-04-20 16:06:37 +02:00
let scale = output . current_scale ( ) . fractional_scale ( ) ;
2022-02-04 21:04:17 +01:00
2022-11-17 20:32:54 +01:00
if let Some ( fps ) = fps . as_mut ( ) {
2022-07-20 17:25:36 +02:00
let fps_overlay = fps_ui (
2022-11-17 20:32:54 +01:00
gpu ,
2022-07-20 17:25:36 +02:00
state ,
2022-11-17 20:32:54 +01:00
renderer . glow_renderer_mut ( ) ,
2022-07-20 17:25:36 +02:00
fps ,
2022-11-17 20:32:54 +01:00
Rectangle ::from_loc_and_size (
( 0 , 0 ) ,
( output_geo . size . w . min ( 400 ) , output_geo . size . h . min ( 800 ) ) ,
) ,
2022-07-20 17:25:36 +02:00
scale ,
2022-11-17 20:32:54 +01:00
)
. map_err ( < R as Renderer > ::Error ::from )
. map_err ( RenderError ::Rendering ) ? ;
elements . push ( fps_overlay . into ( ) ) ;
2022-02-04 21:04:17 +01:00
}
}
2022-09-28 12:01:29 +02:00
elements . extend (
workspace
2022-11-17 20:32:54 +01:00
. render_output ::< R > ( output )
2022-09-28 12:01:29 +02:00
. map_err ( | _ | OutputNoMode ) ?
. into_iter ( )
. map ( Into ::into ) ,
) ;
2022-04-22 15:18:28 +02:00
2022-11-17 20:32:54 +01:00
renderer . bind ( target ) . map_err ( RenderError ::Rendering ) ? ;
2022-09-28 12:01:29 +02:00
let res = damage_tracker . render_output ( renderer , age , & elements , CLEAR_COLOR , None ) ;
2022-02-04 21:04:17 +01:00
#[ cfg(feature = " debug " ) ]
2022-11-17 20:32:54 +01:00
if let Some ( fps ) = fps . as_mut ( ) {
2022-09-28 12:01:29 +02:00
fps . end ( ) ;
2022-04-22 15:18:28 +02:00
}
2022-05-03 13:37:51 +02:00
2022-11-03 18:51:27 +01:00
if let Some ( ( source , buffers ) ) = screencopy {
if res . is_ok ( ) {
for ( session , params ) in buffers {
2022-11-17 20:32:54 +01:00
match render_session (
2022-11-03 18:51:27 +01:00
gpu . cloned ( ) ,
renderer ,
& session ,
params ,
output . current_transform ( ) ,
2022-11-17 20:32:54 +01:00
| _node , buffer , renderer , dtr , age | {
2022-11-03 18:51:27 +01:00
let res = dtr . damage_output ( age , & elements , slog_scope ::logger ( ) ) ? ;
if let ( Some ( ref damage ) , _ ) = & res {
2022-11-17 20:32:54 +01:00
if let Ok ( dmabuf ) = get_dmabuf ( buffer ) {
renderer . bind ( dmabuf ) . map_err ( RenderError ::Rendering ) ? ;
} else {
let size = buffer_dimensions ( buffer ) . unwrap ( ) ;
let render_buffer = renderer
. create_buffer ( size )
. map_err ( RenderError ::Rendering ) ? ;
renderer
. bind ( render_buffer )
. map_err ( RenderError ::Rendering ) ? ;
}
2022-11-03 18:51:27 +01:00
for rect in damage {
renderer
. blit_from ( source . clone ( ) , * rect , * rect , TextureFilter ::Nearest )
. map_err ( RenderError ::Rendering ) ? ;
}
}
Ok ( res )
} ,
) {
Ok ( true ) = > { } // success
Ok ( false ) = > state . still_pending ( session . clone ( ) , params . clone ( ) ) ,
Err ( err ) = > {
slog_scope ::warn! ( " Error rendering to screencopy session: {} " , err ) ;
session . failed ( FailureReason ::Unspec ) ;
}
}
}
}
}
2022-09-28 12:01:29 +02:00
res
2022-02-04 21:04:17 +01:00
}