render: support shm screencopy from direct scanout
This commit is contained in:
parent
9de63bddf3
commit
9fba5f9b45
13 changed files with 203 additions and 62 deletions
|
|
@ -597,7 +597,6 @@ impl MetalConnector {
|
||||||
output.has_fullscreen(),
|
output.has_fullscreen(),
|
||||||
);
|
);
|
||||||
let try_direct_scanout = try_direct_scanout
|
let try_direct_scanout = try_direct_scanout
|
||||||
&& !output.global.have_shm_screencopies()
|
|
||||||
&& self.direct_scanout_enabled()
|
&& self.direct_scanout_enabled()
|
||||||
// at least on AMD, using a FB on a different device for rendering will fail
|
// at least on AMD, using a FB on a different device for rendering will fail
|
||||||
// and destroy the render context. it's possible to work around this by waiting
|
// and destroy the render context. it's possible to work around this by waiting
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
gfx_apis::gl::sys::{GLint, GL_BGRA_EXT, GL_RGBA, GL_UNSIGNED_BYTE},
|
gfx_apis::gl::sys::{GLenum, GLint, GL_BGRA_EXT, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE},
|
||||||
pipewire::pw_pod::{
|
pipewire::pw_pod::{
|
||||||
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SpaVideoFormat, SPA_VIDEO_FORMAT_BGRA,
|
SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SpaVideoFormat, SPA_VIDEO_FORMAT_BGRA,
|
||||||
SPA_VIDEO_FORMAT_RGBA,
|
SPA_VIDEO_FORMAT_RGBA,
|
||||||
|
|
@ -18,6 +18,7 @@ pub struct Format {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub bpp: u32,
|
pub bpp: u32,
|
||||||
pub gl_format: GLint,
|
pub gl_format: GLint,
|
||||||
|
pub gl_internal_format: GLenum,
|
||||||
pub gl_type: GLint,
|
pub gl_type: GLint,
|
||||||
pub vk_format: vk::Format,
|
pub vk_format: vk::Format,
|
||||||
pub drm: u32,
|
pub drm: u32,
|
||||||
|
|
@ -92,6 +93,7 @@ pub static ARGB8888: &Format = &Format {
|
||||||
name: "argb8888",
|
name: "argb8888",
|
||||||
bpp: 4,
|
bpp: 4,
|
||||||
gl_format: GL_BGRA_EXT,
|
gl_format: GL_BGRA_EXT,
|
||||||
|
gl_internal_format: GL_RGBA8,
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||||
drm: ARGB8888_DRM,
|
drm: ARGB8888_DRM,
|
||||||
|
|
@ -107,6 +109,7 @@ pub static XRGB8888: &Format = &Format {
|
||||||
name: "xrgb8888",
|
name: "xrgb8888",
|
||||||
bpp: 4,
|
bpp: 4,
|
||||||
gl_format: GL_BGRA_EXT,
|
gl_format: GL_BGRA_EXT,
|
||||||
|
gl_internal_format: GL_RGBA8,
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||||
drm: XRGB8888_DRM,
|
drm: XRGB8888_DRM,
|
||||||
|
|
@ -122,6 +125,7 @@ static ABGR8888: &Format = &Format {
|
||||||
name: "abgr8888",
|
name: "abgr8888",
|
||||||
bpp: 4,
|
bpp: 4,
|
||||||
gl_format: GL_RGBA,
|
gl_format: GL_RGBA,
|
||||||
|
gl_internal_format: GL_RGBA8,
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||||
drm: fourcc_code('A', 'B', '2', '4'),
|
drm: fourcc_code('A', 'B', '2', '4'),
|
||||||
|
|
@ -137,6 +141,7 @@ static XBGR8888: &Format = &Format {
|
||||||
name: "xbgr8888",
|
name: "xbgr8888",
|
||||||
bpp: 4,
|
bpp: 4,
|
||||||
gl_format: GL_RGBA,
|
gl_format: GL_RGBA,
|
||||||
|
gl_internal_format: GL_RGBA8,
|
||||||
gl_type: GL_UNSIGNED_BYTE,
|
gl_type: GL_UNSIGNED_BYTE,
|
||||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||||
drm: fourcc_code('X', 'B', '2', '4'),
|
drm: fourcc_code('X', 'B', '2', '4'),
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,14 @@ pub trait GfxContext: Debug {
|
||||||
fn gbm(&self) -> &GbmDevice;
|
fn gbm(&self) -> &GbmDevice;
|
||||||
|
|
||||||
fn gfx_api(&self) -> GfxApi;
|
fn gfx_api(&self) -> GfxApi;
|
||||||
|
|
||||||
|
fn create_fb(
|
||||||
|
self: Rc<Self>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<Rc<dyn GfxFramebuffer>, GfxError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,53 @@
|
||||||
use {
|
use {
|
||||||
crate::gfx_apis::gl::{
|
crate::{
|
||||||
egl::{context::EglContext, image::EglImage},
|
format::Format,
|
||||||
gl::{
|
gfx_apis::gl::{
|
||||||
frame_buffer::GlFrameBuffer,
|
egl::{context::EglContext, image::EglImage},
|
||||||
sys::{
|
gl::{
|
||||||
GLeglImageOES, GLuint, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
|
frame_buffer::GlFrameBuffer,
|
||||||
GL_FRAMEBUFFER_COMPLETE, GL_RENDERBUFFER,
|
sys::{
|
||||||
|
GLeglImageOES, GLuint, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
|
||||||
|
GL_FRAMEBUFFER_COMPLETE, GL_RENDERBUFFER,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
RenderError,
|
||||||
},
|
},
|
||||||
RenderError,
|
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GlRenderBuffer {
|
pub struct GlRenderBuffer {
|
||||||
pub img: Rc<EglImage>,
|
pub _img: Option<Rc<EglImage>>,
|
||||||
pub ctx: Rc<EglContext>,
|
pub ctx: Rc<EglContext>,
|
||||||
|
pub width: i32,
|
||||||
|
pub height: i32,
|
||||||
|
pub format: &'static Format,
|
||||||
rbo: GLuint,
|
rbo: GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlRenderBuffer {
|
impl GlRenderBuffer {
|
||||||
|
pub(in crate::gfx_apis::gl) unsafe fn new(
|
||||||
|
ctx: &Rc<EglContext>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
||||||
|
let gles = &ctx.dpy.gles;
|
||||||
|
let mut rbo = 0;
|
||||||
|
(gles.glGenRenderbuffers)(1, &mut rbo);
|
||||||
|
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, rbo);
|
||||||
|
(gles.glRenderbufferStorage)(GL_RENDERBUFFER, format.gl_internal_format, width, height);
|
||||||
|
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, 0);
|
||||||
|
Ok(Rc::new(GlRenderBuffer {
|
||||||
|
_img: None,
|
||||||
|
ctx: ctx.clone(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
format,
|
||||||
|
rbo,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
pub(in crate::gfx_apis::gl) unsafe fn from_image(
|
pub(in crate::gfx_apis::gl) unsafe fn from_image(
|
||||||
img: &Rc<EglImage>,
|
img: &Rc<EglImage>,
|
||||||
ctx: &Rc<EglContext>,
|
ctx: &Rc<EglContext>,
|
||||||
|
|
@ -36,8 +64,11 @@ impl GlRenderBuffer {
|
||||||
.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
|
.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, GLeglImageOES(img.img.0));
|
||||||
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, 0);
|
(gles.glBindRenderbuffer)(GL_RENDERBUFFER, 0);
|
||||||
Ok(Rc::new(GlRenderBuffer {
|
Ok(Rc::new(GlRenderBuffer {
|
||||||
img: img.clone(),
|
_img: Some(img.clone()),
|
||||||
ctx: ctx.clone(),
|
ctx: ctx.clone(),
|
||||||
|
width: img.dmabuf.width,
|
||||||
|
height: img.dmabuf.height,
|
||||||
|
format: img.dmabuf.format,
|
||||||
rbo,
|
rbo,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -62,8 +93,8 @@ impl GlRenderBuffer {
|
||||||
_tex: None,
|
_tex: None,
|
||||||
ctx: self.ctx.clone(),
|
ctx: self.ctx.clone(),
|
||||||
fbo,
|
fbo,
|
||||||
width: self.img.dmabuf.width,
|
width: self.width,
|
||||||
height: self.img.dmabuf.height,
|
height: self.height,
|
||||||
};
|
};
|
||||||
if status != GL_FRAMEBUFFER_COMPLETE {
|
if status != GL_FRAMEBUFFER_COMPLETE {
|
||||||
return Err(RenderError::CreateFramebuffer);
|
return Err(RenderError::CreateFramebuffer);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ pub type GLuint = c::c_uint;
|
||||||
egl_transparent!(GLeglImageOES);
|
egl_transparent!(GLeglImageOES);
|
||||||
|
|
||||||
pub const GL_RGBA: GLint = 0x1908;
|
pub const GL_RGBA: GLint = 0x1908;
|
||||||
|
pub const GL_RGBA8: GLenum = 0x8058;
|
||||||
pub const GL_BGRA_EXT: GLint = 0x80E1;
|
pub const GL_BGRA_EXT: GLint = 0x80E1;
|
||||||
pub const GL_CLAMP_TO_EDGE: GLint = 0x812F;
|
pub const GL_CLAMP_TO_EDGE: GLint = 0x812F;
|
||||||
pub const GL_COLOR_ATTACHMENT0: GLenum = 0x8CE0;
|
pub const GL_COLOR_ATTACHMENT0: GLenum = 0x8CE0;
|
||||||
|
|
@ -49,6 +50,7 @@ dynload! {
|
||||||
GLESV2: GlesV2 from "libGLESv2.so" {
|
GLESV2: GlesV2 from "libGLESv2.so" {
|
||||||
glGetString: unsafe fn(name: GLenum) -> *const u8,
|
glGetString: unsafe fn(name: GLenum) -> *const u8,
|
||||||
glGenRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *mut GLuint),
|
glGenRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *mut GLuint),
|
||||||
|
glRenderbufferStorage: unsafe fn(target: GLenum, format: GLenum, width: GLsizei, height: GLsizei),
|
||||||
glDeleteRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *const GLuint),
|
glDeleteRenderbuffers: unsafe fn(n: GLsizei, renderbuffers: *const GLuint),
|
||||||
glBindRenderbuffer: unsafe fn(target: GLenum, renderbuffer: GLuint),
|
glBindRenderbuffer: unsafe fn(target: GLenum, renderbuffer: GLuint),
|
||||||
glGenFramebuffers: unsafe fn(n: GLsizei, framebuffers: *mut GLuint),
|
glGenFramebuffers: unsafe fn(n: GLsizei, framebuffers: *mut GLuint),
|
||||||
|
|
|
||||||
|
|
@ -255,4 +255,17 @@ impl GfxContext for GlRenderContext {
|
||||||
fn gfx_api(&self) -> GfxApi {
|
fn gfx_api(&self) -> GfxApi {
|
||||||
GfxApi::OpenGl
|
GfxApi::OpenGl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_fb(
|
||||||
|
self: Rc<Self>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
_stride: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||||
|
let fb = self.ctx.with_current(|| unsafe {
|
||||||
|
GlRenderBuffer::new(&self.ctx, width, height, format)?.create_framebuffer()
|
||||||
|
})?;
|
||||||
|
Ok(Rc::new(Framebuffer { ctx: self, gl: fb }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,6 @@ impl GfxFramebuffer for Framebuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(&self) -> &'static Format {
|
fn format(&self) -> &'static Format {
|
||||||
self.gl.rb.img.dmabuf.format
|
self.gl.rb.format
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{GfxContext, GfxError, GfxFormat, GfxImage, GfxTexture, ResetStatus},
|
gfx_api::{
|
||||||
|
GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage, GfxTexture, ResetStatus,
|
||||||
|
},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
image::VulkanImageMemory, instance::VulkanInstance, renderer::VulkanRenderer,
|
image::VulkanImageMemory, instance::VulkanInstance, renderer::VulkanRenderer,
|
||||||
},
|
},
|
||||||
|
|
@ -255,6 +257,19 @@ impl GfxContext for Context {
|
||||||
fn gfx_api(&self) -> GfxApi {
|
fn gfx_api(&self) -> GfxApi {
|
||||||
GfxApi::Vulkan
|
GfxApi::Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_fb(
|
||||||
|
self: Rc<Self>,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||||
|
let fb = self
|
||||||
|
.0
|
||||||
|
.create_shm_texture(format, width, height, stride, &[], true)?;
|
||||||
|
Ok(fb)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Context {
|
impl Drop for Context {
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,6 @@ impl JayScreencast {
|
||||||
self.client.state.perform_screencopy(
|
self.client.state.perform_screencopy(
|
||||||
texture,
|
texture,
|
||||||
&buffer.fb,
|
&buffer.fb,
|
||||||
on.global.preferred_scale.get(),
|
|
||||||
on.global.pos.get(),
|
on.global.pos.get(),
|
||||||
render_hardware_cursors,
|
render_hardware_cursors,
|
||||||
x_off,
|
x_off,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ use {
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
|
||||||
linkedlist::LinkedList,
|
linkedlist::LinkedList,
|
||||||
},
|
},
|
||||||
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
|
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
|
||||||
|
|
@ -201,10 +200,6 @@ impl WlOutputGlobal {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn have_shm_screencopies(&self) -> bool {
|
|
||||||
self.pending_captures.iter().any(|c| c.is_shm.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn perform_screencopies(
|
pub fn perform_screencopies(
|
||||||
&self,
|
&self,
|
||||||
tex: &Rc<dyn GfxTexture>,
|
tex: &Rc<dyn GfxTexture>,
|
||||||
|
|
@ -235,30 +230,17 @@ impl WlOutputGlobal {
|
||||||
if let Some(WlBufferStorage::Shm { mem, stride }) =
|
if let Some(WlBufferStorage::Shm { mem, stride }) =
|
||||||
wl_buffer.storage.borrow_mut().deref()
|
wl_buffer.storage.borrow_mut().deref()
|
||||||
{
|
{
|
||||||
let acc = mem.access(|mem| {
|
self.state.perform_shm_screencopy(
|
||||||
tex.clone().read_pixels(
|
tex,
|
||||||
capture.rect.x1(),
|
self.pos.get(),
|
||||||
capture.rect.y1(),
|
x_off,
|
||||||
capture.rect.width(),
|
y_off,
|
||||||
capture.rect.height(),
|
size,
|
||||||
*stride,
|
&capture,
|
||||||
wl_buffer.format,
|
mem,
|
||||||
mem,
|
*stride,
|
||||||
)
|
wl_buffer.format,
|
||||||
});
|
);
|
||||||
let res = match acc {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(e) => {
|
|
||||||
capture.client.error(e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Err(e) = res {
|
|
||||||
log::warn!("Could not read texture to memory: {}", ErrorFmt(e));
|
|
||||||
capture.send_failed();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// capture.send_flags(FLAGS_Y_INVERT);
|
|
||||||
} else {
|
} else {
|
||||||
let fb = match wl_buffer.famebuffer.get() {
|
let fb = match wl_buffer.famebuffer.get() {
|
||||||
Some(fb) => fb,
|
Some(fb) => fb,
|
||||||
|
|
@ -271,7 +253,6 @@ impl WlOutputGlobal {
|
||||||
self.state.perform_screencopy(
|
self.state.perform_screencopy(
|
||||||
tex,
|
tex,
|
||||||
&fb,
|
&fb,
|
||||||
self.preferred_scale.get(),
|
|
||||||
self.pos.get(),
|
self.pos.get(),
|
||||||
render_hardware_cursors,
|
render_hardware_cursors,
|
||||||
x_off - capture.rect.x1(),
|
x_off - capture.rect.x1(),
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ pub struct ZwlrScreencopyFrameV1 {
|
||||||
pub with_damage: Cell<bool>,
|
pub with_damage: Cell<bool>,
|
||||||
pub output_link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
pub output_link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
||||||
pub buffer: Cell<Option<Rc<WlBuffer>>>,
|
pub buffer: Cell<Option<Rc<WlBuffer>>>,
|
||||||
pub is_shm: Cell<bool>,
|
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,14 +120,6 @@ impl ZwlrScreencopyFrameV1 {
|
||||||
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
|
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let is_shm = match &*buffer.storage.borrow() {
|
|
||||||
None => false,
|
|
||||||
Some(s) => match s {
|
|
||||||
WlBufferStorage::Shm { .. } => true,
|
|
||||||
WlBufferStorage::Dmabuf(_) => false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
self.is_shm.set(is_shm);
|
|
||||||
self.buffer.set(Some(buffer));
|
self.buffer.set(Some(buffer));
|
||||||
if !with_damage {
|
if !with_damage {
|
||||||
self.output.connector.connector.damage();
|
self.output.connector.connector.damage();
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,6 @@ impl ZwlrScreencopyManagerV1 {
|
||||||
with_damage: Cell::new(false),
|
with_damage: Cell::new(false),
|
||||||
output_link: Cell::new(None),
|
output_link: Cell::new(None),
|
||||||
buffer: Cell::new(None),
|
buffer: Cell::new(None),
|
||||||
is_shm: Cell::new(false),
|
|
||||||
version: self.version,
|
version: self.version,
|
||||||
});
|
});
|
||||||
track!(self.client, frame);
|
track!(self.client, frame);
|
||||||
|
|
|
||||||
108
src/state.rs
108
src/state.rs
|
|
@ -9,12 +9,14 @@ use {
|
||||||
backends::dummy::DummyBackend,
|
backends::dummy::DummyBackend,
|
||||||
cli::RunArgs,
|
cli::RunArgs,
|
||||||
client::{Client, ClientId, Clients, SerialRange, NUM_CACHED_SERIAL_RANGES},
|
client::{Client, ClientId, Clients, SerialRange, NUM_CACHED_SERIAL_RANGES},
|
||||||
|
clientmem::ClientMemOffset,
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
cursor::{Cursor, ServerCursors},
|
cursor::{Cursor, ServerCursors},
|
||||||
dbus::Dbus,
|
dbus::Dbus,
|
||||||
drm_feedback::{DrmFeedback, DrmFeedbackIds},
|
drm_feedback::{DrmFeedback, DrmFeedbackIds},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
|
format::Format,
|
||||||
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
||||||
gfx_apis::create_gfx_context,
|
gfx_apis::create_gfx_context,
|
||||||
globals::{Globals, GlobalsError, WaylandGlobal},
|
globals::{Globals, GlobalsError, WaylandGlobal},
|
||||||
|
|
@ -30,6 +32,7 @@ use {
|
||||||
zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1},
|
zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1},
|
||||||
NoneSurfaceExt, WlSurface,
|
NoneSurfaceExt, WlSurface,
|
||||||
},
|
},
|
||||||
|
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
||||||
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
|
||||||
},
|
},
|
||||||
|
|
@ -759,7 +762,6 @@ impl State {
|
||||||
&self,
|
&self,
|
||||||
src: &Rc<dyn GfxTexture>,
|
src: &Rc<dyn GfxTexture>,
|
||||||
target: &Rc<dyn GfxFramebuffer>,
|
target: &Rc<dyn GfxFramebuffer>,
|
||||||
scale: Scale,
|
|
||||||
position: Rect,
|
position: Rect,
|
||||||
render_hardware_cursors: bool,
|
render_hardware_cursors: bool,
|
||||||
x_off: i32,
|
x_off: i32,
|
||||||
|
|
@ -771,9 +773,9 @@ impl State {
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: RendererBase {
|
base: RendererBase {
|
||||||
ops: &mut ops,
|
ops: &mut ops,
|
||||||
scaled: scale != 1,
|
scaled: false,
|
||||||
scale,
|
scale: Scale::from_int(1),
|
||||||
scalef: scale.to_f64(),
|
scalef: 1.0,
|
||||||
},
|
},
|
||||||
state: self,
|
state: self,
|
||||||
result: None,
|
result: None,
|
||||||
|
|
@ -782,7 +784,7 @@ impl State {
|
||||||
};
|
};
|
||||||
renderer
|
renderer
|
||||||
.base
|
.base
|
||||||
.render_texture(src, x_off, y_off, None, size, scale, None);
|
.render_texture(src, x_off, y_off, None, size, Scale::from_int(1), None);
|
||||||
if render_hardware_cursors {
|
if render_hardware_cursors {
|
||||||
for seat in self.globals.lock_seats().values() {
|
for seat in self.globals.lock_seats().values() {
|
||||||
if let Some(cursor) = seat.get_cursor() {
|
if let Some(cursor) = seat.get_cursor() {
|
||||||
|
|
@ -797,4 +799,100 @@ impl State {
|
||||||
}
|
}
|
||||||
target.render(ops, Some(&Color::SOLID_BLACK));
|
target.render(ops, Some(&Color::SOLID_BLACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn have_hardware_cursor(&self) -> bool {
|
||||||
|
for seat in self.globals.lock_seats().values() {
|
||||||
|
if seat.get_cursor().is_some() {
|
||||||
|
if seat.hardware_cursor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform_shm_screencopy(
|
||||||
|
&self,
|
||||||
|
src: &Rc<dyn GfxTexture>,
|
||||||
|
position: Rect,
|
||||||
|
x_off: i32,
|
||||||
|
y_off: i32,
|
||||||
|
size: Option<(i32, i32)>,
|
||||||
|
capture: &ZwlrScreencopyFrameV1,
|
||||||
|
mem: &ClientMemOffset,
|
||||||
|
stride: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
) {
|
||||||
|
let (src_width, src_height) = src.size();
|
||||||
|
let mut needs_copy = capture.rect.x1() < x_off
|
||||||
|
|| capture.rect.x2() > x_off + src_width
|
||||||
|
|| capture.rect.y1() < y_off
|
||||||
|
|| capture.rect.y2() > y_off + src_height
|
||||||
|
|| self.have_hardware_cursor();
|
||||||
|
if let Some((target_width, target_height)) = size {
|
||||||
|
if (target_width, target_height) != (src_width, src_height) {
|
||||||
|
needs_copy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let acc = if needs_copy {
|
||||||
|
let Some(ctx) = self.render_ctx.get() else {
|
||||||
|
log::warn!("Cannot perform shm screencopy because there is no render context");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let fb =
|
||||||
|
match ctx.create_fb(capture.rect.width(), capture.rect.height(), stride, format) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!(
|
||||||
|
"Could not create temporary fb for screencopy: {}",
|
||||||
|
ErrorFmt(e)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.perform_screencopy(
|
||||||
|
src,
|
||||||
|
&fb,
|
||||||
|
position,
|
||||||
|
true,
|
||||||
|
x_off - capture.rect.x1(),
|
||||||
|
y_off - capture.rect.y1(),
|
||||||
|
size,
|
||||||
|
);
|
||||||
|
mem.access(|mem| {
|
||||||
|
fb.copy_to_shm(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
capture.rect.width(),
|
||||||
|
capture.rect.height(),
|
||||||
|
stride,
|
||||||
|
format,
|
||||||
|
mem,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
mem.access(|mem| {
|
||||||
|
src.clone().read_pixels(
|
||||||
|
capture.rect.x1() - x_off,
|
||||||
|
capture.rect.y1() - y_off,
|
||||||
|
capture.rect.width(),
|
||||||
|
capture.rect.height(),
|
||||||
|
stride,
|
||||||
|
format,
|
||||||
|
mem,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let res = match acc {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(e) => {
|
||||||
|
capture.client.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(e) = res {
|
||||||
|
log::warn!("Could not read texture to memory: {}", ErrorFmt(e));
|
||||||
|
capture.send_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue