2022-02-04 21:04:17 +01:00
// SPDX-License-Identifier: GPL-3.0-only
#[ cfg(feature = " debug " ) ]
2022-11-22 18:20:20 +01:00
use crate ::{ debug ::fps_ui , 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-11-22 18:20:20 +01:00
state ::{ Common , Fps } ,
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 } ,
2023-02-13 17:44:24 +01:00
gles2 ::Gles2Error ,
2022-11-17 20:32:54 +01:00
glow ::GlowRenderer ,
2023-02-13 17:44:24 +01:00
multigpu ::{ gbm ::GbmGlesBackend , 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
} ;
2023-02-24 17:41:52 +01:00
use tracing ::warn ;
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 ;
2022-11-28 17:48:50 +01:00
use self ::element ::{ AsGlowRenderer , CosmicElement } ;
2022-02-04 21:04:17 +01:00
2023-02-13 17:44:24 +01:00
pub type GlMultiRenderer < ' a , ' b > =
MultiRenderer < ' a , ' a , ' b , GbmGlesBackend < GlowRenderer > , GbmGlesBackend < GlowRenderer > > ;
pub type GlMultiFrame < ' a , ' b , ' frame > =
MultiFrame < ' a , ' a , ' b , ' frame , GbmGlesBackend < GlowRenderer > , GbmGlesBackend < 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-11-28 17:48:50 +01:00
pub fn cursor_elements < ' frame , 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-11-22 10:28:30 +01:00
R : Renderer + ImportAll + ImportMem + AsGlowRenderer ,
2022-09-28 12:01:29 +02:00
< R as Renderer > ::TextureId : Clone + 'static ,
2022-11-22 10:28:30 +01:00
CosmicMappedRenderElement < R > : RenderElement < R > ,
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 ,
} ;
2022-11-22 19:52:13 +01:00
let location = pointer . current_location ( ) - output . current_location ( ) . to_f64 ( ) ;
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 (
2022-11-28 17:48:50 +01:00
cursor ::draw_dnd_icon ( renderer , & wl_surface , location . to_i32_round ( ) , scale )
2022-10-26 15:26:07 +02:00
. into_iter ( )
. map ( E ::from ) ,
) ;
}
if let Some ( grab_elements ) = seat
. user_data ( )
. get ::< SeatMoveGrabState > ( )
. unwrap ( )
. borrow ( )
. as_ref ( )
2022-11-28 17:48:50 +01:00
. map ( | state | state . render ::< E , R > ( renderer , seat , output ) )
2022-10-26 15:26:07 +02:00
{
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-28 17:48:50 +01:00
pub fn render_output < ' frame , 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-22 18:20:20 +01:00
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 ,
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-22 10:28:30 +01:00
CosmicMappedRenderElement < 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 ;
2023-01-23 18:25:01 +01:00
let result = render_workspace (
2022-08-05 14:28:37 +02:00
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
fps ,
2023-02-10 14:32:56 -08:00
false ,
2023-01-23 18:25:01 +01:00
) ;
result
2022-08-05 14:28:37 +02:00
}
2022-11-28 17:48:50 +01:00
pub fn render_workspace < ' frame , 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-11-22 18:20:20 +01:00
mut fps : Option < & mut Fps > ,
2023-02-10 14:32:56 -08:00
exclude_workspace_overview : bool ,
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 ,
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 > ,
2022-11-22 10:28:30 +01:00
CosmicMappedRenderElement < R > : RenderElement < R > ,
2022-11-17 20:32:54 +01:00
Source : Clone ,
2022-03-16 20:05:24 +01:00
{
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-11-28 17:48:50 +01:00
#[ cfg(feature = " debug " ) ]
2023-02-27 23:54:28 +01:00
if let Some ( rd ) = fps . rd . as_mut ( ) {
rd . start_frame_capture (
renderer . glow_renderer ( ) . egl_context ( ) . get_context_handle ( ) ,
std ::ptr ::null ( ) ,
) ;
2022-11-28 17:48:50 +01:00
}
2022-02-04 21:04:17 +01:00
}
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
2023-01-23 22:56:10 +01:00
. render_output ::< R > (
renderer ,
output ,
& state . shell . override_redirect_windows ,
state . xwayland_state . values_mut ( ) ,
2023-02-10 14:32:56 -08:00
exclude_workspace_overview ,
2023-01-23 22:56:10 +01:00
)
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-18 17:20:52 +01:00
if let Some ( fps ) = fps . as_mut ( ) {
fps . elements ( ) ;
}
2022-11-17 20:32:54 +01:00
renderer . bind ( target ) . map_err ( RenderError ::Rendering ) ? ;
2023-02-24 17:41:52 +01:00
let res = damage_tracker . render_output ( renderer , age , & elements , CLEAR_COLOR ) ;
2022-02-04 21:04:17 +01:00
2022-11-17 20:32:54 +01:00
if let Some ( fps ) = fps . as_mut ( ) {
2022-11-18 17:20:52 +01:00
fps . render ( ) ;
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 | {
2023-02-24 17:41:52 +01:00
let res = dtr . damage_output ( age , & elements ) ? ;
2022-11-03 18:51:27 +01:00
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 ) = > {
2023-02-24 17:41:52 +01:00
warn! ( ? err , " Error rendering to screencopy session. " ) ;
2022-11-03 18:51:27 +01:00
session . failed ( FailureReason ::Unspec ) ;
}
}
}
}
2022-11-18 17:20:52 +01:00
if let Some ( fps ) = fps . as_mut ( ) {
fps . screencopy ( ) ;
2023-02-27 23:54:28 +01:00
}
}
#[ cfg(feature = " debug " ) ]
if let Some ( ref mut fps ) = fps {
if let Some ( rd ) = fps . rd . as_mut ( ) {
rd . end_frame_capture (
renderer . glow_renderer ( ) . egl_context ( ) . get_context_handle ( ) ,
std ::ptr ::null ( ) ,
) ;
2022-11-18 17:20:52 +01:00
}
2022-11-03 18:51:27 +01:00
}
2022-09-28 12:01:29 +02:00
res
2022-02-04 21:04:17 +01:00
}