2022-02-04 21:04:17 +01:00
// SPDX-License-Identifier: GPL-3.0-only
2023-02-25 00:17:54 +01:00
use std ::{
borrow ::{ Borrow , BorrowMut } ,
cell ::RefCell ,
} ;
2022-02-04 21:04:17 +01:00
#[ cfg(feature = " debug " ) ]
2023-03-06 18:48:52 +01:00
use crate ::{
debug ::{ fps_ui , profiler_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 } ,
2023-03-06 18:52:55 +01:00
utils ::prelude ::SeatExt ,
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 ,
} ,
2023-02-25 00:17:54 +01:00
element ::{ Element , RenderElement , RenderElementStates } ,
gles2 ::{
element ::PixelShaderElement , Gles2Error , Gles2PixelProgram , Gles2Renderer , Uniform ,
UniformName , UniformType ,
} ,
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 ,
2023-02-25 00:17:54 +01:00
utils ::{ Logical , Physical , Point , Rectangle , Size } ,
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 ] ;
2023-02-25 00:17:54 +01:00
pub static FOCUS_INDICATOR_COLOR : [ f32 ; 4 ] = [ 0.580 , 0.921 , 0.921 , 1.0 ] ;
pub static FOCUS_INDICATOR_THICKNESS : f32 = 4.0 ;
pub static FOCUS_INDICATOR_RADIUS : f32 = 8.0 ;
pub static FOCUS_INDICATOR_SHADER : & str = include_str! ( " ./shaders/focus_indicator.frag " ) ;
pub struct IndicatorShader ( pub Gles2PixelProgram ) ;
struct IndicatorElement ( pub RefCell < PixelShaderElement > ) ;
impl IndicatorShader {
pub fn get < R : AsGlowRenderer > ( renderer : & R ) -> Gles2PixelProgram {
Borrow ::< Gles2Renderer > ::borrow ( renderer . glow_renderer ( ) )
. egl_context ( )
. user_data ( )
. get ::< IndicatorShader > ( )
. expect ( " Custom Shaders not initialized " )
. 0
. clone ( )
}
pub fn element < R : AsGlowRenderer > (
renderer : & R ,
geo : Rectangle < i32 , Logical > ,
) -> PixelShaderElement {
let thickness = FOCUS_INDICATOR_THICKNESS ;
let thickness_loc = ( thickness as i32 , thickness as i32 ) ;
let thickness_size = ( ( thickness * 2.0 ) as i32 , ( thickness * 2.0 ) as i32 ) ;
let geo = Rectangle ::from_loc_and_size (
geo . loc - Point ::from ( thickness_loc ) ,
geo . size + Size ::from ( thickness_size ) ,
) ;
let user_data = Borrow ::< Gles2Renderer > ::borrow ( renderer . glow_renderer ( ) )
. egl_context ( )
. user_data ( ) ;
match user_data . get ::< IndicatorElement > ( ) {
Some ( elem ) = > {
let mut elem = elem . 0. borrow_mut ( ) ;
if elem . geometry ( 1. 0. into ( ) ) . to_logical ( 1 ) ! = geo {
elem . resize ( geo , None ) ;
}
elem . clone ( )
}
None = > {
let shader = Self ::get ( renderer ) ;
let color = FOCUS_INDICATOR_COLOR ;
let elem = PixelShaderElement ::new (
shader ,
dbg! ( geo ) ,
None , //TODO
color [ 3 ] ,
vec! [
Uniform ::new ( " color " , [ color [ 0 ] , color [ 1 ] , color [ 2 ] ] ) ,
Uniform ::new ( " thickness " , thickness ) ,
Uniform ::new ( " radius " , FOCUS_INDICATOR_RADIUS ) ,
] ,
) ;
if ! user_data . insert_if_missing ( | | IndicatorElement ( RefCell ::new ( elem . clone ( ) ) ) ) {
* user_data . get ::< IndicatorElement > ( ) . unwrap ( ) . 0. borrow_mut ( ) = elem . clone ( ) ;
}
elem
}
}
}
}
pub fn init_shaders < R : AsGlowRenderer > ( renderer : & mut R ) -> Result < ( ) , Gles2Error > {
let glow_renderer = renderer . glow_renderer_mut ( ) ;
let gles_renderer : & mut Gles2Renderer = glow_renderer . borrow_mut ( ) ;
let indicator_shader = gles_renderer . compile_custom_pixel_shader (
FOCUS_INDICATOR_SHADER ,
& [
UniformName ::new ( " color " , UniformType ::_3f ) ,
UniformName ::new ( " thickness " , UniformType ::_1f ) ,
UniformName ::new ( " radius " , UniformType ::_1f ) ,
] ,
) ? ;
let egl_context = gles_renderer . egl_context ( ) ;
egl_context
. user_data ( )
. insert_if_missing ( | | IndicatorShader ( indicator_shader ) ) ;
Ok ( ( ) )
}
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
{
2023-03-06 18:50:11 +01:00
#[ cfg(feature = " debug " ) ]
puffin ::profile_function! ( ) ;
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
{
2023-03-06 18:50:11 +01:00
#[ cfg(feature = " debug " ) ]
puffin ::profile_function! ( ) ;
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-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
}
2023-03-06 18:48:52 +01:00
if state . shell . outputs . first ( ) = = Some ( output ) {
if let Some ( profiler_overlay ) = profiler_ui (
state ,
renderer . glow_renderer_mut ( ) ,
Rectangle ::from_loc_and_size ( ( 0 , 0 ) , output_geo . size ) ,
scale ,
)
. map_err ( < R as Renderer > ::Error ::from )
. map_err ( RenderError ::Rendering ) ?
{
elements . push ( profiler_overlay . into ( ) ) ;
}
}
2022-02-04 21:04:17 +01:00
}
2023-03-06 18:48:52 +01:00
let workspace = state . shell . space_for_handle ( & handle ) . ok_or ( OutputNoMode ) ? ;
2023-02-25 00:17:54 +01:00
let last_active_seat = state . last_active_seat ( ) . clone ( ) ;
let move_active = last_active_seat
. user_data ( )
. get ::< SeatMoveGrabState > ( )
. unwrap ( )
. borrow ( )
. is_some ( ) ;
2023-03-06 18:52:55 +01:00
let active_output = & last_active_seat . active_output ( ) = = output ;
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-03-06 18:52:55 +01:00
( ! move_active & & active_output ) . then_some ( & last_active_seat ) ,
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
}
2023-03-06 18:50:11 +01:00
puffin ::GlobalProfiler ::lock ( ) . new_frame ( ) ;
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
}