state: split rendering helpers
This commit is contained in:
parent
19c2265400
commit
27750a31c4
2 changed files with 217 additions and 203 deletions
208
src/state.rs
208
src/state.rs
|
|
@ -1,5 +1,6 @@
|
||||||
mod animations;
|
mod animations;
|
||||||
mod connectors;
|
mod connectors;
|
||||||
|
mod rendering;
|
||||||
|
|
||||||
pub(crate) use animations::LayoutAnimationCandidate;
|
pub(crate) use animations::LayoutAnimationCandidate;
|
||||||
pub use connectors::{ConnectorData, DrmDevData, OutputData};
|
pub use connectors::{ConnectorData, DrmDevData, OutputData};
|
||||||
|
|
@ -19,11 +20,7 @@ use {
|
||||||
backends::dummy::DummyBackend,
|
backends::dummy::DummyBackend,
|
||||||
cli::RunArgs,
|
cli::RunArgs,
|
||||||
client::{Client, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
client::{Client, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
||||||
clientmem::ClientMemOffset,
|
cmm::cmm_manager::ColorManager,
|
||||||
cmm::{
|
|
||||||
cmm_description::ColorDescription, cmm_manager::ColorManager,
|
|
||||||
cmm_render_intent::RenderIntent,
|
|
||||||
},
|
|
||||||
compositor::LIBEI_SOCKET,
|
compositor::LIBEI_SOCKET,
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
copy_device::CopyDeviceRegistry,
|
copy_device::CopyDeviceRegistry,
|
||||||
|
|
@ -39,14 +36,8 @@ use {
|
||||||
ei_client::{EiClient, EiClients},
|
ei_client::{EiClient, EiClients},
|
||||||
},
|
},
|
||||||
eventfd_cache::EventfdCache,
|
eventfd_cache::EventfdCache,
|
||||||
fixed::Fixed,
|
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
format::Format,
|
gfx_api::{GfxApi, GfxContext, GfxError},
|
||||||
gfx_api::{
|
|
||||||
AcquireSync, AlphaMode, BufferResv, FdSync, GfxApi, GfxBlendBuffer, GfxContext,
|
|
||||||
GfxError, GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync,
|
|
||||||
STAGING_DOWNLOAD, SampleRect,
|
|
||||||
},
|
|
||||||
gfx_apis::create_gfx_context,
|
gfx_apis::create_gfx_context,
|
||||||
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
|
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
|
||||||
icons::Icons,
|
icons::Icons,
|
||||||
|
|
@ -83,7 +74,6 @@ use {
|
||||||
workspace_manager::WorkspaceManagerState,
|
workspace_manager::WorkspaceManagerState,
|
||||||
xdg_activation_token_v1::ActivationToken,
|
xdg_activation_token_v1::ActivationToken,
|
||||||
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
|
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
|
||||||
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
|
||||||
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
||||||
},
|
},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
|
|
@ -93,8 +83,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
pr_caps::PrCapsThread,
|
pr_caps::PrCapsThread,
|
||||||
rect::{Rect, Region},
|
rect::Rect,
|
||||||
renderer::Renderer,
|
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
theme::{BarPosition, Color, Theme, ThemeColor, ThemeSized},
|
theme::{BarPosition, Color, Theme, ThemeColor, ThemeSized},
|
||||||
time::Time,
|
time::Time,
|
||||||
|
|
@ -102,7 +91,7 @@ use {
|
||||||
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
|
||||||
FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode,
|
FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode,
|
||||||
PlaceholderNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
|
PlaceholderNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
|
||||||
ToplevelNode, ToplevelNodeBase, Transform, VrrMode, WorkspaceDisplayOrder,
|
ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceDisplayOrder,
|
||||||
WorkspaceNode, WorkspaceNodeId, WsMoveConfig, generic_node_visitor, move_ws_to_output,
|
WorkspaceNode, WorkspaceNodeId, WsMoveConfig, generic_node_visitor, move_ws_to_output,
|
||||||
},
|
},
|
||||||
udmabuf::UdmabufHolder,
|
udmabuf::UdmabufHolder,
|
||||||
|
|
@ -145,7 +134,6 @@ use {
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
|
||||||
uapi::{OwnedFd, c},
|
uapi::{OwnedFd, c},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1102,180 +1090,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn present_output(
|
|
||||||
&self,
|
|
||||||
output: &OutputNode,
|
|
||||||
fb: &Rc<dyn GfxFramebuffer>,
|
|
||||||
cd: &Rc<ColorDescription>,
|
|
||||||
acquire_sync: AcquireSync,
|
|
||||||
release_sync: ReleaseSync,
|
|
||||||
tex: &Rc<dyn GfxTexture>,
|
|
||||||
render_hw_cursor: bool,
|
|
||||||
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
|
||||||
blend_cd: &Rc<ColorDescription>,
|
|
||||||
) -> Result<Option<FdSync>, GfxError> {
|
|
||||||
let sync = fb.render_output(
|
|
||||||
acquire_sync,
|
|
||||||
release_sync,
|
|
||||||
cd,
|
|
||||||
output,
|
|
||||||
self,
|
|
||||||
Some(output.global.pos.get()),
|
|
||||||
output.global.persistent.scale.get(),
|
|
||||||
render_hw_cursor,
|
|
||||||
true,
|
|
||||||
blend_buffer,
|
|
||||||
blend_cd,
|
|
||||||
)?;
|
|
||||||
output.latched(false);
|
|
||||||
output.perform_screencopies(
|
|
||||||
tex,
|
|
||||||
cd,
|
|
||||||
None,
|
|
||||||
&AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::None,
|
|
||||||
!render_hw_cursor,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
Ok(sync)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn perform_screencopy(
|
|
||||||
&self,
|
|
||||||
src: &Rc<dyn GfxTexture>,
|
|
||||||
resv: Option<&Rc<dyn BufferResv>>,
|
|
||||||
acquire_sync: &AcquireSync,
|
|
||||||
release_sync: ReleaseSync,
|
|
||||||
src_cd: &Rc<ColorDescription>,
|
|
||||||
target: &Rc<dyn GfxFramebuffer>,
|
|
||||||
target_acquire_sync: AcquireSync,
|
|
||||||
target_release_sync: ReleaseSync,
|
|
||||||
target_transform: Transform,
|
|
||||||
target_cd: &Rc<ColorDescription>,
|
|
||||||
position: Rect,
|
|
||||||
render_hardware_cursors: bool,
|
|
||||||
x_off: i32,
|
|
||||||
y_off: i32,
|
|
||||||
size: Option<(i32, i32)>,
|
|
||||||
transform: Transform,
|
|
||||||
scale: Scale,
|
|
||||||
) -> Result<Option<FdSync>, GfxError> {
|
|
||||||
let mut ops = vec![];
|
|
||||||
let mut renderer = Renderer {
|
|
||||||
base: target.renderer_base(&mut ops, scale, target_transform),
|
|
||||||
state: self,
|
|
||||||
logical_extents: position.at_point(0, 0),
|
|
||||||
pixel_extents: {
|
|
||||||
let (width, height) = target.logical_size(target_transform);
|
|
||||||
Rect::new_sized_saturating(0, 0, width, height)
|
|
||||||
},
|
|
||||||
stretch: None,
|
|
||||||
corner_radius: None,
|
|
||||||
};
|
|
||||||
let mut sample_rect = SampleRect::identity();
|
|
||||||
sample_rect.buffer_transform = transform;
|
|
||||||
renderer.base.render_texture(
|
|
||||||
src,
|
|
||||||
None,
|
|
||||||
x_off,
|
|
||||||
y_off,
|
|
||||||
Some(sample_rect),
|
|
||||||
size,
|
|
||||||
scale,
|
|
||||||
None,
|
|
||||||
resv.cloned(),
|
|
||||||
acquire_sync.clone(),
|
|
||||||
release_sync,
|
|
||||||
false,
|
|
||||||
src_cd,
|
|
||||||
RenderIntent::Perceptual,
|
|
||||||
AlphaMode::PremultipliedElectrical,
|
|
||||||
);
|
|
||||||
if render_hardware_cursors
|
|
||||||
&& let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get()
|
|
||||||
&& let Some(cursor_user) = cursor_user_group.active()
|
|
||||||
&& let Some(cursor) = cursor_user.get()
|
|
||||||
{
|
|
||||||
let (mut x, mut y) = cursor_user.position();
|
|
||||||
x = x + x_off - Fixed::from_int(position.x1());
|
|
||||||
y = y + y_off - Fixed::from_int(position.y1());
|
|
||||||
cursor.render(&mut renderer, x, y);
|
|
||||||
}
|
|
||||||
target.render(
|
|
||||||
target_acquire_sync,
|
|
||||||
target_release_sync,
|
|
||||||
target_cd,
|
|
||||||
&ops,
|
|
||||||
Some(&Color::SOLID_BLACK),
|
|
||||||
&target_cd.linear,
|
|
||||||
None,
|
|
||||||
target_cd,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn perform_shm_screencopy(
|
|
||||||
&self,
|
|
||||||
src: &Rc<dyn GfxTexture>,
|
|
||||||
src_cd: &Rc<ColorDescription>,
|
|
||||||
acquire_sync: &AcquireSync,
|
|
||||||
position: Rect,
|
|
||||||
x_off: i32,
|
|
||||||
y_off: i32,
|
|
||||||
size: Option<(i32, i32)>,
|
|
||||||
capture: &Rc<ZwlrScreencopyFrameV1>,
|
|
||||||
mem: &Rc<ClientMemOffset>,
|
|
||||||
stride: i32,
|
|
||||||
format: &'static Format,
|
|
||||||
transform: Transform,
|
|
||||||
scale: Scale,
|
|
||||||
) -> Result<Option<PendingShmTransfer>, ShmScreencopyError> {
|
|
||||||
let Some(ctx) = self.render_ctx.get() else {
|
|
||||||
return Err(ShmScreencopyError::NoRenderContext);
|
|
||||||
};
|
|
||||||
let fb = ctx
|
|
||||||
.clone()
|
|
||||||
.create_internal_fb(
|
|
||||||
&self.cpu_worker,
|
|
||||||
capture.rect.width(),
|
|
||||||
capture.rect.height(),
|
|
||||||
stride,
|
|
||||||
format,
|
|
||||||
)
|
|
||||||
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
|
|
||||||
self.perform_screencopy(
|
|
||||||
src,
|
|
||||||
None,
|
|
||||||
acquire_sync,
|
|
||||||
ReleaseSync::None,
|
|
||||||
src_cd,
|
|
||||||
&(fb.clone() as Rc<dyn GfxFramebuffer>),
|
|
||||||
AcquireSync::Unnecessary,
|
|
||||||
ReleaseSync::None,
|
|
||||||
transform,
|
|
||||||
self.color_manager.srgb_gamma22(),
|
|
||||||
position,
|
|
||||||
true,
|
|
||||||
x_off - capture.rect.x1(),
|
|
||||||
y_off - capture.rect.y1(),
|
|
||||||
size,
|
|
||||||
transform,
|
|
||||||
scale,
|
|
||||||
)
|
|
||||||
.map_err(ShmScreencopyError::CopyToTemporary)?;
|
|
||||||
let staging = ctx.create_staging_buffer(fb.staging_size(), STAGING_DOWNLOAD);
|
|
||||||
let pending = fb
|
|
||||||
.download(
|
|
||||||
&staging,
|
|
||||||
capture.clone(),
|
|
||||||
mem.clone(),
|
|
||||||
Region::new(capture.rect.at_point(0, 0)),
|
|
||||||
)
|
|
||||||
.map_err(ShmScreencopyError::ReadPixels)?;
|
|
||||||
Ok(pending)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_seat(self: &Rc<Self>, name: &str) -> Rc<WlSeatGlobal> {
|
pub fn create_seat(self: &Rc<Self>, name: &str) -> Rc<WlSeatGlobal> {
|
||||||
let global_name = self.globals.name();
|
let global_name = self.globals.name();
|
||||||
let seat = WlSeatGlobal::new(global_name, name, self);
|
let seat = WlSeatGlobal::new(global_name, name, self);
|
||||||
|
|
@ -1881,15 +1695,3 @@ impl State {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum ShmScreencopyError {
|
|
||||||
#[error("There is no render context")]
|
|
||||||
NoRenderContext,
|
|
||||||
#[error("Could not create a bridge framebuffer")]
|
|
||||||
CreateTemporaryFb(#[source] GfxError),
|
|
||||||
#[error("Could not copy texture to bridge framebuffer")]
|
|
||||||
CopyToTemporary(#[source] GfxError),
|
|
||||||
#[error("Could not read pixels from texture")]
|
|
||||||
ReadPixels(#[source] GfxError),
|
|
||||||
}
|
|
||||||
|
|
|
||||||
212
src/state/rendering.rs
Normal file
212
src/state/rendering.rs
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
clientmem::ClientMemOffset,
|
||||||
|
cmm::{cmm_description::ColorDescription, cmm_render_intent::RenderIntent},
|
||||||
|
fixed::Fixed,
|
||||||
|
format::Format,
|
||||||
|
gfx_api::{
|
||||||
|
AcquireSync, AlphaMode, BufferResv, FdSync, GfxBlendBuffer, GfxError,
|
||||||
|
GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync, STAGING_DOWNLOAD,
|
||||||
|
SampleRect,
|
||||||
|
},
|
||||||
|
ifs::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
|
rect::{Rect, Region},
|
||||||
|
renderer::Renderer,
|
||||||
|
scale::Scale,
|
||||||
|
theme::Color,
|
||||||
|
tree::{OutputNode, Transform},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::State;
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn present_output(
|
||||||
|
&self,
|
||||||
|
output: &OutputNode,
|
||||||
|
fb: &Rc<dyn GfxFramebuffer>,
|
||||||
|
cd: &Rc<ColorDescription>,
|
||||||
|
acquire_sync: AcquireSync,
|
||||||
|
release_sync: ReleaseSync,
|
||||||
|
tex: &Rc<dyn GfxTexture>,
|
||||||
|
render_hw_cursor: bool,
|
||||||
|
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
|
||||||
|
blend_cd: &Rc<ColorDescription>,
|
||||||
|
) -> Result<Option<FdSync>, GfxError> {
|
||||||
|
let sync = fb.render_output(
|
||||||
|
acquire_sync,
|
||||||
|
release_sync,
|
||||||
|
cd,
|
||||||
|
output,
|
||||||
|
self,
|
||||||
|
Some(output.global.pos.get()),
|
||||||
|
output.global.persistent.scale.get(),
|
||||||
|
render_hw_cursor,
|
||||||
|
true,
|
||||||
|
blend_buffer,
|
||||||
|
blend_cd,
|
||||||
|
)?;
|
||||||
|
output.latched(false);
|
||||||
|
output.perform_screencopies(
|
||||||
|
tex,
|
||||||
|
cd,
|
||||||
|
None,
|
||||||
|
&AcquireSync::Unnecessary,
|
||||||
|
ReleaseSync::None,
|
||||||
|
!render_hw_cursor,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
Ok(sync)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform_screencopy(
|
||||||
|
&self,
|
||||||
|
src: &Rc<dyn GfxTexture>,
|
||||||
|
resv: Option<&Rc<dyn BufferResv>>,
|
||||||
|
acquire_sync: &AcquireSync,
|
||||||
|
release_sync: ReleaseSync,
|
||||||
|
src_cd: &Rc<ColorDescription>,
|
||||||
|
target: &Rc<dyn GfxFramebuffer>,
|
||||||
|
target_acquire_sync: AcquireSync,
|
||||||
|
target_release_sync: ReleaseSync,
|
||||||
|
target_transform: Transform,
|
||||||
|
target_cd: &Rc<ColorDescription>,
|
||||||
|
position: Rect,
|
||||||
|
render_hardware_cursors: bool,
|
||||||
|
x_off: i32,
|
||||||
|
y_off: i32,
|
||||||
|
size: Option<(i32, i32)>,
|
||||||
|
transform: Transform,
|
||||||
|
scale: Scale,
|
||||||
|
) -> Result<Option<FdSync>, GfxError> {
|
||||||
|
let mut ops = vec![];
|
||||||
|
let mut renderer = Renderer {
|
||||||
|
base: target.renderer_base(&mut ops, scale, target_transform),
|
||||||
|
state: self,
|
||||||
|
logical_extents: position.at_point(0, 0),
|
||||||
|
pixel_extents: {
|
||||||
|
let (width, height) = target.logical_size(target_transform);
|
||||||
|
Rect::new_sized_saturating(0, 0, width, height)
|
||||||
|
},
|
||||||
|
stretch: None,
|
||||||
|
corner_radius: None,
|
||||||
|
};
|
||||||
|
let mut sample_rect = SampleRect::identity();
|
||||||
|
sample_rect.buffer_transform = transform;
|
||||||
|
renderer.base.render_texture(
|
||||||
|
src,
|
||||||
|
None,
|
||||||
|
x_off,
|
||||||
|
y_off,
|
||||||
|
Some(sample_rect),
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
None,
|
||||||
|
resv.cloned(),
|
||||||
|
acquire_sync.clone(),
|
||||||
|
release_sync,
|
||||||
|
false,
|
||||||
|
src_cd,
|
||||||
|
RenderIntent::Perceptual,
|
||||||
|
AlphaMode::PremultipliedElectrical,
|
||||||
|
);
|
||||||
|
if render_hardware_cursors
|
||||||
|
&& let Some(cursor_user_group) = self.cursor_user_group_hardware_cursor.get()
|
||||||
|
&& let Some(cursor_user) = cursor_user_group.active()
|
||||||
|
&& let Some(cursor) = cursor_user.get()
|
||||||
|
{
|
||||||
|
let (mut x, mut y) = cursor_user.position();
|
||||||
|
x = x + x_off - Fixed::from_int(position.x1());
|
||||||
|
y = y + y_off - Fixed::from_int(position.y1());
|
||||||
|
cursor.render(&mut renderer, x, y);
|
||||||
|
}
|
||||||
|
target.render(
|
||||||
|
target_acquire_sync,
|
||||||
|
target_release_sync,
|
||||||
|
target_cd,
|
||||||
|
&ops,
|
||||||
|
Some(&Color::SOLID_BLACK),
|
||||||
|
&target_cd.linear,
|
||||||
|
None,
|
||||||
|
target_cd,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform_shm_screencopy(
|
||||||
|
&self,
|
||||||
|
src: &Rc<dyn GfxTexture>,
|
||||||
|
src_cd: &Rc<ColorDescription>,
|
||||||
|
acquire_sync: &AcquireSync,
|
||||||
|
position: Rect,
|
||||||
|
x_off: i32,
|
||||||
|
y_off: i32,
|
||||||
|
size: Option<(i32, i32)>,
|
||||||
|
capture: &Rc<ZwlrScreencopyFrameV1>,
|
||||||
|
mem: &Rc<ClientMemOffset>,
|
||||||
|
stride: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
transform: Transform,
|
||||||
|
scale: Scale,
|
||||||
|
) -> Result<Option<PendingShmTransfer>, ShmScreencopyError> {
|
||||||
|
let Some(ctx) = self.render_ctx.get() else {
|
||||||
|
return Err(ShmScreencopyError::NoRenderContext);
|
||||||
|
};
|
||||||
|
let fb = ctx
|
||||||
|
.clone()
|
||||||
|
.create_internal_fb(
|
||||||
|
&self.cpu_worker,
|
||||||
|
capture.rect.width(),
|
||||||
|
capture.rect.height(),
|
||||||
|
stride,
|
||||||
|
format,
|
||||||
|
)
|
||||||
|
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
|
||||||
|
self.perform_screencopy(
|
||||||
|
src,
|
||||||
|
None,
|
||||||
|
acquire_sync,
|
||||||
|
ReleaseSync::None,
|
||||||
|
src_cd,
|
||||||
|
&(fb.clone() as Rc<dyn GfxFramebuffer>),
|
||||||
|
AcquireSync::Unnecessary,
|
||||||
|
ReleaseSync::None,
|
||||||
|
transform,
|
||||||
|
self.color_manager.srgb_gamma22(),
|
||||||
|
position,
|
||||||
|
true,
|
||||||
|
x_off - capture.rect.x1(),
|
||||||
|
y_off - capture.rect.y1(),
|
||||||
|
size,
|
||||||
|
transform,
|
||||||
|
scale,
|
||||||
|
)
|
||||||
|
.map_err(ShmScreencopyError::CopyToTemporary)?;
|
||||||
|
let staging = ctx.create_staging_buffer(fb.staging_size(), STAGING_DOWNLOAD);
|
||||||
|
let pending = fb
|
||||||
|
.download(
|
||||||
|
&staging,
|
||||||
|
capture.clone(),
|
||||||
|
mem.clone(),
|
||||||
|
Region::new(capture.rect.at_point(0, 0)),
|
||||||
|
)
|
||||||
|
.map_err(ShmScreencopyError::ReadPixels)?;
|
||||||
|
Ok(pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ShmScreencopyError {
|
||||||
|
#[error("There is no render context")]
|
||||||
|
NoRenderContext,
|
||||||
|
#[error("Could not create a bridge framebuffer")]
|
||||||
|
CreateTemporaryFb(#[source] GfxError),
|
||||||
|
#[error("Could not copy texture to bridge framebuffer")]
|
||||||
|
CopyToTemporary(#[source] GfxError),
|
||||||
|
#[error("Could not read pixels from texture")]
|
||||||
|
ReadPixels(#[source] GfxError),
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue