metal: support multi-gpu systems via copying
This commit is contained in:
parent
d43e7b345c
commit
28e91e0c5d
4 changed files with 167 additions and 80 deletions
|
|
@ -9,7 +9,7 @@ use {
|
||||||
edid::Descriptor,
|
edid::Descriptor,
|
||||||
format::{Format, ARGB8888, XRGB8888},
|
format::{Format, ARGB8888, XRGB8888},
|
||||||
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||||
render::{Framebuffer, RenderContext, RenderResult, ResetStatus, Texture},
|
render::{Framebuffer, RenderContext, RenderResult, Texture},
|
||||||
state::State,
|
state::State,
|
||||||
udev::UdevDevice,
|
udev::UdevDevice,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -48,8 +48,9 @@ pub struct PendingDrmDevice {
|
||||||
pub devnode: CString,
|
pub devnode: CString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct MetalRenderContext {
|
pub struct MetalRenderContext {
|
||||||
pub dev: Rc<MetalDrmDevice>,
|
pub dev_id: DrmDeviceId,
|
||||||
pub egl: Rc<RenderContext>,
|
pub egl: Rc<RenderContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,6 +72,7 @@ pub struct MetalDrmDevice {
|
||||||
pub cursor_height: u64,
|
pub cursor_height: u64,
|
||||||
pub gbm: GbmDevice,
|
pub gbm: GbmDevice,
|
||||||
pub handle_events: HandleEvents,
|
pub handle_events: HandleEvents,
|
||||||
|
pub ctx: Rc<MetalRenderContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackendDrmDevice for MetalDrmDevice {
|
impl BackendDrmDevice for MetalDrmDevice {
|
||||||
|
|
@ -213,7 +215,7 @@ impl HardwareCursor for MetalHardwareCursor {
|
||||||
|
|
||||||
fn get_buffer(&self) -> Rc<Framebuffer> {
|
fn get_buffer(&self) -> Rc<Framebuffer> {
|
||||||
let buffer = (self.connector.cursor_front_buffer.get() + 1) % 2;
|
let buffer = (self.connector.cursor_front_buffer.get() + 1) % 2;
|
||||||
self.cursor_buffers[buffer].fb.clone()
|
self.cursor_buffers[buffer].render_fb()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_position(&self, x: i32, y: i32) {
|
fn set_position(&self, x: i32, y: i32) {
|
||||||
|
|
@ -349,13 +351,14 @@ impl MetalConnector {
|
||||||
let cursor = self.cursor_plane.get();
|
let cursor = self.cursor_plane.get();
|
||||||
let mut changes = self.master.change();
|
let mut changes = self.master.change();
|
||||||
if self.has_damage.get() {
|
if self.has_damage.get() {
|
||||||
if !self.backend.check_render_context() {
|
if !self.backend.check_render_context(&self.dev) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
|
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
|
||||||
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
|
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
|
||||||
let mut rr = self.render_result.borrow_mut();
|
let mut rr = self.render_result.borrow_mut();
|
||||||
buffer.fb.render(
|
let render_fb = buffer.render_fb();
|
||||||
|
render_fb.render(
|
||||||
&*node,
|
&*node,
|
||||||
&self.state,
|
&self.state,
|
||||||
Some(node.global.pos.get()),
|
Some(node.global.pos.get()),
|
||||||
|
|
@ -364,11 +367,14 @@ impl MetalConnector {
|
||||||
node.preferred_scale.get(),
|
node.preferred_scale.get(),
|
||||||
!self.cursor_enabled.get(),
|
!self.cursor_enabled.get(),
|
||||||
);
|
);
|
||||||
|
if let Some(tex) = &buffer.dev_tex {
|
||||||
|
buffer.dev_fb.copy_texture(&self.state, tex, 0, 0, false);
|
||||||
|
}
|
||||||
for fr in rr.frame_requests.drain(..) {
|
for fr in rr.frame_requests.drain(..) {
|
||||||
fr.send_done();
|
fr.send_done();
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
let _ = fr.client.remove_obj(&*fr);
|
||||||
}
|
}
|
||||||
node.perform_screencopies(&buffer.fb, &buffer.tex);
|
node.perform_screencopies(&render_fb, &buffer.render_tex);
|
||||||
}
|
}
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
||||||
|
|
@ -377,22 +383,28 @@ impl MetalConnector {
|
||||||
if self.cursor_changed.get() && cursor.is_some() {
|
if self.cursor_changed.get() && cursor.is_some() {
|
||||||
let plane = cursor.unwrap();
|
let plane = cursor.unwrap();
|
||||||
if self.cursor_enabled.get() {
|
if self.cursor_enabled.get() {
|
||||||
if self.cursor_swap_buffer.take() {
|
let swap_buffer = self.cursor_swap_buffer.take();
|
||||||
|
if swap_buffer {
|
||||||
self.cursor_front_buffer.fetch_add(1);
|
self.cursor_front_buffer.fetch_add(1);
|
||||||
}
|
}
|
||||||
let buffers = self.cursor_buffers.get().unwrap();
|
let buffers = self.cursor_buffers.get().unwrap();
|
||||||
let buffer = &buffers[self.cursor_front_buffer.get() % buffers.len()];
|
let buffer = &buffers[self.cursor_front_buffer.get() % buffers.len()];
|
||||||
|
if swap_buffer {
|
||||||
|
if let Some(tex) = &buffer.dev_tex {
|
||||||
|
buffer.dev_fb.copy_texture(&self.state, tex, 0, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
c.change(plane.fb_id, buffer.drm.id().0 as _);
|
||||||
c.change(plane.crtc_id.id, crtc.id.0 as _);
|
c.change(plane.crtc_id.id, crtc.id.0 as _);
|
||||||
c.change(plane.crtc_x.id, self.cursor_x.get() as _);
|
c.change(plane.crtc_x.id, self.cursor_x.get() as _);
|
||||||
c.change(plane.crtc_y.id, self.cursor_y.get() as _);
|
c.change(plane.crtc_y.id, self.cursor_y.get() as _);
|
||||||
c.change(plane.crtc_w.id, buffer.tex.width() as _);
|
c.change(plane.crtc_w.id, buffer.render_tex.width() as _);
|
||||||
c.change(plane.crtc_h.id, buffer.tex.height() as _);
|
c.change(plane.crtc_h.id, buffer.render_tex.height() as _);
|
||||||
c.change(plane.src_x.id, 0);
|
c.change(plane.src_x.id, 0);
|
||||||
c.change(plane.src_y.id, 0);
|
c.change(plane.src_y.id, 0);
|
||||||
c.change(plane.src_w.id, (buffer.tex.width() as u64) << 16);
|
c.change(plane.src_w.id, (buffer.render_tex.width() as u64) << 16);
|
||||||
c.change(plane.src_h.id, (buffer.tex.height() as u64) << 16);
|
c.change(plane.src_h.id, (buffer.render_tex.height() as u64) << 16);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
changes.change_object(plane.id, |c| {
|
changes.change_object(plane.id, |c| {
|
||||||
|
|
@ -864,59 +876,53 @@ struct Preserve {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetalBackend {
|
impl MetalBackend {
|
||||||
fn check_render_context(&self) -> bool {
|
fn check_render_context(&self, dev: &Rc<MetalDrmDevice>) -> bool {
|
||||||
let ctx = match self.ctx.get() {
|
let ctx = match self.ctx.get() {
|
||||||
Some(ctx) => ctx,
|
Some(ctx) => ctx,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
let reset = match ctx.egl.reset_status() {
|
if let Some(r) = ctx
|
||||||
Some(r) => r,
|
.egl
|
||||||
None => return true,
|
.reset_status()
|
||||||
};
|
.or_else(|| dev.ctx.egl.reset_status())
|
||||||
log::error!("EGL context has been reset: {:?}", reset);
|
{
|
||||||
if reset != ResetStatus::Innocent {
|
fatal!("EGL context has been reset: {:?}", r);
|
||||||
fatal!("We are not innocent. Terminating.");
|
|
||||||
}
|
}
|
||||||
log::info!("Trying to create a new context");
|
|
||||||
self.ctx.set(None);
|
|
||||||
self.state.set_render_ctx(None);
|
|
||||||
let mut old_buffers = vec![];
|
|
||||||
for dev in self.device_holder.drm_devices.lock().values() {
|
|
||||||
for connector in dev.connectors.lock().values() {
|
|
||||||
old_buffers.push(connector.buffers.take());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.make_render_device(&ctx.dev, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_render_context(&self, dev: &Rc<MetalDrmDevice>) -> bool {
|
|
||||||
let ctx = match self.create_render_context(dev) {
|
|
||||||
Ok(ctx) => ctx,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not create a render context: {}", ErrorFmt(e));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.state.set_render_ctx(Some(&ctx.egl));
|
|
||||||
self.ctx.set(Some(ctx));
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_render_context(
|
// fn check_render_context(&self) -> bool {
|
||||||
&self,
|
// let ctx = match self.ctx.get() {
|
||||||
dev: &Rc<MetalDrmDevice>,
|
// Some(ctx) => ctx,
|
||||||
) -> Result<Rc<MetalRenderContext>, MetalError> {
|
// None => return false,
|
||||||
let egl = match RenderContext::from_drm_device(&dev.master) {
|
// };
|
||||||
Ok(r) => Rc::new(r),
|
// let reset = match ctx.egl.reset_status() {
|
||||||
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
// Some(r) => r,
|
||||||
};
|
// None => return true,
|
||||||
let ctx = Rc::new(MetalRenderContext {
|
// };
|
||||||
dev: dev.clone(),
|
// log::error!("EGL context has been reset: {:?}", reset);
|
||||||
egl,
|
// if reset != ResetStatus::Innocent {
|
||||||
});
|
// fatal!("We are not innocent. Terminating.");
|
||||||
self.ctx.set(Some(ctx.clone()));
|
// }
|
||||||
Ok(ctx)
|
// log::info!("Trying to create a new context");
|
||||||
}
|
// self.ctx.set(None);
|
||||||
|
// self.state.set_render_ctx(None);
|
||||||
|
// let mut old_buffers = vec![];
|
||||||
|
// let mut ctx_dev = None;
|
||||||
|
// for dev in self.device_holder.drm_devices.lock().values() {
|
||||||
|
// if dev.dev.id == ctx.dev_id {
|
||||||
|
// ctx_dev = Some(dev.dev.clone());
|
||||||
|
// }
|
||||||
|
// for connector in dev.connectors.lock().values() {
|
||||||
|
// old_buffers.push(connector.buffers.take());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if let Some(dev) = &ctx_dev {
|
||||||
|
// self.make_render_device(dev, true)
|
||||||
|
// } else {
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn handle_drm_change(self: &Rc<Self>, dev: UdevDevice) -> Option<()> {
|
pub fn handle_drm_change(self: &Rc<Self>, dev: UdevDevice) -> Option<()> {
|
||||||
let dev = match self.device_holder.drm_devices.get(&dev.devnum()) {
|
let dev = match self.device_holder.drm_devices.get(&dev.devnum()) {
|
||||||
|
|
@ -1083,6 +1089,15 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let egl = match RenderContext::from_drm_device(master) {
|
||||||
|
Ok(r) => Rc::new(r),
|
||||||
|
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
||||||
|
};
|
||||||
|
let ctx = Rc::new(MetalRenderContext {
|
||||||
|
dev_id: pending.id,
|
||||||
|
egl,
|
||||||
|
});
|
||||||
|
|
||||||
let gbm = match GbmDevice::new(master) {
|
let gbm = match GbmDevice::new(master) {
|
||||||
Ok(g) => g,
|
Ok(g) => g,
|
||||||
Err(e) => return Err(MetalError::GbmDevice(e)),
|
Err(e) => return Err(MetalError::GbmDevice(e)),
|
||||||
|
|
@ -1107,6 +1122,7 @@ impl MetalBackend {
|
||||||
handle_events: HandleEvents {
|
handle_events: HandleEvents {
|
||||||
handle_events: Cell::new(None),
|
handle_events: Cell::new(None),
|
||||||
},
|
},
|
||||||
|
ctx,
|
||||||
});
|
});
|
||||||
|
|
||||||
let (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?;
|
let (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?;
|
||||||
|
|
@ -1406,13 +1422,12 @@ impl MetalBackend {
|
||||||
|
|
||||||
fn make_render_device(&self, dev: &Rc<MetalDrmDevice>, log: bool) -> bool {
|
fn make_render_device(&self, dev: &Rc<MetalDrmDevice>, log: bool) -> bool {
|
||||||
if let Some(ctx) = self.ctx.get() {
|
if let Some(ctx) = self.ctx.get() {
|
||||||
if ctx.dev.id == dev.id {
|
if ctx.dev_id == dev.id {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.install_render_context(dev) {
|
self.state.set_render_ctx(Some(&dev.ctx.egl));
|
||||||
return false;
|
self.ctx.set(Some(dev.ctx.clone()));
|
||||||
}
|
|
||||||
let mut preserve = Preserve::default();
|
let mut preserve = Preserve::default();
|
||||||
for dev in self.device_holder.drm_devices.lock().values() {
|
for dev in self.device_holder.drm_devices.lock().values() {
|
||||||
if let Err(e) = self.init_drm_device(dev, &mut preserve) {
|
if let Err(e) = self.init_drm_device(dev, &mut preserve) {
|
||||||
|
|
@ -1575,39 +1590,77 @@ impl MetalBackend {
|
||||||
format: &ModifiedFormat,
|
format: &ModifiedFormat,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
ctx: &MetalRenderContext,
|
render_ctx: &MetalRenderContext,
|
||||||
cursor: bool,
|
cursor: bool,
|
||||||
) -> Result<RenderBuffer, MetalError> {
|
) -> Result<RenderBuffer, MetalError> {
|
||||||
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
let mut usage = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
|
||||||
if cursor || ctx.dev.id != dev.id {
|
if cursor {
|
||||||
usage |= GBM_BO_USE_LINEAR;
|
usage |= GBM_BO_USE_LINEAR;
|
||||||
};
|
};
|
||||||
let bo = dev.gbm.create_bo(width, height, format, usage);
|
let dev_bo = dev.gbm.create_bo(width, height, format, usage);
|
||||||
let bo = match bo {
|
let dev_bo = match dev_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
||||||
};
|
};
|
||||||
let drm_fb = match dev.master.add_fb(bo.dmabuf()) {
|
let drm_fb = match dev.master.add_fb(dev_bo.dmabuf()) {
|
||||||
Ok(fb) => Rc::new(fb),
|
Ok(fb) => Rc::new(fb),
|
||||||
Err(e) => return Err(MetalError::Framebuffer(e)),
|
Err(e) => return Err(MetalError::Framebuffer(e)),
|
||||||
};
|
};
|
||||||
let egl_img = match ctx.egl.dmabuf_img(bo.dmabuf()) {
|
let dev_img = match dev.ctx.egl.dmabuf_img(dev_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||||
};
|
};
|
||||||
let egl_fb = match egl_img.to_framebuffer() {
|
let dev_fb = match dev_img.to_framebuffer() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||||
};
|
};
|
||||||
let egl_tex = match egl_img.to_texture() {
|
dev_fb.clear();
|
||||||
Ok(fb) => fb,
|
let (dev_tex, render_tex, render_fb) = if dev.id == render_ctx.dev_id {
|
||||||
Err(e) => return Err(MetalError::ImportTexture(e)),
|
let render_tex = match dev_img.to_texture() {
|
||||||
|
Ok(fb) => fb,
|
||||||
|
Err(e) => return Err(MetalError::ImportTexture(e)),
|
||||||
|
};
|
||||||
|
(None, render_tex, None)
|
||||||
|
} else {
|
||||||
|
// Create a _bridge_ BO in the render device
|
||||||
|
usage |= GBM_BO_USE_LINEAR;
|
||||||
|
let render_bo = dev.gbm.create_bo(width, height, format, usage);
|
||||||
|
let render_bo = match render_bo {
|
||||||
|
Ok(b) => b,
|
||||||
|
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
||||||
|
};
|
||||||
|
let render_img = match render_ctx.egl.dmabuf_img(render_bo.dmabuf()) {
|
||||||
|
Ok(img) => img,
|
||||||
|
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||||
|
};
|
||||||
|
let render_fb = match render_img.to_framebuffer() {
|
||||||
|
Ok(fb) => fb,
|
||||||
|
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||||
|
};
|
||||||
|
render_fb.clear();
|
||||||
|
let render_tex = match render_img.to_texture() {
|
||||||
|
Ok(fb) => fb,
|
||||||
|
Err(e) => return Err(MetalError::ImportTexture(e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import the bridge BO into the current device
|
||||||
|
let dev_img = match dev.ctx.egl.dmabuf_img(render_bo.dmabuf()) {
|
||||||
|
Ok(img) => img,
|
||||||
|
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||||
|
};
|
||||||
|
let dev_tex = match dev_img.to_texture() {
|
||||||
|
Ok(fb) => fb,
|
||||||
|
Err(e) => return Err(MetalError::ImportTexture(e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
(Some(dev_tex), render_tex, Some(render_fb))
|
||||||
};
|
};
|
||||||
egl_fb.clear();
|
|
||||||
Ok(RenderBuffer {
|
Ok(RenderBuffer {
|
||||||
drm: drm_fb,
|
drm: drm_fb,
|
||||||
fb: egl_fb,
|
dev_fb,
|
||||||
tex: egl_tex,
|
dev_tex,
|
||||||
|
render_tex,
|
||||||
|
render_fb,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1783,8 +1836,26 @@ impl MetalBackend {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RenderBuffer {
|
pub struct RenderBuffer {
|
||||||
drm: Rc<DrmFramebuffer>,
|
drm: Rc<DrmFramebuffer>,
|
||||||
fb: Rc<Framebuffer>,
|
// ctx = dev
|
||||||
tex: Rc<Texture>,
|
// buffer location = dev
|
||||||
|
dev_fb: Rc<Framebuffer>,
|
||||||
|
// ctx = dev
|
||||||
|
// buffer location = render
|
||||||
|
dev_tex: Option<Rc<Texture>>,
|
||||||
|
// ctx = render
|
||||||
|
// buffer location = render
|
||||||
|
render_tex: Rc<Texture>,
|
||||||
|
// ctx = render
|
||||||
|
// buffer location = render
|
||||||
|
render_fb: Option<Rc<Framebuffer>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderBuffer {
|
||||||
|
fn render_fb(&self) -> Rc<Framebuffer> {
|
||||||
|
self.render_fb
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| self.dev_fb.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modes_equal(a: &DrmModeInfo, b: &DrmModeInfo) -> bool {
|
fn modes_equal(a: &DrmModeInfo, b: &DrmModeInfo) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,9 @@ impl JayScreencast {
|
||||||
let mut buffer = self.buffers.borrow_mut();
|
let mut buffer = self.buffers.borrow_mut();
|
||||||
for (idx, buffer) in buffer.deref_mut().iter_mut().enumerate() {
|
for (idx, buffer) in buffer.deref_mut().iter_mut().enumerate() {
|
||||||
if buffer.free {
|
if buffer.free {
|
||||||
buffer.fb.copy_texture(&self.client.state, texture, 0, 0);
|
buffer
|
||||||
|
.fb
|
||||||
|
.copy_texture(&self.client.state, texture, 0, 0, false);
|
||||||
self.client.event(Ready {
|
self.client.event(Ready {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
idx: idx as _,
|
idx: idx as _,
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,13 @@ impl WlOutputGlobal {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fb.copy_texture(&self.state, tex, -capture.rect.x1(), -capture.rect.y1());
|
fb.copy_texture(
|
||||||
|
&self.state,
|
||||||
|
tex,
|
||||||
|
-capture.rect.x1(),
|
||||||
|
-capture.rect.y1(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if capture.with_damage.get() {
|
if capture.with_damage.get() {
|
||||||
capture.send_damage();
|
capture.send_damage();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::{Format, XRGB8888},
|
format::{Format, ARGB8888, XRGB8888},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{
|
render::{
|
||||||
gl::{
|
gl::{
|
||||||
|
|
@ -55,11 +55,15 @@ impl Framebuffer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_texture(&self, state: &State, texture: &Texture, x: i32, y: i32) {
|
pub fn copy_texture(&self, state: &State, texture: &Texture, x: i32, y: i32, alpha: bool) {
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
unsafe {
|
unsafe {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
if alpha {
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
let scale = Scale::from_int(1);
|
let scale = Scale::from_int(1);
|
||||||
|
|
@ -76,9 +80,13 @@ impl Framebuffer {
|
||||||
result: &mut RenderResult::default(),
|
result: &mut RenderResult::default(),
|
||||||
logical_extents: Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap(),
|
logical_extents: Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||||
};
|
};
|
||||||
|
let format = match alpha {
|
||||||
|
true => ARGB8888,
|
||||||
|
false => XRGB8888,
|
||||||
|
};
|
||||||
renderer
|
renderer
|
||||||
.base
|
.base
|
||||||
.render_texture(texture, x, y, XRGB8888, None, None, scale);
|
.render_texture(texture, x, y, format, None, None, scale);
|
||||||
unsafe {
|
unsafe {
|
||||||
glFlush();
|
glFlush();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue