Merge pull request #65 from mahkoh/jorth/gfx2
Abstract over the graphics API
This commit is contained in:
commit
b4d73064d9
82 changed files with 2211 additions and 1526 deletions
698
Cargo.lock
generated
698
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -20,9 +20,9 @@ ahash = "0.8.2"
|
||||||
log = { version = "0.4.16", features = ["std"] }
|
log = { version = "0.4.16", features = ["std"] }
|
||||||
futures-util = "0.3.19"
|
futures-util = "0.3.19"
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
num-derive = "0.3.3"
|
num-derive = "0.4.1"
|
||||||
bitflags = "1.3.2"
|
bitflags = "2.4.1"
|
||||||
libloading = "0.7.2"
|
libloading = "0.8.1"
|
||||||
bstr = { version = "1.1.0", default-features = false, features = ["std"] }
|
bstr = { version = "1.1.0", default-features = false, features = ["std"] }
|
||||||
isnt = "0.1.0"
|
isnt = "0.1.0"
|
||||||
once_cell = "1.9.0"
|
once_cell = "1.9.0"
|
||||||
|
|
@ -37,7 +37,7 @@ pin-project = "1.0.10"
|
||||||
clap = { version = "4.0.29", features = ["derive", "wrap_help"] }
|
clap = { version = "4.0.29", features = ["derive", "wrap_help"] }
|
||||||
clap_complete = "4.0.6"
|
clap_complete = "4.0.6"
|
||||||
humantime = "2.1.0"
|
humantime = "2.1.0"
|
||||||
dirs = "4.0.0"
|
dirs = "5.0.1"
|
||||||
backtrace = "0.3.64"
|
backtrace = "0.3.64"
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.19"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ pub fn bincode_ops() -> impl bincode::config::Config {
|
||||||
.with_fixed_int_encoding()
|
.with_fixed_int_encoding()
|
||||||
.with_little_endian()
|
.with_little_endian()
|
||||||
.with_no_limit()
|
.with_no_limit()
|
||||||
.skip_fixed_array_length()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Config {
|
pub trait Config {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::GfxFramebuffer,
|
||||||
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
||||||
render::Framebuffer,
|
|
||||||
video::drm::{ConnectorType, DrmError, DrmVersion},
|
video::drm::{ConnectorType, DrmError, DrmVersion},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -95,7 +95,7 @@ pub enum ConnectorEvent {
|
||||||
|
|
||||||
pub trait HardwareCursor: Debug {
|
pub trait HardwareCursor: Debug {
|
||||||
fn set_enabled(&self, enabled: bool);
|
fn set_enabled(&self, enabled: bool);
|
||||||
fn get_buffer(&self) -> Rc<Framebuffer>;
|
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>;
|
||||||
fn set_position(&self, x: i32, y: i32);
|
fn set_position(&self, x: i32, y: i32);
|
||||||
fn swap_buffer(&self);
|
fn swap_buffer(&self);
|
||||||
fn commit(&self);
|
fn commit(&self);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use {
|
||||||
},
|
},
|
||||||
backends::metal::video::{MetalDrmDeviceData, MetalRenderContext, PendingDrmDevice},
|
backends::metal::video::{MetalDrmDeviceData, MetalRenderContext, PendingDrmDevice},
|
||||||
dbus::{DbusError, SignalHandler},
|
dbus::{DbusError, SignalHandler},
|
||||||
|
gfx_api::GfxError,
|
||||||
libinput::{
|
libinput::{
|
||||||
consts::{
|
consts::{
|
||||||
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
|
|
@ -23,7 +24,6 @@ use {
|
||||||
LibInput, LibInputAdapter, LibInputError,
|
LibInput, LibInputAdapter, LibInputError,
|
||||||
},
|
},
|
||||||
logind::{LogindError, Session},
|
logind::{LogindError, Session},
|
||||||
render::RenderError,
|
|
||||||
state::State,
|
state::State,
|
||||||
time::now_usec,
|
time::now_usec,
|
||||||
udev::{Udev, UdevError, UdevMonitor},
|
udev::{Udev, UdevError, UdevMonitor},
|
||||||
|
|
@ -75,7 +75,7 @@ pub enum MetalError {
|
||||||
#[error("Could not update the drm properties")]
|
#[error("Could not update the drm properties")]
|
||||||
UpdateProperties(#[source] DrmError),
|
UpdateProperties(#[source] DrmError),
|
||||||
#[error("Could not create a render context")]
|
#[error("Could not create a render context")]
|
||||||
CreateRenderContex(#[source] RenderError),
|
CreateRenderContex(#[source] GfxError),
|
||||||
#[error("Cannot initialize connector because no CRTC is available")]
|
#[error("Cannot initialize connector because no CRTC is available")]
|
||||||
NoCrtcForConnector,
|
NoCrtcForConnector,
|
||||||
#[error("Cannot initialize connector because no primary plane is available")]
|
#[error("Cannot initialize connector because no primary plane is available")]
|
||||||
|
|
@ -86,12 +86,12 @@ pub enum MetalError {
|
||||||
ScanoutBuffer(#[source] GbmError),
|
ScanoutBuffer(#[source] GbmError),
|
||||||
#[error("addfb2 failed")]
|
#[error("addfb2 failed")]
|
||||||
Framebuffer(#[source] DrmError),
|
Framebuffer(#[source] DrmError),
|
||||||
#[error("Could not import a framebuffer into EGL")]
|
#[error("Could not import a framebuffer into the graphics API")]
|
||||||
ImportFb(#[source] RenderError),
|
ImportFb(#[source] GfxError),
|
||||||
#[error("Could not import a texture into EGL")]
|
#[error("Could not import a texture into the graphics API")]
|
||||||
ImportTexture(#[source] RenderError),
|
ImportTexture(#[source] GfxError),
|
||||||
#[error("Could not import an image into EGL")]
|
#[error("Could not import an image into the graphics API")]
|
||||||
ImportImage(#[source] RenderError),
|
ImportImage(#[source] GfxError),
|
||||||
#[error("Could not perform modeset")]
|
#[error("Could not perform modeset")]
|
||||||
Modeset(#[source] DrmError),
|
Modeset(#[source] DrmError),
|
||||||
#[error("Could not enable atomic modesetting")]
|
#[error("Could not enable atomic modesetting")]
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ use {
|
||||||
backends::metal::{MetalBackend, MetalError},
|
backends::metal::{MetalBackend, MetalError},
|
||||||
edid::Descriptor,
|
edid::Descriptor,
|
||||||
format::{Format, ARGB8888, XRGB8888},
|
format::{Format, ARGB8888, XRGB8888},
|
||||||
|
gfx_api::{GfxContext, GfxFramebuffer, GfxTexture},
|
||||||
|
gfx_apis::create_gfx_context,
|
||||||
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||||
render::{Framebuffer, RenderContext, RenderResult, Texture},
|
renderer::RenderResult,
|
||||||
state::State,
|
state::State,
|
||||||
udev::UdevDevice,
|
udev::UdevDevice,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -51,7 +53,7 @@ pub struct PendingDrmDevice {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MetalRenderContext {
|
pub struct MetalRenderContext {
|
||||||
pub dev_id: DrmDeviceId,
|
pub dev_id: DrmDeviceId,
|
||||||
pub egl: Rc<RenderContext>,
|
pub gfx: Rc<dyn GfxContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -213,7 +215,7 @@ impl HardwareCursor for MetalHardwareCursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_buffer(&self) -> Rc<Framebuffer> {
|
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer> {
|
||||||
let buffer = (self.connector.cursor_front_buffer.get() + 1) % 2;
|
let buffer = (self.connector.cursor_front_buffer.get() + 1) % 2;
|
||||||
self.cursor_buffers[buffer].render_fb()
|
self.cursor_buffers[buffer].render_fb()
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +376,7 @@ impl MetalConnector {
|
||||||
fr.send_done();
|
fr.send_done();
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
let _ = fr.client.remove_obj(&*fr);
|
||||||
}
|
}
|
||||||
node.perform_screencopies(&render_fb, &buffer.render_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 _);
|
||||||
|
|
@ -882,9 +884,9 @@ impl MetalBackend {
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
if let Some(r) = ctx
|
if let Some(r) = ctx
|
||||||
.egl
|
.gfx
|
||||||
.reset_status()
|
.reset_status()
|
||||||
.or_else(|| dev.ctx.egl.reset_status())
|
.or_else(|| dev.ctx.gfx.reset_status())
|
||||||
{
|
{
|
||||||
fatal!("EGL context has been reset: {:?}", r);
|
fatal!("EGL context has been reset: {:?}", r);
|
||||||
}
|
}
|
||||||
|
|
@ -1089,13 +1091,13 @@ impl MetalBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let egl = match RenderContext::from_drm_device(master) {
|
let gfx = match create_gfx_context(master) {
|
||||||
Ok(r) => Rc::new(r),
|
Ok(r) => r,
|
||||||
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
Err(e) => return Err(MetalError::CreateRenderContex(e)),
|
||||||
};
|
};
|
||||||
let ctx = Rc::new(MetalRenderContext {
|
let ctx = Rc::new(MetalRenderContext {
|
||||||
dev_id: pending.id,
|
dev_id: pending.id,
|
||||||
egl,
|
gfx,
|
||||||
});
|
});
|
||||||
|
|
||||||
let gbm = match GbmDevice::new(master) {
|
let gbm = match GbmDevice::new(master) {
|
||||||
|
|
@ -1420,7 +1422,7 @@ impl MetalBackend {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state.set_render_ctx(Some(&dev.ctx.egl));
|
self.state.set_render_ctx(Some(dev.ctx.gfx.clone()));
|
||||||
self.ctx.set(Some(dev.ctx.clone()));
|
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() {
|
||||||
|
|
@ -1600,11 +1602,11 @@ impl MetalBackend {
|
||||||
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 dev_img = match dev.ctx.egl.dmabuf_img(dev_bo.dmabuf()) {
|
let dev_img = match dev.ctx.gfx.clone().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 dev_fb = match dev_img.to_framebuffer() {
|
let dev_fb = match dev_img.clone().to_framebuffer() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||||
};
|
};
|
||||||
|
|
@ -1618,16 +1620,16 @@ impl MetalBackend {
|
||||||
} else {
|
} else {
|
||||||
// Create a _bridge_ BO in the render device
|
// Create a _bridge_ BO in the render device
|
||||||
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
usage = GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR;
|
||||||
let render_bo = render_ctx.egl.gbm.create_bo(width, height, format, usage);
|
let render_bo = render_ctx.gfx.gbm().create_bo(width, height, format, usage);
|
||||||
let render_bo = match render_bo {
|
let render_bo = match render_bo {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
Err(e) => return Err(MetalError::ScanoutBuffer(e)),
|
||||||
};
|
};
|
||||||
let render_img = match render_ctx.egl.dmabuf_img(render_bo.dmabuf()) {
|
let render_img = match render_ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||||
};
|
};
|
||||||
let render_fb = match render_img.to_framebuffer() {
|
let render_fb = match render_img.clone().to_framebuffer() {
|
||||||
Ok(fb) => fb,
|
Ok(fb) => fb,
|
||||||
Err(e) => return Err(MetalError::ImportFb(e)),
|
Err(e) => return Err(MetalError::ImportFb(e)),
|
||||||
};
|
};
|
||||||
|
|
@ -1638,7 +1640,7 @@ impl MetalBackend {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Import the bridge BO into the current device
|
// Import the bridge BO into the current device
|
||||||
let dev_img = match dev.ctx.egl.dmabuf_img(render_bo.dmabuf()) {
|
let dev_img = match dev.ctx.gfx.clone().dmabuf_img(render_bo.dmabuf()) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => return Err(MetalError::ImportImage(e)),
|
Err(e) => return Err(MetalError::ImportImage(e)),
|
||||||
};
|
};
|
||||||
|
|
@ -1832,20 +1834,20 @@ pub struct RenderBuffer {
|
||||||
drm: Rc<DrmFramebuffer>,
|
drm: Rc<DrmFramebuffer>,
|
||||||
// ctx = dev
|
// ctx = dev
|
||||||
// buffer location = dev
|
// buffer location = dev
|
||||||
dev_fb: Rc<Framebuffer>,
|
dev_fb: Rc<dyn GfxFramebuffer>,
|
||||||
// ctx = dev
|
// ctx = dev
|
||||||
// buffer location = render
|
// buffer location = render
|
||||||
dev_tex: Option<Rc<Texture>>,
|
dev_tex: Option<Rc<dyn GfxTexture>>,
|
||||||
// ctx = render
|
// ctx = render
|
||||||
// buffer location = render
|
// buffer location = render
|
||||||
render_tex: Rc<Texture>,
|
render_tex: Rc<dyn GfxTexture>,
|
||||||
// ctx = render
|
// ctx = render
|
||||||
// buffer location = render
|
// buffer location = render
|
||||||
render_fb: Option<Rc<Framebuffer>>,
|
render_fb: Option<Rc<dyn GfxFramebuffer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderBuffer {
|
impl RenderBuffer {
|
||||||
fn render_fb(&self) -> Rc<Framebuffer> {
|
fn render_fb(&self) -> Rc<dyn GfxFramebuffer> {
|
||||||
self.render_fb
|
self.render_fb
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| self.dev_fb.clone())
|
.unwrap_or_else(|| self.dev_fb.clone())
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ use {
|
||||||
},
|
},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
render::{Framebuffer, RenderContext, RenderError, RenderResult, Texture},
|
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
||||||
|
gfx_apis::create_gfx_context,
|
||||||
|
renderer::RenderResult,
|
||||||
state::State,
|
state::State,
|
||||||
time::now_usec,
|
time::now_usec,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -88,14 +90,14 @@ pub enum XBackendError {
|
||||||
GbmError(#[from] GbmError),
|
GbmError(#[from] GbmError),
|
||||||
#[error("Could not import a dma-buf")]
|
#[error("Could not import a dma-buf")]
|
||||||
ImportBuffer(#[source] XconError),
|
ImportBuffer(#[source] XconError),
|
||||||
#[error("Could not create an EGL context")]
|
#[error("Could not create a graphics API context")]
|
||||||
CreateEgl(#[source] RenderError),
|
CreateEgl(#[source] GfxError),
|
||||||
#[error("Could not create an EGL image from a dma-buf")]
|
#[error("Could not create an graphics API image from a dma-buf")]
|
||||||
CreateImage(#[source] RenderError),
|
CreateImage(#[source] GfxError),
|
||||||
#[error("Could not create a framebuffer from an EGL image")]
|
#[error("Could not create a framebuffer from a graphics API image")]
|
||||||
CreateFramebuffer(#[source] RenderError),
|
CreateFramebuffer(#[source] GfxError),
|
||||||
#[error("Could not create a texture from an EGL image")]
|
#[error("Could not create a texture from an graphics API image")]
|
||||||
CreateTexture(#[source] RenderError),
|
CreateTexture(#[source] GfxError),
|
||||||
#[error("Could not select input events")]
|
#[error("Could not select input events")]
|
||||||
CannotSelectInputEvents(#[source] XconError),
|
CannotSelectInputEvents(#[source] XconError),
|
||||||
#[error("Could not select present events")]
|
#[error("Could not select present events")]
|
||||||
|
|
@ -177,8 +179,8 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
||||||
Err(e) => return Err(XBackendError::DrmDeviceFstat(e)),
|
Err(e) => return Err(XBackendError::DrmDeviceFstat(e)),
|
||||||
};
|
};
|
||||||
let gbm = GbmDevice::new(&drm)?;
|
let gbm = GbmDevice::new(&drm)?;
|
||||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
let ctx = match create_gfx_context(&drm) {
|
||||||
Ok(r) => Rc::new(r),
|
Ok(r) => r,
|
||||||
Err(e) => return Err(XBackendError::CreateEgl(e)),
|
Err(e) => return Err(XBackendError::CreateEgl(e)),
|
||||||
};
|
};
|
||||||
let cursor = {
|
let cursor = {
|
||||||
|
|
@ -265,7 +267,7 @@ pub struct XBackend {
|
||||||
outputs: CopyHashMap<u32, Rc<XOutput>>,
|
outputs: CopyHashMap<u32, Rc<XOutput>>,
|
||||||
seats: CopyHashMap<u16, Rc<XSeat>>,
|
seats: CopyHashMap<u16, Rc<XSeat>>,
|
||||||
mouse_seats: CopyHashMap<u16, Rc<XSeat>>,
|
mouse_seats: CopyHashMap<u16, Rc<XSeat>>,
|
||||||
ctx: Rc<RenderContext>,
|
ctx: Rc<dyn GfxContext>,
|
||||||
gbm: GbmDevice,
|
gbm: GbmDevice,
|
||||||
cursor: u32,
|
cursor: u32,
|
||||||
root: u32,
|
root: u32,
|
||||||
|
|
@ -287,7 +289,7 @@ impl XBackend {
|
||||||
.eng
|
.eng
|
||||||
.spawn2(Phase::Present, self.clone().present_handler());
|
.spawn2(Phase::Present, self.clone().present_handler());
|
||||||
|
|
||||||
self.state.set_render_ctx(Some(&self.ctx));
|
self.state.set_render_ctx(Some(self.ctx.clone()));
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewDrmDevice(Rc::new(XDrmDevice {
|
.push(BackendEvent::NewDrmDevice(Rc::new(XDrmDevice {
|
||||||
|
|
@ -387,11 +389,11 @@ impl XBackend {
|
||||||
assert!(dma.planes.len() == 1);
|
assert!(dma.planes.len() == 1);
|
||||||
let plane = dma.planes.first().unwrap();
|
let plane = dma.planes.first().unwrap();
|
||||||
let size = plane.stride * dma.height as u32;
|
let size = plane.stride * dma.height as u32;
|
||||||
let img = match self.ctx.dmabuf_img(dma) {
|
let img = match self.ctx.clone().dmabuf_img(dma) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => return Err(XBackendError::CreateImage(e)),
|
Err(e) => return Err(XBackendError::CreateImage(e)),
|
||||||
};
|
};
|
||||||
let fb = match img.to_framebuffer() {
|
let fb = match img.clone().to_framebuffer() {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => return Err(XBackendError::CreateFramebuffer(e)),
|
Err(e) => return Err(XBackendError::CreateFramebuffer(e)),
|
||||||
};
|
};
|
||||||
|
|
@ -734,7 +736,7 @@ impl XBackend {
|
||||||
fr.send_done();
|
fr.send_done();
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
let _ = fr.client.remove_obj(&*fr);
|
||||||
}
|
}
|
||||||
node.perform_screencopies(&fb, &image.tex.get());
|
node.perform_screencopies(&*fb, &image.tex.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
let pp = PresentPixmap {
|
let pp = PresentPixmap {
|
||||||
|
|
@ -988,8 +990,8 @@ struct XOutput {
|
||||||
|
|
||||||
struct XImage {
|
struct XImage {
|
||||||
pixmap: Cell<u32>,
|
pixmap: Cell<u32>,
|
||||||
fb: CloneCell<Rc<Framebuffer>>,
|
fb: CloneCell<Rc<dyn GfxFramebuffer>>,
|
||||||
tex: CloneCell<Rc<Texture>>,
|
tex: CloneCell<Rc<dyn GfxTexture>>,
|
||||||
idle: Cell<bool>,
|
idle: Cell<bool>,
|
||||||
render_on_idle: Cell<bool>,
|
render_on_idle: Cell<bool>,
|
||||||
last_serial: Cell<u32>,
|
last_serial: Cell<u32>,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ use {
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
leaks,
|
leaks,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
render::{self, RenderError},
|
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
sighand::{self, SighandError},
|
sighand::{self, SighandError},
|
||||||
state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState},
|
state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState},
|
||||||
|
|
@ -86,8 +85,6 @@ pub enum CompositorError {
|
||||||
ClientmemError(#[from] ClientMemError),
|
ClientmemError(#[from] ClientMemError),
|
||||||
#[error("The timer subsystem caused an error")]
|
#[error("The timer subsystem caused an error")]
|
||||||
WheelError(#[from] WheelError),
|
WheelError(#[from] WheelError),
|
||||||
#[error("The render backend caused an error")]
|
|
||||||
RenderError(#[from] RenderError),
|
|
||||||
#[error("Could not create an io-uring")]
|
#[error("Could not create an io-uring")]
|
||||||
IoUringError(#[from] IoUringError),
|
IoUringError(#[from] IoUringError),
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +109,6 @@ fn start_compositor2(
|
||||||
log::info!("pid = {}", uapi::getpid());
|
log::info!("pid = {}", uapi::getpid());
|
||||||
init_fd_limit();
|
init_fd_limit();
|
||||||
leaks::init();
|
leaks::init();
|
||||||
render::init()?;
|
|
||||||
clientmem::init()?;
|
clientmem::init()?;
|
||||||
let xkb_ctx = XkbContext::new().unwrap();
|
let xkb_ctx = XkbContext::new().unwrap();
|
||||||
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::ARGB8888,
|
format::ARGB8888,
|
||||||
|
gfx_api::{GfxContext, GfxError, GfxTexture},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{RenderContext, RenderError, Renderer, Texture},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
time::Time,
|
time::Time,
|
||||||
|
|
@ -86,7 +87,7 @@ pub enum KnownCursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerCursors {
|
impl ServerCursors {
|
||||||
pub fn load(ctx: &Rc<RenderContext>, state: &State) -> Result<Option<Self>, CursorError> {
|
pub fn load(ctx: &Rc<dyn GfxContext>, state: &State) -> Result<Option<Self>, CursorError> {
|
||||||
let paths = find_cursor_paths();
|
let paths = find_cursor_paths();
|
||||||
log::debug!("Trying to load cursors from paths {:?}", paths);
|
log::debug!("Trying to load cursors from paths {:?}", paths);
|
||||||
let sizes = state.cursor_sizes.to_vec();
|
let sizes = state.cursor_sizes.to_vec();
|
||||||
|
|
@ -134,7 +135,7 @@ impl ServerCursorTemplate {
|
||||||
scales: &[Scale],
|
scales: &[Scale],
|
||||||
sizes: &[u32],
|
sizes: &[u32],
|
||||||
paths: &[BString],
|
paths: &[BString],
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
) -> Result<Self, CursorError> {
|
) -> Result<Self, CursorError> {
|
||||||
match open_cursor(name, theme, scales, sizes, paths) {
|
match open_cursor(name, theme, scales, sizes, paths) {
|
||||||
Ok(cs) => {
|
Ok(cs) => {
|
||||||
|
|
@ -214,7 +215,7 @@ impl ServerCursorTemplate {
|
||||||
|
|
||||||
struct CursorImageScaled {
|
struct CursorImageScaled {
|
||||||
extents: Rect,
|
extents: Rect,
|
||||||
tex: Rc<Texture>,
|
tex: Rc<dyn GfxTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CursorImage {
|
struct CursorImage {
|
||||||
|
|
@ -229,7 +230,7 @@ struct InstantiatedCursorImage {
|
||||||
|
|
||||||
impl CursorImageScaled {
|
impl CursorImageScaled {
|
||||||
fn from_bytes(
|
fn from_bytes(
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
data: &[Cell<u8>],
|
data: &[Cell<u8>],
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
|
|
@ -238,7 +239,9 @@ impl CursorImageScaled {
|
||||||
) -> Result<Rc<Self>, CursorError> {
|
) -> Result<Rc<Self>, CursorError> {
|
||||||
Ok(Rc::new(Self {
|
Ok(Rc::new(Self {
|
||||||
extents: Rect::new_sized(-xhot, -yhot, width, height).unwrap(),
|
extents: Rect::new_sized(-xhot, -yhot, width, height).unwrap(),
|
||||||
tex: ctx.shmem_texture(data, ARGB8888, width, height, width * 4)?,
|
tex: ctx
|
||||||
|
.clone()
|
||||||
|
.shmem_texture(data, ARGB8888, width, height, width * 4)?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,6 +298,8 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
scale,
|
scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -306,9 +311,17 @@ impl Cursor for StaticCursor {
|
||||||
|
|
||||||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||||
if let Some(img) = self.image.scales.get(&renderer.scale()) {
|
if let Some(img) = self.image.scales.get(&renderer.scale()) {
|
||||||
renderer
|
renderer.base.render_texture(
|
||||||
.base
|
&img.tex,
|
||||||
.render_texture(&img.tex, 0, 0, ARGB8888, None, None, renderer.scale());
|
0,
|
||||||
|
0,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
renderer.scale(),
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,9 +349,17 @@ impl Cursor for AnimatedCursor {
|
||||||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||||
let img = &self.images[self.idx.get()];
|
let img = &self.images[self.idx.get()];
|
||||||
if let Some(img) = img.scales.get(&renderer.scale()) {
|
if let Some(img) = img.scales.get(&renderer.scale()) {
|
||||||
renderer
|
renderer.base.render_texture(
|
||||||
.base
|
&img.tex,
|
||||||
.render_texture(&img.tex, 0, 0, ARGB8888, None, None, renderer.scale());
|
0,
|
||||||
|
0,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
renderer.scale(),
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,7 +538,7 @@ pub enum CursorError {
|
||||||
#[error("The requested cursor could not be found")]
|
#[error("The requested cursor could not be found")]
|
||||||
NotFound,
|
NotFound,
|
||||||
#[error("Could not import the cursor as a texture")]
|
#[error("Could not import the cursor as a texture")]
|
||||||
ImportError(#[from] RenderError),
|
ImportError(#[from] GfxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
gfx_apis::gl::sys::{GLint, GL_BGRA_EXT, GL_RGBA, 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_NV12, SPA_VIDEO_FORMAT_RGBA,
|
SPA_VIDEO_FORMAT_NV12, SPA_VIDEO_FORMAT_RGBA,
|
||||||
},
|
},
|
||||||
render::sys::{GLint, GL_BGRA_EXT, GL_RGBA, GL_UNSIGNED_BYTE},
|
|
||||||
utils::debug_fn::debug_fn,
|
utils::debug_fn::debug_fn,
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
|
||||||
218
src/gfx_api.rs
Normal file
218
src/gfx_api.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
cursor::Cursor,
|
||||||
|
format::Format,
|
||||||
|
rect::Rect,
|
||||||
|
renderer::{renderer_base::RendererBase, RenderResult},
|
||||||
|
scale::Scale,
|
||||||
|
state::State,
|
||||||
|
theme::Color,
|
||||||
|
tree::Node,
|
||||||
|
video::{dmabuf::DmaBuf, gbm::GbmDevice},
|
||||||
|
},
|
||||||
|
ahash::AHashMap,
|
||||||
|
std::{
|
||||||
|
any::Any,
|
||||||
|
cell::Cell,
|
||||||
|
error::Error,
|
||||||
|
ffi::CString,
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum GfxApiOpt {
|
||||||
|
Sync,
|
||||||
|
Clear(Clear),
|
||||||
|
FillRect(FillRect),
|
||||||
|
CopyTexture(CopyTexture),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
|
pub struct BufferPoint {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufferPoint {
|
||||||
|
pub fn is_leq_1(&self) -> bool {
|
||||||
|
self.x <= 1.0 && self.y <= 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
|
pub struct BufferPoints {
|
||||||
|
pub top_left: BufferPoint,
|
||||||
|
pub top_right: BufferPoint,
|
||||||
|
pub bottom_left: BufferPoint,
|
||||||
|
pub bottom_right: BufferPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufferPoints {
|
||||||
|
pub fn norm(&self, width: f32, height: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
top_left: BufferPoint {
|
||||||
|
x: self.top_left.x / width,
|
||||||
|
y: self.top_left.y / height,
|
||||||
|
},
|
||||||
|
top_right: BufferPoint {
|
||||||
|
x: self.top_right.x / width,
|
||||||
|
y: self.top_right.y / height,
|
||||||
|
},
|
||||||
|
bottom_left: BufferPoint {
|
||||||
|
x: self.bottom_left.x / width,
|
||||||
|
y: self.bottom_left.y / height,
|
||||||
|
},
|
||||||
|
bottom_right: BufferPoint {
|
||||||
|
x: self.bottom_right.x / width,
|
||||||
|
y: self.bottom_right.y / height,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_leq_1(&self) -> bool {
|
||||||
|
self.top_left.is_leq_1()
|
||||||
|
&& self.top_right.is_leq_1()
|
||||||
|
&& self.bottom_left.is_leq_1()
|
||||||
|
&& self.bottom_right.is_leq_1()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AbsoluteRect {
|
||||||
|
pub x1: f32,
|
||||||
|
pub x2: f32,
|
||||||
|
pub y1: f32,
|
||||||
|
pub y2: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Clear {
|
||||||
|
pub color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FillRect {
|
||||||
|
pub rect: AbsoluteRect,
|
||||||
|
pub color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyTexture {
|
||||||
|
pub tex: Rc<dyn GfxTexture>,
|
||||||
|
pub format: &'static Format,
|
||||||
|
pub source: BufferPoints,
|
||||||
|
pub target: AbsoluteRect,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ResetStatus {
|
||||||
|
Guilty,
|
||||||
|
Innocent,
|
||||||
|
Unknown,
|
||||||
|
Other(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GfxFramebuffer: Debug {
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
fn clear(&self);
|
||||||
|
|
||||||
|
fn clear_with(&self, r: f32, g: f32, b: f32, a: f32);
|
||||||
|
|
||||||
|
fn copy_texture(
|
||||||
|
&self,
|
||||||
|
state: &State,
|
||||||
|
texture: &Rc<dyn GfxTexture>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
alpha: bool,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn copy_to_shm(
|
||||||
|
&self,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &Format,
|
||||||
|
shm: &[Cell<u8>],
|
||||||
|
);
|
||||||
|
|
||||||
|
fn render_custom(&self, scale: Scale, f: &mut dyn FnMut(&mut RendererBase));
|
||||||
|
|
||||||
|
fn render(
|
||||||
|
&self,
|
||||||
|
node: &dyn Node,
|
||||||
|
state: &State,
|
||||||
|
cursor_rect: Option<Rect>,
|
||||||
|
on_output: bool,
|
||||||
|
result: &mut RenderResult,
|
||||||
|
scale: Scale,
|
||||||
|
render_hardware_cursor: bool,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GfxImage {
|
||||||
|
fn to_framebuffer(self: Rc<Self>) -> Result<Rc<dyn GfxFramebuffer>, GfxError>;
|
||||||
|
|
||||||
|
fn to_texture(self: Rc<Self>) -> Result<Rc<dyn GfxTexture>, GfxError>;
|
||||||
|
|
||||||
|
fn width(&self) -> i32;
|
||||||
|
fn height(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GfxTexture: Debug {
|
||||||
|
fn width(&self) -> i32;
|
||||||
|
fn height(&self) -> i32;
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GfxContext: Debug {
|
||||||
|
fn take_render_ops(&self) -> Vec<GfxApiOpt>;
|
||||||
|
|
||||||
|
fn reset_status(&self) -> Option<ResetStatus>;
|
||||||
|
|
||||||
|
fn supports_external_texture(&self) -> bool;
|
||||||
|
|
||||||
|
fn render_node(&self) -> Rc<CString>;
|
||||||
|
|
||||||
|
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>>;
|
||||||
|
|
||||||
|
fn dmabuf_fb(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxFramebuffer>, GfxError>;
|
||||||
|
|
||||||
|
fn dmabuf_img(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxImage>, GfxError>;
|
||||||
|
|
||||||
|
fn shmem_texture(
|
||||||
|
self: Rc<Self>,
|
||||||
|
data: &[Cell<u8>],
|
||||||
|
format: &'static Format,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
) -> Result<Rc<dyn GfxTexture>, GfxError>;
|
||||||
|
|
||||||
|
fn gbm(&self) -> &GbmDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GfxFormat {
|
||||||
|
pub format: &'static Format,
|
||||||
|
pub implicit_external_only: bool,
|
||||||
|
pub modifiers: AHashMap<u64, GfxModifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GfxModifier {
|
||||||
|
pub modifier: u64,
|
||||||
|
pub external_only: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error)]
|
||||||
|
#[error(transparent)]
|
||||||
|
pub struct GfxError(pub Box<dyn Error>);
|
||||||
|
|
||||||
|
impl Debug for GfxError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Debug::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/gfx_apis.rs
Normal file
13
src/gfx_apis.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
gfx_api::{GfxContext, GfxError},
|
||||||
|
video::drm::Drm,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod gl;
|
||||||
|
|
||||||
|
pub fn create_gfx_context(drm: &Drm) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
|
gl::create_gfx_context(drm)
|
||||||
|
}
|
||||||
358
src/gfx_apis/gl.rs
Normal file
358
src/gfx_apis/gl.rs
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
macro_rules! egl_transparent {
|
||||||
|
($name:ident) => {
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct $name(pub *mut u8);
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const fn none() -> Self {
|
||||||
|
Self(std::ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn is_none(self) -> bool {
|
||||||
|
self.0.is_null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
format::Format,
|
||||||
|
gfx_api::{
|
||||||
|
BufferPoints, CopyTexture, FillRect, GfxApiOpt, GfxContext, GfxError, GfxTexture,
|
||||||
|
},
|
||||||
|
gfx_apis::gl::{
|
||||||
|
gl::texture::image_target,
|
||||||
|
renderer::{context::GlRenderContext, framebuffer::Framebuffer, texture::Texture},
|
||||||
|
sys::{
|
||||||
|
glActiveTexture, glBindTexture, glClear, glClearColor, glDisable,
|
||||||
|
glDisableVertexAttribArray, glDrawArrays, glEnable, glEnableVertexAttribArray,
|
||||||
|
glTexParameteri, glUniform1i, glUniform4f, glUseProgram, glVertexAttribPointer,
|
||||||
|
GL_BLEND, GL_COLOR_BUFFER_BIT, GL_FALSE, GL_FLOAT, GL_LINEAR, GL_TEXTURE0,
|
||||||
|
GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
theme::Color,
|
||||||
|
utils::{rc_eq::rc_eq, vecstorage::VecStorage},
|
||||||
|
video::{
|
||||||
|
drm::{Drm, DrmError},
|
||||||
|
gbm::GbmError,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isnt::std_1::vec::IsntVecExt,
|
||||||
|
once_cell::sync::Lazy,
|
||||||
|
std::{cell::RefCell, rc::Rc, sync::Arc},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod egl;
|
||||||
|
mod ext;
|
||||||
|
mod gl;
|
||||||
|
mod proc;
|
||||||
|
mod renderer;
|
||||||
|
|
||||||
|
pub mod sys {
|
||||||
|
pub use super::{egl::sys::*, gl::sys::*};
|
||||||
|
}
|
||||||
|
|
||||||
|
static INIT: Lazy<Result<(), Arc<RenderError>>> = Lazy::new(|| egl::init().map_err(Arc::new));
|
||||||
|
|
||||||
|
pub(super) fn create_gfx_context(drm: &Drm) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
|
if let Err(e) = &*INIT {
|
||||||
|
return Err(GfxError(Box::new(e.clone())));
|
||||||
|
}
|
||||||
|
GlRenderContext::from_drm_device(drm)
|
||||||
|
.map(|v| Rc::new(v) as Rc<dyn GfxContext>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum RenderError {
|
||||||
|
#[error("EGL library does not support `EGL_EXT_platform_base`")]
|
||||||
|
ExtPlatformBase,
|
||||||
|
#[error("Could not compile a shader")]
|
||||||
|
ShaderCompileFailed,
|
||||||
|
#[error("Could not link a program")]
|
||||||
|
ProgramLink,
|
||||||
|
#[error("Could not bind to `EGL_OPENGL_ES_API`")]
|
||||||
|
BindFailed,
|
||||||
|
#[error("EGL library does not support the GBM platform")]
|
||||||
|
GbmExt,
|
||||||
|
#[error("Could not create a GBM device")]
|
||||||
|
Gbm(#[source] GbmError),
|
||||||
|
#[error("`eglCreateContext` failed")]
|
||||||
|
CreateContext,
|
||||||
|
#[error("`eglMakeCurrent` failed")]
|
||||||
|
MakeCurrent,
|
||||||
|
#[error("`eglCreateImageKHR` failed")]
|
||||||
|
CreateImage,
|
||||||
|
#[error("Image buffer is too small")]
|
||||||
|
SmallImageBuffer,
|
||||||
|
#[error("Binding a renderbuffer to a framebuffer failed")]
|
||||||
|
CreateFramebuffer,
|
||||||
|
#[error("`eglGetPlatformDisplayEXT` failed")]
|
||||||
|
GetDisplay,
|
||||||
|
#[error("`eglInitialize` failed")]
|
||||||
|
Initialize,
|
||||||
|
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
||||||
|
DmaBufImport,
|
||||||
|
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
||||||
|
OesEglImage,
|
||||||
|
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
||||||
|
ImageBase,
|
||||||
|
#[error(
|
||||||
|
"EGL display does not support `EGL_KHR_no_config_context` or `EGL_MESA_configless_context`"
|
||||||
|
)]
|
||||||
|
ConfiglessContext,
|
||||||
|
#[error("EGL display does not support `EGL_KHR_surfaceless_context`")]
|
||||||
|
SurfacelessContext,
|
||||||
|
#[error("`eglQueryDmaBufFormatsEXT` failed")]
|
||||||
|
QueryDmaBufFormats,
|
||||||
|
#[error("`eglQueryDmaBufModifiersEXT` failed")]
|
||||||
|
QueryDmaBufModifiers,
|
||||||
|
#[error(transparent)]
|
||||||
|
DrmError(#[from] DrmError),
|
||||||
|
#[error("The GLES driver does not support the XRGB8888 format")]
|
||||||
|
XRGB888,
|
||||||
|
#[error("The DRM device does not have a render node")]
|
||||||
|
NoRenderNode,
|
||||||
|
#[error("The requested format is not supported")]
|
||||||
|
UnsupportedFormat,
|
||||||
|
#[error("The requested modifier is not supported")]
|
||||||
|
UnsupportedModifier,
|
||||||
|
#[error("Image is external only and cannot be rendered to")]
|
||||||
|
ExternalOnly,
|
||||||
|
#[error("OpenGL context does not support external textures")]
|
||||||
|
ExternalUnsupported,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct GfxGlState {
|
||||||
|
triangles: RefCell<Vec<f32>>,
|
||||||
|
fill_rect: VecStorage<&'static FillRect>,
|
||||||
|
copy_tex: VecStorage<&'static CopyTexture>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) {
|
||||||
|
let mut state = fb.ctx.gl_state.borrow_mut();
|
||||||
|
let state = &mut *state;
|
||||||
|
let mut fill_rect = state.fill_rect.take();
|
||||||
|
let fill_rect = &mut *fill_rect;
|
||||||
|
let mut copy_tex = state.copy_tex.take();
|
||||||
|
let copy_tex = &mut *copy_tex;
|
||||||
|
let mut triangles = state.triangles.borrow_mut();
|
||||||
|
let triangles = &mut *triangles;
|
||||||
|
let width = fb.gl.width as f32;
|
||||||
|
let height = fb.gl.height as f32;
|
||||||
|
let mut i = 0;
|
||||||
|
while i < ops.len() {
|
||||||
|
macro_rules! has_ops {
|
||||||
|
() => {
|
||||||
|
fill_rect.is_not_empty() || copy_tex.is_not_empty()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
fill_rect.clear();
|
||||||
|
copy_tex.clear();
|
||||||
|
while i < ops.len() {
|
||||||
|
match &ops[i] {
|
||||||
|
GfxApiOpt::Sync => {
|
||||||
|
i += 1;
|
||||||
|
if has_ops!() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GfxApiOpt::Clear(c) => {
|
||||||
|
if has_ops!() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clear(&c.color);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
GfxApiOpt::FillRect(f) => {
|
||||||
|
fill_rect.push(f);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
GfxApiOpt::CopyTexture(c) => {
|
||||||
|
copy_tex.push(c);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fill_rect.is_not_empty() {
|
||||||
|
fill_rect.sort_unstable_by_key(|f| f.color);
|
||||||
|
let mut i = 0;
|
||||||
|
while i < fill_rect.len() {
|
||||||
|
triangles.clear();
|
||||||
|
let mut color = None;
|
||||||
|
while i < fill_rect.len() {
|
||||||
|
let fr = fill_rect[i];
|
||||||
|
match color {
|
||||||
|
None => color = Some(fr.color),
|
||||||
|
Some(c) if c == fr.color => {}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
let x1 = 2.0 * (fr.rect.x1 / width) - 1.0;
|
||||||
|
let x2 = 2.0 * (fr.rect.x2 / width) - 1.0;
|
||||||
|
let y1 = 2.0 * (fr.rect.y1 / height) - 1.0;
|
||||||
|
let y2 = 2.0 * (fr.rect.y2 / height) - 1.0;
|
||||||
|
triangles.extend_from_slice(&[
|
||||||
|
// triangle 1
|
||||||
|
x2, y1, // top right
|
||||||
|
x1, y1, // top left
|
||||||
|
x1, y2, // bottom left
|
||||||
|
// triangle 2
|
||||||
|
x2, y1, // top right
|
||||||
|
x1, y2, // bottom left
|
||||||
|
x2, y2, // bottom right
|
||||||
|
]);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if let Some(color) = color {
|
||||||
|
fill_boxes3(&fb.ctx, triangles, &color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for tex in &*copy_tex {
|
||||||
|
let x1 = 2.0 * (tex.target.x1 / width) - 1.0;
|
||||||
|
let y1 = 2.0 * (tex.target.y1 / height) - 1.0;
|
||||||
|
let x2 = 2.0 * (tex.target.x2 / width) - 1.0;
|
||||||
|
let y2 = 2.0 * (tex.target.y2 / height) - 1.0;
|
||||||
|
render_texture(
|
||||||
|
&fb.ctx,
|
||||||
|
&tex.tex.as_gl(),
|
||||||
|
tex.format,
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
x2,
|
||||||
|
y2,
|
||||||
|
&tex.source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(c: &Color) {
|
||||||
|
unsafe {
|
||||||
|
glClearColor(c.r, c.g, c.b, c.a);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_boxes3(ctx: &GlRenderContext, boxes: &[f32], color: &Color) {
|
||||||
|
unsafe {
|
||||||
|
glUseProgram(ctx.fill_prog.prog);
|
||||||
|
glUniform4f(ctx.fill_prog_color, color.r, color.g, color.b, color.a);
|
||||||
|
glVertexAttribPointer(
|
||||||
|
ctx.fill_prog_pos as _,
|
||||||
|
2,
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_FALSE,
|
||||||
|
0,
|
||||||
|
boxes.as_ptr() as _,
|
||||||
|
);
|
||||||
|
glEnableVertexAttribArray(ctx.fill_prog_pos as _);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() / 2) as _);
|
||||||
|
glDisableVertexAttribArray(ctx.fill_prog_pos as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_texture(
|
||||||
|
ctx: &GlRenderContext,
|
||||||
|
texture: &Texture,
|
||||||
|
format: &Format,
|
||||||
|
x1: f32,
|
||||||
|
y1: f32,
|
||||||
|
x2: f32,
|
||||||
|
y2: f32,
|
||||||
|
src: &BufferPoints,
|
||||||
|
) {
|
||||||
|
assert!(rc_eq(&ctx.ctx, &texture.ctx.ctx));
|
||||||
|
unsafe {
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
let target = image_target(texture.gl.external_only);
|
||||||
|
|
||||||
|
glBindTexture(target, texture.gl.tex);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
let progs = match texture.gl.external_only {
|
||||||
|
true => match &ctx.tex_external {
|
||||||
|
Some(p) => p,
|
||||||
|
_ => {
|
||||||
|
log::error!("Trying to render an external-only texture but context does not support the required extension");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => &ctx.tex_internal,
|
||||||
|
};
|
||||||
|
let prog = match format.has_alpha {
|
||||||
|
true => {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
&progs.alpha
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
&progs.solid
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
glUseProgram(prog.prog.prog);
|
||||||
|
|
||||||
|
glUniform1i(prog.tex, 0);
|
||||||
|
|
||||||
|
let texcoord = [
|
||||||
|
src.top_right.x,
|
||||||
|
src.top_right.y,
|
||||||
|
src.top_left.x,
|
||||||
|
src.top_left.y,
|
||||||
|
src.bottom_right.x,
|
||||||
|
src.bottom_right.y,
|
||||||
|
src.bottom_left.x,
|
||||||
|
src.bottom_left.y,
|
||||||
|
];
|
||||||
|
|
||||||
|
let pos = [
|
||||||
|
x2, y1, // top right
|
||||||
|
x1, y1, // top left
|
||||||
|
x2, y2, // bottom right
|
||||||
|
x1, y2, // bottom left
|
||||||
|
];
|
||||||
|
|
||||||
|
glVertexAttribPointer(
|
||||||
|
prog.texcoord as _,
|
||||||
|
2,
|
||||||
|
GL_FLOAT,
|
||||||
|
GL_FALSE,
|
||||||
|
0,
|
||||||
|
texcoord.as_ptr() as _,
|
||||||
|
);
|
||||||
|
glVertexAttribPointer(prog.pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(prog.texcoord as _);
|
||||||
|
glEnableVertexAttribArray(prog.pos as _);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(prog.texcoord as _);
|
||||||
|
glDisableVertexAttribArray(prog.pos as _);
|
||||||
|
|
||||||
|
glBindTexture(target, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn GfxTexture {
|
||||||
|
fn as_gl(&self) -> &Texture {
|
||||||
|
self.as_any()
|
||||||
|
.downcast_ref()
|
||||||
|
.expect("Non-gl texture passed into gl")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RenderError> for GfxError {
|
||||||
|
fn from(value: RenderError) -> Self {
|
||||||
|
Self(Box::new(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::render::{
|
crate::gfx_apis::gl::{
|
||||||
egl::sys::{
|
egl::sys::{
|
||||||
eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_DEBUG_MSG_CRITICAL_KHR,
|
eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_DEBUG_MSG_CRITICAL_KHR,
|
||||||
EGL_DEBUG_MSG_ERROR_KHR, EGL_DEBUG_MSG_INFO_KHR, EGL_DEBUG_MSG_WARN_KHR, EGL_NONE,
|
EGL_DEBUG_MSG_ERROR_KHR, EGL_DEBUG_MSG_INFO_KHR, EGL_DEBUG_MSG_WARN_KHR, EGL_NONE,
|
||||||
|
|
@ -27,11 +27,11 @@ pub mod display;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
|
|
||||||
pub(super) static PROCS: Lazy<ExtProc> = Lazy::new(ExtProc::load);
|
pub(crate) static PROCS: Lazy<ExtProc> = Lazy::new(ExtProc::load);
|
||||||
|
|
||||||
pub(super) static EXTS: Lazy<ClientExt> = Lazy::new(get_client_ext);
|
pub(crate) static EXTS: Lazy<ClientExt> = Lazy::new(get_client_ext);
|
||||||
|
|
||||||
pub fn init() -> Result<(), RenderError> {
|
pub(in crate::gfx_apis::gl) fn init() -> Result<(), RenderError> {
|
||||||
if !EXTS.contains(ClientExt::EXT_PLATFORM_BASE) {
|
if !EXTS.contains(ClientExt::EXT_PLATFORM_BASE) {
|
||||||
return Err(RenderError::ExtPlatformBase);
|
return Err(RenderError::ExtPlatformBase);
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
use {
|
use {
|
||||||
crate::render::{
|
crate::{
|
||||||
egl::{
|
gfx_api::ResetStatus,
|
||||||
display::EglDisplay,
|
gfx_apis::gl::{
|
||||||
sys::{eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE},
|
egl::{
|
||||||
PROCS,
|
display::EglDisplay,
|
||||||
|
sys::{
|
||||||
|
eglDestroyContext, eglMakeCurrent, EGLContext, EGLSurface, EGL_FALSE, EGL_TRUE,
|
||||||
|
},
|
||||||
|
PROCS,
|
||||||
|
},
|
||||||
|
ext::{DisplayExt, GlExt},
|
||||||
|
sys::{
|
||||||
|
GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB,
|
||||||
|
GL_UNKNOWN_CONTEXT_RESET_ARB,
|
||||||
|
},
|
||||||
|
RenderError,
|
||||||
},
|
},
|
||||||
ext::{DisplayExt, GlExt},
|
|
||||||
sys::{
|
|
||||||
GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB,
|
|
||||||
GL_UNKNOWN_CONTEXT_RESET_ARB,
|
|
||||||
},
|
|
||||||
RenderError, ResetStatus,
|
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
@ -58,7 +63,7 @@ impl EglContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_current<T, F: FnOnce() -> Result<T, RenderError>>(
|
pub(in crate::gfx_apis::gl) fn with_current<T, F: FnOnce() -> Result<T, RenderError>>(
|
||||||
&self,
|
&self,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<T, RenderError> {
|
) -> Result<T, RenderError> {
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::{formats, Format},
|
format::{formats, Format},
|
||||||
render::{
|
gfx_api::{GfxFormat, GfxModifier},
|
||||||
|
gfx_apis::gl::{
|
||||||
egl::{
|
egl::{
|
||||||
context::EglContext,
|
context::EglContext,
|
||||||
image::EglImage,
|
image::EglImage,
|
||||||
|
|
@ -35,29 +36,16 @@ use {
|
||||||
std::{ptr, rc::Rc},
|
std::{ptr, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EglFormat {
|
|
||||||
pub format: &'static Format,
|
|
||||||
pub implicit_external_only: bool,
|
|
||||||
pub modifiers: AHashMap<u64, EglModifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EglModifier {
|
|
||||||
pub modifier: u64,
|
|
||||||
pub external_only: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EglDisplay {
|
pub struct EglDisplay {
|
||||||
pub exts: DisplayExt,
|
pub exts: DisplayExt,
|
||||||
pub formats: Rc<AHashMap<u32, EglFormat>>,
|
pub formats: Rc<AHashMap<u32, GfxFormat>>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
pub dpy: EGLDisplay,
|
pub dpy: EGLDisplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EglDisplay {
|
impl EglDisplay {
|
||||||
pub fn create(drm: &Drm) -> Result<Rc<Self>, RenderError> {
|
pub(in crate::gfx_apis::gl) fn create(drm: &Drm) -> Result<Rc<Self>, RenderError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let gbm = match GbmDevice::new(drm) {
|
let gbm = match GbmDevice::new(drm) {
|
||||||
Ok(gbm) => gbm,
|
Ok(gbm) => gbm,
|
||||||
|
|
@ -107,7 +95,9 @@ impl EglDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_context(self: &Rc<Self>) -> Result<Rc<EglContext>, RenderError> {
|
pub(in crate::gfx_apis::gl) fn create_context(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Result<Rc<EglContext>, RenderError> {
|
||||||
let mut attrib = vec![EGL_CONTEXT_CLIENT_VERSION, 2];
|
let mut attrib = vec![EGL_CONTEXT_CLIENT_VERSION, 2];
|
||||||
if self
|
if self
|
||||||
.exts
|
.exts
|
||||||
|
|
@ -142,7 +132,10 @@ impl EglDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_dmabuf(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<EglImage>, RenderError> {
|
pub(in crate::gfx_apis::gl) fn import_dmabuf(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
buf: &DmaBuf,
|
||||||
|
) -> Result<Rc<EglImage>, RenderError> {
|
||||||
let format = match self.formats.get(&buf.format.drm) {
|
let format = match self.formats.get(&buf.format.drm) {
|
||||||
Some(fmt) => match fmt.modifiers.get(&buf.modifier) {
|
Some(fmt) => match fmt.modifiers.get(&buf.modifier) {
|
||||||
Some(fmt) => fmt,
|
Some(fmt) => fmt,
|
||||||
|
|
@ -235,7 +228,7 @@ impl Drop for EglDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, RenderError> {
|
unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, GfxFormat>, RenderError> {
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num);
|
let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num);
|
||||||
|
|
@ -255,7 +248,7 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result<AHashMap<u32, EglFormat>, Ren
|
||||||
let (modifiers, external_only) = query_modifiers(dpy, fmt, format)?;
|
let (modifiers, external_only) = query_modifiers(dpy, fmt, format)?;
|
||||||
res.insert(
|
res.insert(
|
||||||
format.drm,
|
format.drm,
|
||||||
EglFormat {
|
GfxFormat {
|
||||||
format,
|
format,
|
||||||
implicit_external_only: external_only,
|
implicit_external_only: external_only,
|
||||||
modifiers,
|
modifiers,
|
||||||
|
|
@ -270,7 +263,7 @@ unsafe fn query_modifiers(
|
||||||
dpy: EGLDisplay,
|
dpy: EGLDisplay,
|
||||||
gl_format: EGLint,
|
gl_format: EGLint,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
) -> Result<(AHashMap<u64, EglModifier>, bool), RenderError> {
|
) -> Result<(AHashMap<u64, GfxModifier>, bool), RenderError> {
|
||||||
let mut mods = vec![];
|
let mut mods = vec![];
|
||||||
let mut ext_only = vec![];
|
let mut ext_only = vec![];
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
|
|
@ -304,7 +297,7 @@ unsafe fn query_modifiers(
|
||||||
for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) {
|
for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) {
|
||||||
res.insert(
|
res.insert(
|
||||||
modifier as _,
|
modifier as _,
|
||||||
EglModifier {
|
GfxModifier {
|
||||||
modifier: modifier as _,
|
modifier: modifier as _,
|
||||||
external_only: ext_only == EGL_TRUE,
|
external_only: ext_only == EGL_TRUE,
|
||||||
},
|
},
|
||||||
|
|
@ -316,7 +309,7 @@ unsafe fn query_modifiers(
|
||||||
}
|
}
|
||||||
res.insert(
|
res.insert(
|
||||||
INVALID_MODIFIER,
|
INVALID_MODIFIER,
|
||||||
EglModifier {
|
GfxModifier {
|
||||||
modifier: INVALID_MODIFIER,
|
modifier: INVALID_MODIFIER,
|
||||||
external_only,
|
external_only,
|
||||||
},
|
},
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::render::egl::{
|
crate::gfx_apis::gl::egl::{
|
||||||
display::EglDisplay,
|
display::EglDisplay,
|
||||||
sys::{EGLImageKHR, EGL_FALSE},
|
sys::{EGLImageKHR, EGL_FALSE},
|
||||||
PROCS,
|
PROCS,
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use {crate::render::sys::GLenum, uapi::c};
|
use {crate::gfx_apis::gl::sys::GLenum, uapi::c};
|
||||||
|
|
||||||
pub type EGLint = i32;
|
pub type EGLint = i32;
|
||||||
pub type EGLenum = c::c_uint;
|
pub type EGLenum = c::c_uint;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
render::{
|
gfx_apis::gl::{
|
||||||
egl::sys::{eglQueryString, EGLDisplay, EGL_EXTENSIONS},
|
egl::sys::{eglQueryString, EGLDisplay, EGL_EXTENSIONS},
|
||||||
gl::sys::{glGetString, GL_EXTENSIONS},
|
gl::sys::{glGetString, GL_EXTENSIONS},
|
||||||
},
|
},
|
||||||
|
|
@ -47,6 +47,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ClientExt: u32 {
|
pub struct ClientExt: u32 {
|
||||||
const EXT_CLIENT_EXTENSION = 1 << 0;
|
const EXT_CLIENT_EXTENSION = 1 << 0;
|
||||||
const EXT_PLATFORM_BASE = 1 << 1;
|
const EXT_PLATFORM_BASE = 1 << 1;
|
||||||
|
|
@ -68,6 +69,7 @@ pub fn get_client_ext() -> ClientExt {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct DisplayExt: u32 {
|
pub struct DisplayExt: u32 {
|
||||||
const KHR_IMAGE_BASE = 1 << 0;
|
const KHR_IMAGE_BASE = 1 << 0;
|
||||||
const EXT_IMAGE_DMA_BUF_IMPORT = 1 << 1;
|
const EXT_IMAGE_DMA_BUF_IMPORT = 1 << 1;
|
||||||
|
|
@ -80,7 +82,7 @@ bitflags::bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
|
pub(crate) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
|
||||||
let map = [
|
let map = [
|
||||||
("EGL_KHR_image_base", DisplayExt::KHR_IMAGE_BASE),
|
("EGL_KHR_image_base", DisplayExt::KHR_IMAGE_BASE),
|
||||||
(
|
(
|
||||||
|
|
@ -116,6 +118,7 @@ pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GlExt: u32 {
|
pub struct GlExt: u32 {
|
||||||
const GL_OES_EGL_IMAGE = 1 << 0;
|
const GL_OES_EGL_IMAGE = 1 << 0;
|
||||||
const GL_OES_EGL_IMAGE_EXTERNAL = 1 << 1;
|
const GL_OES_EGL_IMAGE_EXTERNAL = 1 << 1;
|
||||||
31
src/gfx_apis/gl/gl/frame_buffer.rs
Normal file
31
src/gfx_apis/gl/gl/frame_buffer.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
use {
|
||||||
|
crate::gfx_apis::gl::{
|
||||||
|
egl::context::EglContext,
|
||||||
|
gl::{
|
||||||
|
render_buffer::GlRenderBuffer,
|
||||||
|
sys::{glDeleteFramebuffers, GLuint},
|
||||||
|
texture::GlTexture,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct GlFrameBuffer {
|
||||||
|
pub _rb: Option<Rc<GlRenderBuffer>>,
|
||||||
|
pub _tex: Option<Rc<GlTexture>>,
|
||||||
|
pub ctx: Rc<EglContext>,
|
||||||
|
pub width: i32,
|
||||||
|
pub height: i32,
|
||||||
|
pub fbo: GLuint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GlFrameBuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glDeleteFramebuffers(1, &self.fbo);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::render::{
|
crate::gfx_apis::gl::{
|
||||||
egl::context::EglContext,
|
egl::context::EglContext,
|
||||||
gl::{
|
gl::{
|
||||||
shader::GlShader,
|
shader::GlShader,
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct GlProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlProgram {
|
impl GlProgram {
|
||||||
pub unsafe fn from_shaders(
|
pub(in crate::gfx_apis::gl) unsafe fn from_shaders(
|
||||||
ctx: &Rc<EglContext>,
|
ctx: &Rc<EglContext>,
|
||||||
vert: &str,
|
vert: &str,
|
||||||
frag: &str,
|
frag: &str,
|
||||||
|
|
@ -31,7 +31,10 @@ impl GlProgram {
|
||||||
Self::link(&vert, &frag)
|
Self::link(&vert, &frag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn link(vert: &GlShader, frag: &GlShader) -> Result<Self, RenderError> {
|
pub(in crate::gfx_apis::gl) unsafe fn link(
|
||||||
|
vert: &GlShader,
|
||||||
|
frag: &GlShader,
|
||||||
|
) -> Result<Self, RenderError> {
|
||||||
let res = GlProgram {
|
let res = GlProgram {
|
||||||
_ctx: vert.ctx.clone(),
|
_ctx: vert.ctx.clone(),
|
||||||
prog: glCreateProgram(),
|
prog: glCreateProgram(),
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::render::{
|
crate::gfx_apis::gl::{
|
||||||
egl::{context::EglContext, image::EglImage, PROCS},
|
egl::{context::EglContext, image::EglImage, PROCS},
|
||||||
gl::{
|
gl::{
|
||||||
frame_buffer::GlFrameBuffer,
|
frame_buffer::GlFrameBuffer,
|
||||||
|
|
@ -22,7 +22,7 @@ pub struct GlRenderBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlRenderBuffer {
|
impl GlRenderBuffer {
|
||||||
pub 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>,
|
||||||
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
) -> Result<Rc<GlRenderBuffer>, RenderError> {
|
||||||
|
|
@ -41,7 +41,9 @@ impl GlRenderBuffer {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn create_framebuffer(self: &Rc<Self>) -> Result<GlFrameBuffer, RenderError> {
|
pub(in crate::gfx_apis::gl) unsafe fn create_framebuffer(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Result<GlFrameBuffer, RenderError> {
|
||||||
let mut fbo = 0;
|
let mut fbo = 0;
|
||||||
glGenFramebuffers(1, &mut fbo);
|
glGenFramebuffers(1, &mut fbo);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::render::{
|
crate::gfx_apis::gl::{
|
||||||
egl::context::EglContext,
|
egl::context::EglContext,
|
||||||
gl::sys::{
|
gl::sys::{
|
||||||
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum,
|
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum,
|
||||||
|
|
@ -17,7 +17,7 @@ pub struct GlShader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlShader {
|
impl GlShader {
|
||||||
pub unsafe fn compile(
|
pub(in crate::gfx_apis::gl) unsafe fn compile(
|
||||||
ctx: &Rc<EglContext>,
|
ctx: &Rc<EglContext>,
|
||||||
ty: GLenum,
|
ty: GLenum,
|
||||||
src: &str,
|
src: &str,
|
||||||
|
|
@ -28,7 +28,6 @@ pub const GL_FRAMEBUFFER: GLenum = 0x8D40;
|
||||||
pub const GL_LINEAR: GLint = 0x2601;
|
pub const GL_LINEAR: GLint = 0x2601;
|
||||||
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
pub const GL_LINK_STATUS: GLenum = 0x8B82;
|
||||||
pub const GL_RENDERBUFFER: GLenum = 0x8D41;
|
pub const GL_RENDERBUFFER: GLenum = 0x8D41;
|
||||||
pub const GL_SCISSOR_TEST: GLenum = 0x0C11;
|
|
||||||
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
pub const GL_TEXTURE0: GLenum = 0x84C0;
|
||||||
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
pub const GL_TEXTURE_2D: GLenum = 0x0DE1;
|
||||||
pub const GL_TEXTURE_EXTERNAL_OES: GLenum = 0x8D65;
|
pub const GL_TEXTURE_EXTERNAL_OES: GLenum = 0x8D65;
|
||||||
|
|
@ -106,7 +105,6 @@ extern "C" {
|
||||||
pixels: *const c::c_void,
|
pixels: *const c::c_void,
|
||||||
);
|
);
|
||||||
|
|
||||||
pub fn glScissor(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
|
|
||||||
pub fn glEnable(cap: GLenum);
|
pub fn glEnable(cap: GLenum);
|
||||||
pub fn glDisable(cap: GLenum);
|
pub fn glDisable(cap: GLenum);
|
||||||
pub fn glViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
|
pub fn glViewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei);
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
format::Format,
|
||||||
render::{
|
gfx_apis::gl::{
|
||||||
egl::{context::EglContext, image::EglImage, PROCS},
|
egl::{context::EglContext, image::EglImage, PROCS},
|
||||||
ext::GlExt,
|
ext::GlExt,
|
||||||
gl::sys::{
|
gl::sys::{
|
||||||
|
|
@ -17,7 +17,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GlTexture {
|
pub struct GlTexture {
|
||||||
pub(super) ctx: Rc<EglContext>,
|
pub(crate) ctx: Rc<EglContext>,
|
||||||
pub img: Option<Rc<EglImage>>,
|
pub img: Option<Rc<EglImage>>,
|
||||||
pub tex: GLuint,
|
pub tex: GLuint,
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
|
|
@ -33,7 +33,10 @@ pub fn image_target(external_only: bool) -> GLenum {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlTexture {
|
impl GlTexture {
|
||||||
pub fn import_img(ctx: &Rc<EglContext>, img: &Rc<EglImage>) -> Result<GlTexture, RenderError> {
|
pub(in crate::gfx_apis::gl) fn import_img(
|
||||||
|
ctx: &Rc<EglContext>,
|
||||||
|
img: &Rc<EglImage>,
|
||||||
|
) -> Result<GlTexture, RenderError> {
|
||||||
if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL) {
|
if !ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL) {
|
||||||
return Err(RenderError::ExternalUnsupported);
|
return Err(RenderError::ExternalUnsupported);
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +61,7 @@ impl GlTexture {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_shm(
|
pub(in crate::gfx_apis::gl) fn import_shm(
|
||||||
ctx: &Rc<EglContext>,
|
ctx: &Rc<EglContext>,
|
||||||
data: &[Cell<u8>],
|
data: &[Cell<u8>],
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
4
src/gfx_apis/gl/renderer.rs
Normal file
4
src/gfx_apis/gl/renderer.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub(super) mod context;
|
||||||
|
pub(super) mod framebuffer;
|
||||||
|
pub(super) mod image;
|
||||||
|
pub(super) mod texture;
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
render::{
|
gfx_api::{
|
||||||
egl::{
|
GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage, GfxTexture,
|
||||||
context::EglContext,
|
ResetStatus,
|
||||||
display::{EglDisplay, EglFormat},
|
},
|
||||||
},
|
gfx_apis::gl::{
|
||||||
|
egl::{context::EglContext, display::EglDisplay},
|
||||||
ext::GlExt,
|
ext::GlExt,
|
||||||
gl::{
|
gl::{
|
||||||
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
program::GlProgram, render_buffer::GlRenderBuffer, sys::GLint, texture::GlTexture,
|
||||||
},
|
},
|
||||||
renderer::{framebuffer::Framebuffer, image::Image},
|
renderer::{framebuffer::Framebuffer, image::Image},
|
||||||
RenderError, Texture,
|
GfxGlState, RenderError, Texture,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
|
|
@ -21,19 +22,20 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::{Cell, RefCell},
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
mem,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
uapi::ustr,
|
uapi::ustr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct TexProg {
|
pub(crate) struct TexProg {
|
||||||
pub(super) prog: GlProgram,
|
pub(crate) prog: GlProgram,
|
||||||
pub(super) pos: GLint,
|
pub(crate) pos: GLint,
|
||||||
pub(super) texcoord: GLint,
|
pub(crate) texcoord: GLint,
|
||||||
pub(super) tex: GLint,
|
pub(crate) tex: GLint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TexProg {
|
impl TexProg {
|
||||||
|
|
@ -47,40 +49,35 @@ impl TexProg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct TexProgs {
|
pub(crate) struct TexProgs {
|
||||||
pub alpha: TexProg,
|
pub alpha: TexProg,
|
||||||
pub solid: TexProg,
|
pub solid: TexProg,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderContext {
|
pub(in crate::gfx_apis::gl) struct GlRenderContext {
|
||||||
pub(super) ctx: Rc<EglContext>,
|
pub(crate) ctx: Rc<EglContext>,
|
||||||
pub gbm: Rc<GbmDevice>,
|
pub gbm: Rc<GbmDevice>,
|
||||||
|
|
||||||
pub(super) render_node: Rc<CString>,
|
pub(crate) render_node: Rc<CString>,
|
||||||
|
|
||||||
pub(super) tex_internal: TexProgs,
|
pub(crate) tex_internal: TexProgs,
|
||||||
pub(super) tex_external: Option<TexProgs>,
|
pub(crate) tex_external: Option<TexProgs>,
|
||||||
|
|
||||||
pub(super) fill_prog: GlProgram,
|
pub(crate) fill_prog: GlProgram,
|
||||||
pub(super) fill_prog_pos: GLint,
|
pub(crate) fill_prog_pos: GLint,
|
||||||
pub(super) fill_prog_color: GLint,
|
pub(crate) fill_prog_color: GLint,
|
||||||
|
|
||||||
|
pub(crate) gfx_ops: RefCell<Vec<GfxApiOpt>>,
|
||||||
|
pub(in crate::gfx_apis::gl) gl_state: RefCell<GfxGlState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for RenderContext {
|
impl Debug for GlRenderContext {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("RenderContext").finish_non_exhaustive()
|
f.debug_struct("RenderContext").finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
impl GlRenderContext {
|
||||||
pub enum ResetStatus {
|
|
||||||
Guilty,
|
|
||||||
Innocent,
|
|
||||||
Unknown,
|
|
||||||
Other(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderContext {
|
|
||||||
pub fn reset_status(&self) -> Option<ResetStatus> {
|
pub fn reset_status(&self) -> Option<ResetStatus> {
|
||||||
self.ctx.reset_status()
|
self.ctx.reset_status()
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +86,7 @@ impl RenderContext {
|
||||||
self.ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL)
|
self.ctx.ext.contains(GlExt::GL_OES_EGL_IMAGE_EXTERNAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
pub(in crate::gfx_apis::gl) fn from_drm_device(drm: &Drm) -> Result<Self, RenderError> {
|
||||||
let nodes = drm.get_nodes()?;
|
let nodes = drm.get_nodes()?;
|
||||||
let node = match nodes
|
let node = match nodes
|
||||||
.get(&NodeType::Render)
|
.get(&NodeType::Render)
|
||||||
|
|
@ -153,6 +150,9 @@ impl RenderContext {
|
||||||
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
fill_prog_pos: fill_prog.get_attrib_location(ustr!("pos")),
|
||||||
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
fill_prog_color: fill_prog.get_uniform_location(ustr!("color")),
|
||||||
fill_prog,
|
fill_prog,
|
||||||
|
|
||||||
|
gfx_ops: Default::default(),
|
||||||
|
gl_state: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,11 +160,11 @@ impl RenderContext {
|
||||||
self.render_node.clone()
|
self.render_node.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn formats(&self) -> Rc<AHashMap<u32, EglFormat>> {
|
pub fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
||||||
self.ctx.dpy.formats.clone()
|
self.ctx.dpy.formats.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dmabuf_fb(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Framebuffer>, RenderError> {
|
fn dmabuf_fb(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Framebuffer>, RenderError> {
|
||||||
self.ctx.with_current(|| unsafe {
|
self.ctx.with_current(|| unsafe {
|
||||||
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
||||||
let rb = GlRenderBuffer::from_image(&img, &self.ctx)?;
|
let rb = GlRenderBuffer::from_image(&img, &self.ctx)?;
|
||||||
|
|
@ -176,7 +176,7 @@ impl RenderContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dmabuf_img(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Image>, RenderError> {
|
fn dmabuf_img(self: &Rc<Self>, buf: &DmaBuf) -> Result<Rc<Image>, RenderError> {
|
||||||
self.ctx.with_current(|| {
|
self.ctx.with_current(|| {
|
||||||
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
let img = self.ctx.dpy.import_dmabuf(buf)?;
|
||||||
Ok(Rc::new(Image {
|
Ok(Rc::new(Image {
|
||||||
|
|
@ -186,7 +186,7 @@ impl RenderContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shmem_texture(
|
fn shmem_texture(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
data: &[Cell<u8>],
|
data: &[Cell<u8>],
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
|
|
@ -201,3 +201,57 @@ impl RenderContext {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GfxContext for GlRenderContext {
|
||||||
|
fn take_render_ops(&self) -> Vec<GfxApiOpt> {
|
||||||
|
mem::take(&mut self.gfx_ops.borrow_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_status(&self) -> Option<ResetStatus> {
|
||||||
|
self.reset_status()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supports_external_texture(&self) -> bool {
|
||||||
|
self.supports_external_texture()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_node(&self) -> Rc<CString> {
|
||||||
|
self.render_node()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn formats(&self) -> Rc<AHashMap<u32, GfxFormat>> {
|
||||||
|
self.formats()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dmabuf_fb(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||||
|
(&self)
|
||||||
|
.dmabuf_fb(buf)
|
||||||
|
.map(|w| w as Rc<dyn GfxFramebuffer>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dmabuf_img(self: Rc<Self>, buf: &DmaBuf) -> Result<Rc<dyn GfxImage>, GfxError> {
|
||||||
|
(&self)
|
||||||
|
.dmabuf_img(buf)
|
||||||
|
.map(|w| w as Rc<dyn GfxImage>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shmem_texture(
|
||||||
|
self: Rc<Self>,
|
||||||
|
data: &[Cell<u8>],
|
||||||
|
format: &'static Format,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
) -> Result<Rc<dyn GfxTexture>, GfxError> {
|
||||||
|
(&self)
|
||||||
|
.shmem_texture(data, format, width, height, stride)
|
||||||
|
.map(|w| w as Rc<dyn GfxTexture>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gbm(&self) -> &GbmDevice {
|
||||||
|
&self.gbm
|
||||||
|
}
|
||||||
|
}
|
||||||
331
src/gfx_apis/gl/renderer/framebuffer.rs
Normal file
331
src/gfx_apis/gl/renderer/framebuffer.rs
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
cursor::Cursor,
|
||||||
|
fixed::Fixed,
|
||||||
|
format::{Format, ARGB8888, XRGB8888},
|
||||||
|
gfx_api::{GfxFramebuffer, GfxTexture},
|
||||||
|
gfx_apis::gl::{
|
||||||
|
gl::{
|
||||||
|
frame_buffer::GlFrameBuffer,
|
||||||
|
sys::{
|
||||||
|
glBindFramebuffer, glClear, glClearColor, glViewport, GL_COLOR_BUFFER_BIT,
|
||||||
|
GL_FRAMEBUFFER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderer::context::GlRenderContext,
|
||||||
|
run_ops,
|
||||||
|
sys::{glBlendFunc, glFlush, glReadnPixels, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||||
|
},
|
||||||
|
rect::Rect,
|
||||||
|
renderer::{renderer_base::RendererBase, RenderResult, Renderer},
|
||||||
|
scale::Scale,
|
||||||
|
state::State,
|
||||||
|
tree::Node,
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
any::Any,
|
||||||
|
cell::Cell,
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Framebuffer {
|
||||||
|
pub(in crate::gfx_apis::gl) ctx: Rc<GlRenderContext>,
|
||||||
|
pub(in crate::gfx_apis::gl) gl: GlFrameBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Framebuffer {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Framebuffer").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Framebuffer {
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.clear_with(0.0, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) {
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
glClearColor(r, g, b, a);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_texture(
|
||||||
|
&self,
|
||||||
|
state: &State,
|
||||||
|
texture: &Rc<dyn GfxTexture>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
alpha: bool,
|
||||||
|
) {
|
||||||
|
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||||
|
ops.clear();
|
||||||
|
let scale = Scale::from_int(1);
|
||||||
|
let extents = Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap();
|
||||||
|
let mut renderer = Renderer {
|
||||||
|
base: RendererBase {
|
||||||
|
ops: &mut ops,
|
||||||
|
scaled: false,
|
||||||
|
scale,
|
||||||
|
scalef: 1.0,
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
on_output: false,
|
||||||
|
result: &mut RenderResult::default(),
|
||||||
|
logical_extents: extents,
|
||||||
|
physical_extents: extents,
|
||||||
|
};
|
||||||
|
let format = match alpha {
|
||||||
|
true => ARGB8888,
|
||||||
|
false => XRGB8888,
|
||||||
|
};
|
||||||
|
renderer
|
||||||
|
.base
|
||||||
|
.render_texture(texture, x, y, format, None, None, scale, i32::MAX, i32::MAX);
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
run_ops(self, &ops);
|
||||||
|
unsafe {
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_shm(
|
||||||
|
&self,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &Format,
|
||||||
|
shm: &[Cell<u8>],
|
||||||
|
) {
|
||||||
|
let y = self.gl.height - y - height;
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
glReadnPixels(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
format.gl_format as _,
|
||||||
|
format.gl_type as _,
|
||||||
|
shm.len() as _,
|
||||||
|
shm.as_ptr() as _,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_custom(&self, scale: Scale, f: &mut dyn FnMut(&mut RendererBase)) {
|
||||||
|
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||||
|
ops.clear();
|
||||||
|
let mut renderer = RendererBase {
|
||||||
|
ops: &mut ops,
|
||||||
|
scaled: scale != 1,
|
||||||
|
scale,
|
||||||
|
scalef: scale.to_f64(),
|
||||||
|
};
|
||||||
|
f(&mut renderer);
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
run_ops(self, &ops);
|
||||||
|
unsafe {
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
&self,
|
||||||
|
node: &dyn Node,
|
||||||
|
state: &State,
|
||||||
|
cursor_rect: Option<Rect>,
|
||||||
|
on_output: bool,
|
||||||
|
result: &mut RenderResult,
|
||||||
|
scale: Scale,
|
||||||
|
render_hardware_cursor: bool,
|
||||||
|
) {
|
||||||
|
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||||
|
ops.clear();
|
||||||
|
let mut renderer = Renderer {
|
||||||
|
base: RendererBase {
|
||||||
|
ops: &mut ops,
|
||||||
|
scaled: scale != 1,
|
||||||
|
scale,
|
||||||
|
scalef: scale.to_f64(),
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
on_output,
|
||||||
|
result,
|
||||||
|
logical_extents: node.node_absolute_position().at_point(0, 0),
|
||||||
|
physical_extents: Rect::new(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||||
|
};
|
||||||
|
node.node_render(&mut renderer, 0, 0, i32::MAX, i32::MAX);
|
||||||
|
if let Some(rect) = cursor_rect {
|
||||||
|
let seats = state.globals.lock_seats();
|
||||||
|
for seat in seats.values() {
|
||||||
|
if !render_hardware_cursor && seat.hardware_cursor() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(cursor) = seat.get_cursor() {
|
||||||
|
let (mut x, mut y) = seat.get_position();
|
||||||
|
if let Some(dnd_icon) = seat.dnd_icon() {
|
||||||
|
let extents = dnd_icon.extents.get().move_(
|
||||||
|
x.round_down() + dnd_icon.buf_x.get(),
|
||||||
|
y.round_down() + dnd_icon.buf_y.get(),
|
||||||
|
);
|
||||||
|
if extents.intersects(&rect) {
|
||||||
|
let (x, y) = rect.translate(extents.x1(), extents.y1());
|
||||||
|
renderer.render_surface(&dnd_icon, x, y, i32::MAX, i32::MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.tick();
|
||||||
|
x -= Fixed::from_int(rect.x1());
|
||||||
|
y -= Fixed::from_int(rect.y1());
|
||||||
|
cursor.render(&mut renderer, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
let c = state.theme.colors.background.get();
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
glClearColor(c.r, c.g, c.b, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
run_ops(self, &ops);
|
||||||
|
unsafe {
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale) {
|
||||||
|
let mut ops = self.ctx.gfx_ops.borrow_mut();
|
||||||
|
ops.clear();
|
||||||
|
let mut res = RenderResult::default();
|
||||||
|
let mut renderer = Renderer {
|
||||||
|
base: RendererBase {
|
||||||
|
ops: &mut ops,
|
||||||
|
scaled: scale != 1,
|
||||||
|
scale,
|
||||||
|
scalef: scale.to_f64(),
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
on_output: false,
|
||||||
|
result: &mut res,
|
||||||
|
logical_extents: Rect::new_empty(0, 0),
|
||||||
|
physical_extents: Rect::new(0, 0, self.gl.width, self.gl.height).unwrap(),
|
||||||
|
};
|
||||||
|
cursor.render_hardware_cursor(&mut renderer);
|
||||||
|
let _ = self.ctx.ctx.with_current(|| {
|
||||||
|
unsafe {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
||||||
|
glViewport(0, 0, self.gl.width, self.gl.height);
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
}
|
||||||
|
run_ops(self, &ops);
|
||||||
|
unsafe {
|
||||||
|
glFlush();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GfxFramebuffer for Framebuffer {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self) {
|
||||||
|
self.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) {
|
||||||
|
self.clear_with(r, g, b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_texture(
|
||||||
|
&self,
|
||||||
|
state: &State,
|
||||||
|
texture: &Rc<dyn GfxTexture>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
alpha: bool,
|
||||||
|
) {
|
||||||
|
self.copy_texture(state, texture, x, y, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_to_shm(
|
||||||
|
&self,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
format: &Format,
|
||||||
|
shm: &[Cell<u8>],
|
||||||
|
) {
|
||||||
|
self.copy_to_shm(x, y, width, height, format, shm)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_custom(&self, scale: Scale, f: &mut dyn FnMut(&mut RendererBase)) {
|
||||||
|
self.render_custom(scale, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(
|
||||||
|
&self,
|
||||||
|
node: &dyn Node,
|
||||||
|
state: &State,
|
||||||
|
cursor_rect: Option<Rect>,
|
||||||
|
on_output: bool,
|
||||||
|
result: &mut RenderResult,
|
||||||
|
scale: Scale,
|
||||||
|
render_hardware_cursor: bool,
|
||||||
|
) {
|
||||||
|
self.render(
|
||||||
|
node,
|
||||||
|
state,
|
||||||
|
cursor_rect,
|
||||||
|
on_output,
|
||||||
|
result,
|
||||||
|
scale,
|
||||||
|
render_hardware_cursor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale) {
|
||||||
|
self.render_hardware_cursor(cursor, state, scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/gfx_apis/gl/renderer/image.rs
Normal file
68
src/gfx_apis/gl/renderer/image.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
gfx_api::{GfxError, GfxFramebuffer, GfxImage, GfxTexture},
|
||||||
|
gfx_apis::gl::{
|
||||||
|
egl::image::EglImage,
|
||||||
|
gl::{render_buffer::GlRenderBuffer, texture::GlTexture},
|
||||||
|
Framebuffer, GlRenderContext, RenderError, Texture,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Image {
|
||||||
|
pub(in crate::gfx_apis::gl) ctx: Rc<GlRenderContext>,
|
||||||
|
pub(in crate::gfx_apis::gl) gl: Rc<EglImage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn width(&self) -> i32 {
|
||||||
|
self.gl.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> i32 {
|
||||||
|
self.gl.height
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_texture(self: &Rc<Self>) -> Result<Rc<Texture>, RenderError> {
|
||||||
|
Ok(Rc::new(Texture {
|
||||||
|
ctx: self.ctx.clone(),
|
||||||
|
gl: GlTexture::import_img(&self.ctx.ctx, &self.gl)?,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_framebuffer(&self) -> Result<Rc<Framebuffer>, RenderError> {
|
||||||
|
self.ctx.ctx.with_current(|| unsafe {
|
||||||
|
let rb = GlRenderBuffer::from_image(&self.gl, &self.ctx.ctx)?;
|
||||||
|
let fb = rb.create_framebuffer()?;
|
||||||
|
Ok(Rc::new(Framebuffer {
|
||||||
|
ctx: self.ctx.clone(),
|
||||||
|
gl: fb,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GfxImage for Image {
|
||||||
|
fn to_framebuffer(self: Rc<Self>) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||||
|
(*self)
|
||||||
|
.to_framebuffer()
|
||||||
|
.map(|v| v as Rc<dyn GfxFramebuffer>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_texture(self: Rc<Self>) -> Result<Rc<dyn GfxTexture>, GfxError> {
|
||||||
|
(&self)
|
||||||
|
.to_texture()
|
||||||
|
.map(|v| v as Rc<dyn GfxTexture>)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> i32 {
|
||||||
|
self.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> i32 {
|
||||||
|
self.height()
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/gfx_apis/gl/renderer/texture.rs
Normal file
46
src/gfx_apis/gl/renderer/texture.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
gfx_api::GfxTexture,
|
||||||
|
gfx_apis::gl::{gl::texture::GlTexture, renderer::context::GlRenderContext},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
any::Any,
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Texture {
|
||||||
|
pub(in crate::gfx_apis::gl) ctx: Rc<GlRenderContext>,
|
||||||
|
pub(in crate::gfx_apis::gl) gl: GlTexture,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Texture {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Texture").finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Texture {
|
||||||
|
pub fn width(&self) -> i32 {
|
||||||
|
self.gl.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> i32 {
|
||||||
|
self.gl.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GfxTexture for Texture {
|
||||||
|
fn width(&self) -> i32 {
|
||||||
|
self.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> i32 {
|
||||||
|
self.height()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -277,7 +277,7 @@ impl JayCompositor {
|
||||||
.render_ctx_watchers
|
.render_ctx_watchers
|
||||||
.set((self.client.id, req.id), ctx.clone());
|
.set((self.client.id, req.id), ctx.clone());
|
||||||
let rctx = self.client.state.render_ctx.get();
|
let rctx = self.client.state.render_ctx.get();
|
||||||
ctx.send_render_ctx(rctx.as_ref());
|
ctx.send_render_ctx(rctx);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
|
gfx_api::GfxContext,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
render::RenderContext,
|
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
|
@ -21,10 +21,10 @@ pub struct JayRenderCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JayRenderCtx {
|
impl JayRenderCtx {
|
||||||
pub fn send_render_ctx(&self, ctx: Option<&Rc<RenderContext>>) {
|
pub fn send_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
|
||||||
let mut fd = None;
|
let mut fd = None;
|
||||||
if let Some(ctx) = ctx {
|
if let Some(ctx) = ctx {
|
||||||
match ctx.gbm.drm.dup_render() {
|
match ctx.gbm().drm.dup_render() {
|
||||||
Ok(d) => fd = Some(d.fd().clone()),
|
Ok(d) => fd = Some(d.fd().clone()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Could not dup drm fd: {}", ErrorFmt(e));
|
log::error!("Could not dup drm fd: {}", ErrorFmt(e));
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
|
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
||||||
ifs::jay_output::JayOutput,
|
ifs::jay_output::JayOutput,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
render::{Framebuffer, RenderContext, RenderError, Texture},
|
|
||||||
tree::{OutputNode, WorkspaceNodeId},
|
tree::{OutputNode, WorkspaceNodeId},
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
|
|
@ -60,7 +60,7 @@ struct Pending {
|
||||||
|
|
||||||
struct ScreencastBuffer {
|
struct ScreencastBuffer {
|
||||||
dmabuf: DmaBuf,
|
dmabuf: DmaBuf,
|
||||||
fb: Rc<Framebuffer>,
|
fb: Rc<dyn GfxFramebuffer>,
|
||||||
free: bool,
|
free: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ impl JayScreencast {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_texture(&self, on: &OutputNode, texture: &Texture) {
|
pub fn copy_texture(&self, on: &OutputNode, texture: &Rc<dyn GfxTexture>) {
|
||||||
if !self.running.get() {
|
if !self.running.get() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ impl JayScreencast {
|
||||||
self.client.event(Destroyed { self_id: self.id });
|
self.client.event(Destroyed { self_id: self.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn realloc(&self, ctx: &Rc<RenderContext>) -> Result<(), JayScreencastError> {
|
pub fn realloc(&self, ctx: &Rc<dyn GfxContext>) -> Result<(), JayScreencastError> {
|
||||||
let mut buffers = vec![];
|
let mut buffers = vec![];
|
||||||
if let Some(output) = self.output.get() {
|
if let Some(output) = self.output.get() {
|
||||||
let mode = output.global.mode.get();
|
let mode = output.global.mode.get();
|
||||||
|
|
@ -207,8 +207,10 @@ impl JayScreencast {
|
||||||
if self.linear.get() {
|
if self.linear.get() {
|
||||||
flags |= GBM_BO_USE_LINEAR;
|
flags |= GBM_BO_USE_LINEAR;
|
||||||
}
|
}
|
||||||
let buffer = ctx.gbm.create_bo(mode.width, mode.height, &format, flags)?;
|
let buffer = ctx
|
||||||
let fb = ctx.dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
|
.gbm()
|
||||||
|
.create_bo(mode.width, mode.height, &format, flags)?;
|
||||||
|
let fb = ctx.clone().dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
|
||||||
buffers.push(ScreencastBuffer {
|
buffers.push(ScreencastBuffer {
|
||||||
dmabuf: buffer.dmabuf().clone(),
|
dmabuf: buffer.dmabuf().clone(),
|
||||||
fb,
|
fb,
|
||||||
|
|
@ -444,7 +446,7 @@ pub enum JayScreencastError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
GbmError(#[from] GbmError),
|
GbmError(#[from] GbmError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
RenderError(#[from] RenderError),
|
GfxError(#[from] GfxError),
|
||||||
}
|
}
|
||||||
efrom!(JayScreencastError, MsgParserError);
|
efrom!(JayScreencastError, MsgParserError);
|
||||||
efrom!(JayScreencastError, ClientError);
|
efrom!(JayScreencastError, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ use {
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
clientmem::{ClientMem, ClientMemError, ClientMemOffset},
|
clientmem::{ClientMem, ClientMemError, ClientMemOffset},
|
||||||
format::Format,
|
format::Format,
|
||||||
|
gfx_api::{GfxError, GfxFramebuffer, GfxImage, GfxTexture},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Framebuffer, Image, RenderError, Texture},
|
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
|
|
@ -25,7 +25,7 @@ use {
|
||||||
|
|
||||||
pub enum WlBufferStorage {
|
pub enum WlBufferStorage {
|
||||||
Shm { mem: ClientMemOffset, stride: i32 },
|
Shm { mem: ClientMemOffset, stride: i32 },
|
||||||
Dmabuf(Rc<Image>),
|
Dmabuf(Rc<dyn GfxImage>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WlBuffer {
|
pub struct WlBuffer {
|
||||||
|
|
@ -37,8 +37,8 @@ pub struct WlBuffer {
|
||||||
dmabuf: Option<DmaBuf>,
|
dmabuf: Option<DmaBuf>,
|
||||||
render_ctx_version: Cell<u32>,
|
render_ctx_version: Cell<u32>,
|
||||||
pub storage: RefCell<Option<WlBufferStorage>>,
|
pub storage: RefCell<Option<WlBufferStorage>>,
|
||||||
pub texture: CloneCell<Option<Rc<Texture>>>,
|
pub texture: CloneCell<Option<Rc<dyn GfxTexture>>>,
|
||||||
pub famebuffer: CloneCell<Option<Rc<Framebuffer>>>,
|
pub famebuffer: CloneCell<Option<Rc<dyn GfxFramebuffer>>>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
|
|
@ -55,7 +55,7 @@ impl WlBuffer {
|
||||||
client: &Rc<Client>,
|
client: &Rc<Client>,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
dmabuf: DmaBuf,
|
dmabuf: DmaBuf,
|
||||||
img: &Rc<Image>,
|
img: &Rc<dyn GfxImage>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let width = img.width();
|
let width = img.width();
|
||||||
let height = img.height();
|
let height = img.height();
|
||||||
|
|
@ -165,7 +165,7 @@ impl WlBuffer {
|
||||||
}
|
}
|
||||||
WlBufferStorage::Dmabuf(img) => {
|
WlBufferStorage::Dmabuf(img) => {
|
||||||
if self.texture.get().is_none() {
|
if self.texture.get().is_none() {
|
||||||
self.texture.set(Some(img.to_texture()?));
|
self.texture.set(Some(img.clone().to_texture()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +184,7 @@ impl WlBuffer {
|
||||||
}
|
}
|
||||||
WlBufferStorage::Dmabuf(img) => {
|
WlBufferStorage::Dmabuf(img) => {
|
||||||
if self.famebuffer.get().is_none() {
|
if self.famebuffer.get().is_none() {
|
||||||
self.famebuffer.set(Some(img.to_framebuffer()?));
|
self.famebuffer.set(Some(img.clone().to_framebuffer()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,14 +225,13 @@ pub enum WlBufferError {
|
||||||
StrideTooSmall,
|
StrideTooSmall,
|
||||||
#[error("Could not access the client memory")]
|
#[error("Could not access the client memory")]
|
||||||
ClientMemError(#[source] Box<ClientMemError>),
|
ClientMemError(#[source] Box<ClientMemError>),
|
||||||
#[error("GLES could not import the client image")]
|
#[error("The graphics library could not import the client image")]
|
||||||
RenderError(#[source] Box<RenderError>),
|
GfxError(#[from] GfxError),
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
MsgParserError(#[source] Box<MsgParserError>),
|
MsgParserError(#[source] Box<MsgParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<ClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(WlBufferError, ClientMemError);
|
efrom!(WlBufferError, ClientMemError);
|
||||||
efrom!(WlBufferError, RenderError);
|
|
||||||
efrom!(WlBufferError, MsgParserError);
|
efrom!(WlBufferError, MsgParserError);
|
||||||
efrom!(WlBufferError, ClientError);
|
efrom!(WlBufferError, ClientError);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
|
gfx_api::GfxError,
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::wl_buffer::WlBuffer,
|
ifs::wl_buffer::WlBuffer,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
render::RenderError,
|
|
||||||
utils::buffd::{MsgParser, MsgParserError},
|
utils::buffd::{MsgParser, MsgParserError},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::{DmaBuf, DmaBufPlane},
|
dmabuf::{DmaBuf, DmaBufPlane},
|
||||||
|
|
@ -190,7 +190,7 @@ pub enum WlDrmError {
|
||||||
#[error("The format {0} is not supported")]
|
#[error("The format {0} is not supported")]
|
||||||
InvalidFormat(u32),
|
InvalidFormat(u32),
|
||||||
#[error("Could not import the buffer")]
|
#[error("Could not import the buffer")]
|
||||||
ImportError(#[from] RenderError),
|
ImportError(#[from] GfxError),
|
||||||
}
|
}
|
||||||
efrom!(WlDrmError, ClientError);
|
efrom!(WlDrmError, ClientError);
|
||||||
efrom!(WlDrmError, MsgParserError);
|
efrom!(WlDrmError, MsgParserError);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use {
|
||||||
backend,
|
backend,
|
||||||
client::{Client, ClientError, ClientId},
|
client::{Client, ClientError, ClientId},
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
|
gfx_api::{GfxFramebuffer, GfxTexture},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::WlBufferStorage, wl_surface::WlSurface,
|
wl_buffer::WlBufferStorage, wl_surface::WlSurface,
|
||||||
|
|
@ -11,7 +12,6 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Framebuffer, Texture},
|
|
||||||
state::{ConnectorData, State},
|
state::{ConnectorData, State},
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::OutputNode,
|
tree::OutputNode,
|
||||||
|
|
@ -199,7 +199,7 @@ impl WlOutputGlobal {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) {
|
pub fn perform_screencopies(&self, fb: &dyn GfxFramebuffer, tex: &Rc<dyn GfxTexture>) {
|
||||||
if self.pending_captures.is_empty() {
|
if self.pending_captures.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -887,7 +887,7 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut bindings = self.bindings.borrow_mut();
|
let mut bindings = self.bindings.borrow_mut();
|
||||||
let bindings = bindings.entry(client.id).or_insert_with(Default::default);
|
let bindings = bindings.entry(client.id).or_default();
|
||||||
bindings.insert(id, obj.clone());
|
bindings.insert(id, obj.clone());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use {
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
client::{Client, ClientError, RequestParser},
|
client::{Client, ClientError, RequestParser},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::{BufferPoint, BufferPoints},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::WlBuffer,
|
wl_buffer::WlBuffer,
|
||||||
wl_callback::WlCallback,
|
wl_callback::WlCallback,
|
||||||
|
|
@ -38,7 +39,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase, OutputNode,
|
FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase, OutputNode,
|
||||||
ToplevelNode,
|
ToplevelNode,
|
||||||
|
|
@ -101,20 +102,6 @@ impl Transform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
struct BufferPoint {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
struct BufferPoints {
|
|
||||||
top_right: BufferPoint,
|
|
||||||
top_left: BufferPoint,
|
|
||||||
bottom_right: BufferPoint,
|
|
||||||
bottom_left: BufferPoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Transform {
|
impl Transform {
|
||||||
fn apply_inv_sized(self, x1: f32, y1: f32, width: f32, height: f32) -> BufferPoints {
|
fn apply_inv_sized(self, x1: f32, y1: f32, width: f32, height: f32) -> BufferPoints {
|
||||||
let x2 = x1 + width;
|
let x2 = x1 + width;
|
||||||
|
|
@ -237,7 +224,7 @@ pub struct WlSurface {
|
||||||
input_region: Cell<Option<Rc<Region>>>,
|
input_region: Cell<Option<Rc<Region>>>,
|
||||||
opaque_region: Cell<Option<Rc<Region>>>,
|
opaque_region: Cell<Option<Rc<Region>>>,
|
||||||
buffer_points: RefCell<BufferPoints>,
|
buffer_points: RefCell<BufferPoints>,
|
||||||
pub buffer_points_norm: RefCell<[f32; 8]>,
|
pub buffer_points_norm: RefCell<BufferPoints>,
|
||||||
buffer_transform: Cell<Transform>,
|
buffer_transform: Cell<Transform>,
|
||||||
buffer_scale: Cell<i32>,
|
buffer_scale: Cell<i32>,
|
||||||
src_rect: Cell<Option<[Fixed; 4]>>,
|
src_rect: Cell<Option<[Fixed; 4]>>,
|
||||||
|
|
@ -817,35 +804,12 @@ impl WlSurface {
|
||||||
.buffer_transform
|
.buffer_transform
|
||||||
.get()
|
.get()
|
||||||
.apply_inv_sized(0.0, 0.0, 1.0, 1.0);
|
.apply_inv_sized(0.0, 0.0, 1.0, 1.0);
|
||||||
let points = &*buffer_points;
|
*buffer_points_norm = *buffer_points;
|
||||||
*buffer_points_norm = [
|
|
||||||
points.top_right.x,
|
|
||||||
points.top_right.y,
|
|
||||||
points.top_left.x,
|
|
||||||
points.top_left.y,
|
|
||||||
points.bottom_right.x,
|
|
||||||
points.bottom_right.y,
|
|
||||||
points.bottom_left.x,
|
|
||||||
points.bottom_left.y,
|
|
||||||
];
|
|
||||||
} else {
|
} else {
|
||||||
let width = buffer.rect.width() as f32;
|
*buffer_points_norm = buffer_points
|
||||||
let height = buffer.rect.height() as f32;
|
.norm(buffer.rect.width() as f32, buffer.rect.height() as f32);
|
||||||
let points = &*buffer_points;
|
if !buffer_points_norm.is_leq_1() {
|
||||||
*buffer_points_norm = [
|
return Err(WlSurfaceError::ViewportOutsideBuffer);
|
||||||
points.top_right.x / width,
|
|
||||||
points.top_right.y / height,
|
|
||||||
points.top_left.x / width,
|
|
||||||
points.top_left.y / height,
|
|
||||||
points.bottom_right.x / width,
|
|
||||||
points.bottom_right.y / height,
|
|
||||||
points.bottom_left.x / width,
|
|
||||||
points.bottom_left.y / height,
|
|
||||||
];
|
|
||||||
for &v in buffer_points_norm.iter() {
|
|
||||||
if v > 1.0 {
|
|
||||||
return Err(WlSurfaceError::ViewportOutsideBuffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1134,8 +1098,15 @@ impl Node for WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
renderer.render_surface(self, x, y);
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
|
renderer.render_surface(self, x, y, max_width, max_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_client(&self) -> Option<Rc<Client>> {
|
fn node_client(&self) -> Option<Rc<Client>> {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
ifs::{wl_seat::WlSeatGlobal, wl_surface::WlSurface},
|
ifs::{wl_seat::WlSeatGlobal, wl_surface::WlSurface},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
tree::{Node, NodeVisitorBase, OutputNode},
|
tree::{Node, NodeVisitorBase, OutputNode},
|
||||||
},
|
},
|
||||||
|
|
@ -76,16 +76,28 @@ impl Cursor for CursorSurface {
|
||||||
let (hot_x, hot_y) = (Fixed::from_int(hot_x), Fixed::from_int(hot_y));
|
let (hot_x, hot_y) = (Fixed::from_int(hot_x), Fixed::from_int(hot_y));
|
||||||
let x = ((x - hot_x).to_f64() * scale).round() as _;
|
let x = ((x - hot_x).to_f64() * scale).round() as _;
|
||||||
let y = ((y - hot_y).to_f64() * scale).round() as _;
|
let y = ((y - hot_y).to_f64() * scale).round() as _;
|
||||||
renderer.render_surface_scaled(&self.surface, x, y, None);
|
renderer.render_surface_scaled(&self.surface, x, y, None, i32::MAX, i32::MAX);
|
||||||
} else {
|
} else {
|
||||||
renderer.render_surface(&self.surface, x_int - hot_x, y_int - hot_y);
|
renderer.render_surface(
|
||||||
|
&self.surface,
|
||||||
|
x_int - hot_x,
|
||||||
|
y_int - hot_y,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
fn render_hardware_cursor(&self, renderer: &mut Renderer) {
|
||||||
let extents = self.surface.extents.get();
|
let extents = self.surface.extents.get();
|
||||||
renderer.render_surface(&self.surface, -extents.x1(), -extents.y1());
|
renderer.render_surface(
|
||||||
|
&self.surface,
|
||||||
|
-extents.x1(),
|
||||||
|
-extents.y1(),
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
|
|
||||||
struct FrameRequests;
|
struct FrameRequests;
|
||||||
impl NodeVisitorBase for FrameRequests {
|
impl NodeVisitorBase for FrameRequests {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
wl_surface::{x_surface::XSurface, WlSurface, WlSurfaceError},
|
wl_surface::{x_surface::XSurface, WlSurface, WlSurfaceError},
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode,
|
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode,
|
||||||
|
|
@ -334,8 +334,15 @@ impl Node for Xwindow {
|
||||||
FindTreeResult::Other
|
FindTreeResult::Other
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
renderer.render_surface(&self.x.surface, x, y)
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
|
renderer.render_surface(&self.x.surface, x, y, max_width, max_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_client(&self) -> Option<Rc<Client>> {
|
fn node_client(&self) -> Option<Rc<Client>> {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode, WorkspaceNode},
|
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode, WorkspaceNode},
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
|
|
@ -308,8 +308,15 @@ impl Node for XdgPopup {
|
||||||
self.xdg.find_tree_at(x, y, tree)
|
self.xdg.find_tree_at(x, y, tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
|
renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_client(&self) -> Option<Rc<Client>> {
|
fn node_client(&self) -> Option<Rc<Client>> {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData,
|
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData,
|
||||||
|
|
@ -425,8 +425,15 @@ impl Node for XdgToplevel {
|
||||||
self.xdg.find_tree_at(x, y, tree)
|
self.xdg.find_tree_at(x, y, tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
renderer.render_xdg_surface(&self.xdg, x, y)
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
|
renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_client(&self) -> Option<Rc<Client>> {
|
fn node_client(&self) -> Option<Rc<Client>> {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, OutputNode},
|
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, OutputNode},
|
||||||
utils::{
|
utils::{
|
||||||
bitflags::BitflagsExt,
|
bitflags::BitflagsExt,
|
||||||
|
|
@ -394,7 +394,14 @@ impl Node for ZwlrLayerSurfaceV1 {
|
||||||
self.surface.find_tree_at_(x, y, tree)
|
self.surface.find_tree_at_(x, y, tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_layer_surface(self, x, y);
|
renderer.render_layer_surface(self, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const TOP_RIGHT: u32 = 7;
|
||||||
const BOTTOM_RIGHT: u32 = 8;
|
const BOTTOM_RIGHT: u32 = 8;
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
#[derive(Default)]
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
pub struct Edge: u32 {
|
pub struct Edge: u32 {
|
||||||
const TOP = 1 << 0;
|
const TOP = 1 << 0;
|
||||||
const BOTTOM = 1 << 1;
|
const BOTTOM = 1 << 1;
|
||||||
|
|
@ -53,7 +53,7 @@ impl Edge {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
#[derive(Default)]
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
pub struct CA: u32 {
|
pub struct CA: u32 {
|
||||||
const NONE = 0;
|
const NONE = 0;
|
||||||
const SLIDE_X = 1;
|
const SLIDE_X = 1;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientError,
|
client::ClientError,
|
||||||
|
gfx_api::GfxError,
|
||||||
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
ifs::{wl_buffer::WlBuffer, zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
render::RenderError,
|
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
|
@ -228,7 +228,7 @@ pub enum ZwpLinuxBufferParamsV1Error {
|
||||||
#[error("Plane {0} was not set")]
|
#[error("Plane {0} was not set")]
|
||||||
MissingPlane(usize),
|
MissingPlane(usize),
|
||||||
#[error("Could not import the buffer")]
|
#[error("Could not import the buffer")]
|
||||||
ImportError(#[from] RenderError),
|
ImportError(#[from] GfxError),
|
||||||
}
|
}
|
||||||
efrom!(ZwpLinuxBufferParamsV1Error, ClientError);
|
efrom!(ZwpLinuxBufferParamsV1Error, ClientError);
|
||||||
efrom!(ZwpLinuxBufferParamsV1Error, MsgParserError);
|
efrom!(ZwpLinuxBufferParamsV1Error, MsgParserError);
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@ use {
|
||||||
},
|
},
|
||||||
compositor::TestFuture,
|
compositor::TestFuture,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::GfxError,
|
||||||
|
gfx_apis::create_gfx_context,
|
||||||
it::test_error::TestResult,
|
it::test_error::TestResult,
|
||||||
render::{RenderContext, RenderError},
|
|
||||||
state::State,
|
state::State,
|
||||||
time::now_usec,
|
time::now_usec,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -33,7 +34,7 @@ pub enum TestBackendError {
|
||||||
#[error("Could not open drm node {0}")]
|
#[error("Could not open drm node {0}")]
|
||||||
OpenDrmNode(String, #[source] OsError),
|
OpenDrmNode(String, #[source] OsError),
|
||||||
#[error("Could not create a render context")]
|
#[error("Could not create a render context")]
|
||||||
RenderContext(#[source] RenderError),
|
RenderContext(#[source] GfxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestBackend {
|
pub struct TestBackend {
|
||||||
|
|
@ -177,11 +178,11 @@ impl TestBackend {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let drm = Drm::open_existing(file);
|
let drm = Drm::open_existing(file);
|
||||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
let ctx = match create_gfx_context(&drm) {
|
||||||
Ok(ctx) => ctx,
|
Ok(ctx) => ctx,
|
||||||
Err(e) => return Err(TestBackendError::RenderContext(e)),
|
Err(e) => return Err(TestBackendError::RenderContext(e)),
|
||||||
};
|
};
|
||||||
self.state.set_render_ctx(Some(&Rc::new(ctx)));
|
self.state.set_render_ctx(Some(ctx));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ impl Session {
|
||||||
LOGIND_NAME,
|
LOGIND_NAME,
|
||||||
&self.session_path,
|
&self.session_path,
|
||||||
org::freedesktop::login1::session::TakeDevice { major, minor },
|
org::freedesktop::login1::session::TakeDevice { major, minor },
|
||||||
move |r| f(r),
|
f,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ impl Session {
|
||||||
.handle_signal::<org::freedesktop::login1::session::PauseDevice, _>(
|
.handle_signal::<org::freedesktop::login1::session::PauseDevice, _>(
|
||||||
Some(LOGIND_NAME),
|
Some(LOGIND_NAME),
|
||||||
Some(&self.session_path),
|
Some(&self.session_path),
|
||||||
move |v| f(v),
|
f,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ impl Session {
|
||||||
LOGIND_NAME,
|
LOGIND_NAME,
|
||||||
&self.seat,
|
&self.seat,
|
||||||
org::freedesktop::login1::seat::SwitchTo { vtnr },
|
org::freedesktop::login1::seat::SwitchTo { vtnr },
|
||||||
|r| f(r),
|
f,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ mod edid;
|
||||||
mod fixed;
|
mod fixed;
|
||||||
mod forker;
|
mod forker;
|
||||||
mod format;
|
mod format;
|
||||||
|
mod gfx_api;
|
||||||
|
mod gfx_apis;
|
||||||
mod globals;
|
mod globals;
|
||||||
mod ifs;
|
mod ifs;
|
||||||
mod io_uring;
|
mod io_uring;
|
||||||
|
|
@ -75,7 +77,7 @@ mod pango;
|
||||||
mod pipewire;
|
mod pipewire;
|
||||||
mod portal;
|
mod portal;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod render;
|
mod renderer;
|
||||||
mod scale;
|
mod scale;
|
||||||
mod screenshoter;
|
mod screenshoter;
|
||||||
mod sighand;
|
mod sighand;
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ impl PwClientNode {
|
||||||
f.write_int(-1);
|
f.write_int(-1);
|
||||||
// n_buffers
|
// n_buffers
|
||||||
f.write_uint(buffers.len() as _);
|
f.write_uint(buffers.len() as _);
|
||||||
for buffer in buffers.deref() {
|
for buffer in buffers {
|
||||||
// n_datas
|
// n_datas
|
||||||
f.write_uint(buffer.planes.len() as _);
|
f.write_uint(buffer.planes.len() as _);
|
||||||
for plane in &buffer.planes {
|
for plane in &buffer.planes {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
gfx_apis::create_gfx_context,
|
||||||
ifs::wl_seat::POINTER,
|
ifs::wl_seat::POINTER,
|
||||||
portal::{
|
portal::{
|
||||||
ptl_render_ctx::PortalRenderCtx, ptl_screencast::ScreencastSession,
|
ptl_render_ctx::PortalRenderCtx, ptl_screencast::ScreencastSession,
|
||||||
ptr_gui::WindowData, PortalState,
|
ptr_gui::WindowData, PortalState,
|
||||||
},
|
},
|
||||||
render::RenderContext,
|
|
||||||
utils::{
|
utils::{
|
||||||
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt, oserror::OsError,
|
errorfmt::ErrorFmt, oserror::OsError,
|
||||||
|
|
@ -169,7 +169,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
||||||
}
|
}
|
||||||
if self.render_ctx.get().is_none() {
|
if self.render_ctx.get().is_none() {
|
||||||
let drm = Drm::open_existing(fd);
|
let drm = Drm::open_existing(fd);
|
||||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
let ctx = match create_gfx_context(&drm) {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
|
|
@ -179,10 +179,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let ctx = Rc::new(PortalRenderCtx {
|
let ctx = Rc::new(PortalRenderCtx { dev_id, ctx });
|
||||||
dev_id,
|
|
||||||
ctx: Rc::new(ctx),
|
|
||||||
});
|
|
||||||
self.render_ctx.set(Some(ctx.clone()));
|
self.render_ctx.set(Some(ctx.clone()));
|
||||||
self.state.render_ctxs.set(dev_id, Rc::downgrade(&ctx));
|
self.state.render_ctxs.set(dev_id, Rc::downgrade(&ctx));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {crate::render::RenderContext, std::rc::Rc, uapi::c};
|
use {crate::gfx_api::GfxContext, std::rc::Rc, uapi::c};
|
||||||
|
|
||||||
pub struct PortalRenderCtx {
|
pub struct PortalRenderCtx {
|
||||||
pub dev_id: c::dev_t,
|
pub dev_id: c::dev_t,
|
||||||
pub ctx: Rc<RenderContext>,
|
pub ctx: Rc<dyn GfxContext>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ use {
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::ARGB8888,
|
format::ARGB8888,
|
||||||
|
gfx_api::{GfxContext, GfxFramebuffer, GfxTexture},
|
||||||
ifs::zwlr_layer_shell_v1::OVERLAY,
|
ifs::zwlr_layer_shell_v1::OVERLAY,
|
||||||
portal::ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
portal::ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
||||||
render::{Framebuffer, RenderContext, RendererBase, Texture},
|
renderer::renderer_base::RendererBase,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
text::{self, TextMeasurement},
|
text::{self, TextMeasurement},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
|
|
@ -49,7 +50,7 @@ pub trait GuiElement {
|
||||||
fn data(&self) -> &GuiElementData;
|
fn data(&self) -> &GuiElementData;
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
max_width: f32,
|
max_width: f32,
|
||||||
max_height: f32,
|
max_height: f32,
|
||||||
|
|
@ -117,7 +118,7 @@ pub struct Button {
|
||||||
pub bg_hover_color: Cell<Color>,
|
pub bg_hover_color: Cell<Color>,
|
||||||
pub text: RefCell<String>,
|
pub text: RefCell<String>,
|
||||||
pub font: RefCell<Cow<'static, str>>,
|
pub font: RefCell<Cow<'static, str>>,
|
||||||
pub tex: CloneCell<Option<Rc<Texture>>>,
|
pub tex: CloneCell<Option<Rc<dyn GfxTexture>>>,
|
||||||
pub owner: CloneCell<Option<Rc<dyn ButtonOwner>>>,
|
pub owner: CloneCell<Option<Rc<dyn ButtonOwner>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,7 +157,7 @@ impl GuiElement for Button {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
_max_width: f32,
|
_max_width: f32,
|
||||||
_max_height: f32,
|
_max_height: f32,
|
||||||
|
|
@ -219,6 +220,8 @@ impl GuiElement for Button {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
r.scale(),
|
r.scale(),
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +260,7 @@ pub struct Label {
|
||||||
pub data: GuiElementData,
|
pub data: GuiElementData,
|
||||||
pub font: RefCell<Cow<'static, str>>,
|
pub font: RefCell<Cow<'static, str>>,
|
||||||
pub text: RefCell<String>,
|
pub text: RefCell<String>,
|
||||||
pub tex: CloneCell<Option<Rc<Texture>>>,
|
pub tex: CloneCell<Option<Rc<dyn GfxTexture>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Label {
|
impl Default for Label {
|
||||||
|
|
@ -278,7 +281,7 @@ impl GuiElement for Label {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
_max_width: f32,
|
_max_width: f32,
|
||||||
_max_height: f32,
|
_max_height: f32,
|
||||||
|
|
@ -315,6 +318,8 @@ impl GuiElement for Label {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
r.scale(),
|
r.scale(),
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -359,7 +364,7 @@ impl GuiElement for Flow {
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
max_width: f32,
|
max_width: f32,
|
||||||
max_height: f32,
|
max_height: f32,
|
||||||
|
|
@ -633,7 +638,7 @@ impl WindowData {
|
||||||
self.have_frame.set(false);
|
self.have_frame.set(false);
|
||||||
buf.free.set(false);
|
buf.free.set(false);
|
||||||
|
|
||||||
buf.fb.render_custom(self.scale.get(), |r| {
|
buf.fb.render_custom(self.scale.get(), &mut |r| {
|
||||||
r.clear(&Color::from_gray(0));
|
r.clear(&Color::from_gray(0));
|
||||||
if let Some(content) = self.content.get() {
|
if let Some(content) = self.content.get() {
|
||||||
content.render_at(r, 0.0, 0.0)
|
content.render_at(r, 0.0, 0.0)
|
||||||
|
|
@ -695,7 +700,7 @@ impl WindowData {
|
||||||
};
|
};
|
||||||
let bo = match ctx
|
let bo = match ctx
|
||||||
.ctx
|
.ctx
|
||||||
.gbm
|
.gbm()
|
||||||
.create_bo(width, height, &format, GBM_BO_USE_RENDERING)
|
.create_bo(width, height, &format, GBM_BO_USE_RENDERING)
|
||||||
{
|
{
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
|
|
@ -704,7 +709,7 @@ impl WindowData {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let img = match ctx.ctx.dmabuf_img(bo.dmabuf()) {
|
let img = match ctx.ctx.clone().dmabuf_img(bo.dmabuf()) {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Could not import dmabuf into EGL: {}", ErrorFmt(e));
|
log::error!("Could not import dmabuf into EGL: {}", ErrorFmt(e));
|
||||||
|
|
@ -809,14 +814,14 @@ impl WindowData {
|
||||||
pub struct GuiBuffer {
|
pub struct GuiBuffer {
|
||||||
pub wl: Rc<UsrWlBuffer>,
|
pub wl: Rc<UsrWlBuffer>,
|
||||||
pub window: Rc<WindowData>,
|
pub window: Rc<WindowData>,
|
||||||
pub fb: Rc<Framebuffer>,
|
pub fb: Rc<dyn GfxFramebuffer>,
|
||||||
pub free: Cell<bool>,
|
pub free: Cell<bool>,
|
||||||
pub size: (i32, i32),
|
pub size: (i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GuiBufferPending {
|
struct GuiBufferPending {
|
||||||
pub window: Rc<WindowData>,
|
pub window: Rc<WindowData>,
|
||||||
pub fb: Rc<Framebuffer>,
|
pub fb: Rc<dyn GfxFramebuffer>,
|
||||||
pub params: Rc<UsrLinuxBufferParams>,
|
pub params: Rc<UsrLinuxBufferParams>,
|
||||||
pub size: (i32, i32),
|
pub size: (i32, i32),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
macro_rules! egl_transparent {
|
|
||||||
($name:ident) => {
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct $name(pub *mut u8);
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub const fn none() -> Self {
|
|
||||||
Self(std::ptr::null_mut())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn is_none(self) -> bool {
|
|
||||||
self.0.is_null()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use renderer::*;
|
|
||||||
use {
|
|
||||||
crate::video::{drm::DrmError, gbm::GbmError},
|
|
||||||
thiserror::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod egl;
|
|
||||||
mod ext;
|
|
||||||
mod gl;
|
|
||||||
mod proc;
|
|
||||||
mod renderer;
|
|
||||||
|
|
||||||
pub mod sys {
|
|
||||||
pub use super::{egl::sys::*, gl::sys::*};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init() -> Result<(), RenderError> {
|
|
||||||
egl::init()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum RenderError {
|
|
||||||
#[error("EGL library does not support `EGL_EXT_platform_base`")]
|
|
||||||
ExtPlatformBase,
|
|
||||||
#[error("Could not compile a shader")]
|
|
||||||
ShaderCompileFailed,
|
|
||||||
#[error("Could not link a program")]
|
|
||||||
ProgramLink,
|
|
||||||
#[error("Could not bind to `EGL_OPENGL_ES_API`")]
|
|
||||||
BindFailed,
|
|
||||||
#[error("EGL library does not support the GBM platform")]
|
|
||||||
GbmExt,
|
|
||||||
#[error("Could not create a GBM device")]
|
|
||||||
Gbm(#[source] GbmError),
|
|
||||||
#[error("`eglCreateContext` failed")]
|
|
||||||
CreateContext,
|
|
||||||
#[error("`eglMakeCurrent` failed")]
|
|
||||||
MakeCurrent,
|
|
||||||
#[error("`eglCreateImageKHR` failed")]
|
|
||||||
CreateImage,
|
|
||||||
#[error("Image buffer is too small")]
|
|
||||||
SmallImageBuffer,
|
|
||||||
#[error("Binding a renderbuffer to a framebuffer failed")]
|
|
||||||
CreateFramebuffer,
|
|
||||||
#[error("`eglGetPlatformDisplayEXT` failed")]
|
|
||||||
GetDisplay,
|
|
||||||
#[error("`eglInitialize` failed")]
|
|
||||||
Initialize,
|
|
||||||
#[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")]
|
|
||||||
DmaBufImport,
|
|
||||||
#[error("GLES driver does not support `GL_OES_EGL_image`")]
|
|
||||||
OesEglImage,
|
|
||||||
#[error("EGL display does not support `EGL_KHR_image_base`")]
|
|
||||||
ImageBase,
|
|
||||||
#[error(
|
|
||||||
"EGL display does not support `EGL_KHR_no_config_context` or `EGL_MESA_configless_context`"
|
|
||||||
)]
|
|
||||||
ConfiglessContext,
|
|
||||||
#[error("EGL display does not support `EGL_KHR_surfaceless_context`")]
|
|
||||||
SurfacelessContext,
|
|
||||||
#[error("`eglQueryDmaBufFormatsEXT` failed")]
|
|
||||||
QueryDmaBufFormats,
|
|
||||||
#[error("`eglQueryDmaBufModifiersEXT` failed")]
|
|
||||||
QueryDmaBufModifiers,
|
|
||||||
#[error(transparent)]
|
|
||||||
DrmError(#[from] DrmError),
|
|
||||||
#[error("The GLES driver does not support the XRGB8888 format")]
|
|
||||||
XRGB888,
|
|
||||||
#[error("The DRM device does not have a render node")]
|
|
||||||
NoRenderNode,
|
|
||||||
#[error("The requested format is not supported")]
|
|
||||||
UnsupportedFormat,
|
|
||||||
#[error("The requested modifier is not supported")]
|
|
||||||
UnsupportedModifier,
|
|
||||||
#[error("Image is external only and cannot be rendered to")]
|
|
||||||
ExternalOnly,
|
|
||||||
#[error("OpenGL context does not support external textures")]
|
|
||||||
ExternalUnsupported,
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
rect::Rect,
|
|
||||||
render::{
|
|
||||||
egl::context::EglContext,
|
|
||||||
gl::{
|
|
||||||
render_buffer::GlRenderBuffer,
|
|
||||||
sys::{glDeleteFramebuffers, GLuint},
|
|
||||||
texture::GlTexture,
|
|
||||||
},
|
|
||||||
sys::{glDisable, glEnable, glScissor, GL_SCISSOR_TEST},
|
|
||||||
},
|
|
||||||
utils::ptr_ext::PtrExt,
|
|
||||||
},
|
|
||||||
std::{ptr, rc::Rc},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct GlFrameBuffer {
|
|
||||||
pub _rb: Option<Rc<GlRenderBuffer>>,
|
|
||||||
pub _tex: Option<Rc<GlTexture>>,
|
|
||||||
pub ctx: Rc<EglContext>,
|
|
||||||
pub width: i32,
|
|
||||||
pub height: i32,
|
|
||||||
pub fbo: GLuint,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for GlFrameBuffer {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glDeleteFramebuffers(1, &self.fbo);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn with_scissor<T, F: FnOnce() -> T>(scissor: &Rect, f: F) -> T {
|
|
||||||
#[thread_local]
|
|
||||||
static mut SCISSOR: *const Rect = ptr::null();
|
|
||||||
|
|
||||||
let prev = SCISSOR;
|
|
||||||
if prev.is_null() {
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
}
|
|
||||||
glScissor(
|
|
||||||
scissor.x1(),
|
|
||||||
scissor.y1(),
|
|
||||||
scissor.width(),
|
|
||||||
scissor.height(),
|
|
||||||
);
|
|
||||||
SCISSOR = scissor;
|
|
||||||
let res = f();
|
|
||||||
if prev.is_null() {
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
} else {
|
|
||||||
let prev = prev.deref();
|
|
||||||
glScissor(prev.x1(), prev.y1(), prev.width(), prev.height());
|
|
||||||
}
|
|
||||||
SCISSOR = prev;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
pub use {context::*, framebuffer::*, image::*, renderer::*, renderer_base::*, texture::*};
|
|
||||||
|
|
||||||
mod context;
|
|
||||||
mod framebuffer;
|
|
||||||
mod image;
|
|
||||||
mod renderer;
|
|
||||||
mod renderer_base;
|
|
||||||
mod texture;
|
|
||||||
|
|
@ -1,243 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
cursor::Cursor,
|
|
||||||
fixed::Fixed,
|
|
||||||
format::{Format, ARGB8888, XRGB8888},
|
|
||||||
rect::Rect,
|
|
||||||
render::{
|
|
||||||
gl::{
|
|
||||||
frame_buffer::GlFrameBuffer,
|
|
||||||
sys::{
|
|
||||||
glBindFramebuffer, glClear, glClearColor, glViewport, GL_COLOR_BUFFER_BIT,
|
|
||||||
GL_FRAMEBUFFER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
renderer::{context::RenderContext, renderer::Renderer, renderer_base::RendererBase},
|
|
||||||
sys::{glBlendFunc, glFlush, glReadnPixels, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
|
||||||
RenderResult, Texture,
|
|
||||||
},
|
|
||||||
scale::Scale,
|
|
||||||
state::State,
|
|
||||||
tree::Node,
|
|
||||||
},
|
|
||||||
std::{
|
|
||||||
cell::Cell,
|
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
rc::Rc,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Framebuffer {
|
|
||||||
pub(super) ctx: Rc<RenderContext>,
|
|
||||||
pub(super) gl: GlFrameBuffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Framebuffer {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("Framebuffer").finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Framebuffer {
|
|
||||||
pub fn clear(&self) {
|
|
||||||
self.clear_with(0.0, 0.0, 0.0, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_with(&self, r: f32, g: f32, b: f32, a: f32) {
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
|
||||||
glClearColor(r, g, b, a);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_texture(&self, state: &State, texture: &Texture, x: i32, y: i32, alpha: bool) {
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
let scale = Scale::from_int(1);
|
|
||||||
let mut renderer = Renderer {
|
|
||||||
base: RendererBase {
|
|
||||||
ctx: &self.ctx,
|
|
||||||
fb: &self.gl,
|
|
||||||
scaled: false,
|
|
||||||
scale,
|
|
||||||
scalef: 1.0,
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
on_output: false,
|
|
||||||
result: &mut RenderResult::default(),
|
|
||||||
logical_extents: Rect::new_sized(0, 0, self.gl.width, self.gl.height).unwrap(),
|
|
||||||
};
|
|
||||||
let format = match alpha {
|
|
||||||
true => ARGB8888,
|
|
||||||
false => XRGB8888,
|
|
||||||
};
|
|
||||||
renderer
|
|
||||||
.base
|
|
||||||
.render_texture(texture, x, y, format, None, None, scale);
|
|
||||||
unsafe {
|
|
||||||
glFlush();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_to_shm(
|
|
||||||
&self,
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
width: i32,
|
|
||||||
height: i32,
|
|
||||||
format: &Format,
|
|
||||||
shm: &[Cell<u8>],
|
|
||||||
) {
|
|
||||||
let y = self.gl.height - y - height;
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
|
||||||
glReadnPixels(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format.gl_format as _,
|
|
||||||
format.gl_type as _,
|
|
||||||
shm.len() as _,
|
|
||||||
shm.as_ptr() as _,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_custom(&self, scale: Scale, f: impl FnOnce(&mut RendererBase)) {
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
let mut renderer = RendererBase {
|
|
||||||
ctx: &self.ctx,
|
|
||||||
fb: &self.gl,
|
|
||||||
scaled: scale != 1,
|
|
||||||
scale,
|
|
||||||
scalef: scale.to_f64(),
|
|
||||||
};
|
|
||||||
f(&mut renderer);
|
|
||||||
unsafe {
|
|
||||||
glFlush();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(
|
|
||||||
&self,
|
|
||||||
node: &dyn Node,
|
|
||||||
state: &State,
|
|
||||||
cursor_rect: Option<Rect>,
|
|
||||||
on_output: bool,
|
|
||||||
result: &mut RenderResult,
|
|
||||||
scale: Scale,
|
|
||||||
render_hardware_cursor: bool,
|
|
||||||
) {
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
let c = state.theme.colors.background.get();
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
|
||||||
glClearColor(c.r, c.g, c.b, 1.0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
let mut renderer = Renderer {
|
|
||||||
base: RendererBase {
|
|
||||||
ctx: &self.ctx,
|
|
||||||
fb: &self.gl,
|
|
||||||
scaled: scale != 1,
|
|
||||||
scale,
|
|
||||||
scalef: scale.to_f64(),
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
on_output,
|
|
||||||
result,
|
|
||||||
logical_extents: node.node_absolute_position().at_point(0, 0),
|
|
||||||
};
|
|
||||||
node.node_render(&mut renderer, 0, 0);
|
|
||||||
if let Some(rect) = cursor_rect {
|
|
||||||
let seats = state.globals.lock_seats();
|
|
||||||
for seat in seats.values() {
|
|
||||||
if !render_hardware_cursor && seat.hardware_cursor() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(cursor) = seat.get_cursor() {
|
|
||||||
let (mut x, mut y) = seat.get_position();
|
|
||||||
if let Some(dnd_icon) = seat.dnd_icon() {
|
|
||||||
let extents = dnd_icon.extents.get().move_(
|
|
||||||
x.round_down() + dnd_icon.buf_x.get(),
|
|
||||||
y.round_down() + dnd_icon.buf_y.get(),
|
|
||||||
);
|
|
||||||
if extents.intersects(&rect) {
|
|
||||||
let (x, y) = rect.translate(extents.x1(), extents.y1());
|
|
||||||
renderer.render_surface(&dnd_icon, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.tick();
|
|
||||||
x -= Fixed::from_int(rect.x1());
|
|
||||||
y -= Fixed::from_int(rect.y1());
|
|
||||||
cursor.render(&mut renderer, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
glFlush();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_hardware_cursor(&self, cursor: &dyn Cursor, state: &State, scale: Scale) {
|
|
||||||
let _ = self.ctx.ctx.with_current(|| {
|
|
||||||
unsafe {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, self.gl.fbo);
|
|
||||||
glViewport(0, 0, self.gl.width, self.gl.height);
|
|
||||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
let mut res = RenderResult::default();
|
|
||||||
let mut renderer = Renderer {
|
|
||||||
base: RendererBase {
|
|
||||||
ctx: &self.ctx,
|
|
||||||
fb: &self.gl,
|
|
||||||
scaled: scale != 1,
|
|
||||||
scale,
|
|
||||||
scalef: scale.to_f64(),
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
on_output: false,
|
|
||||||
result: &mut res,
|
|
||||||
logical_extents: Rect::new_empty(0, 0),
|
|
||||||
};
|
|
||||||
cursor.render_hardware_cursor(&mut renderer);
|
|
||||||
unsafe {
|
|
||||||
glFlush();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
use {
|
|
||||||
crate::render::{
|
|
||||||
egl::image::EglImage,
|
|
||||||
gl::{render_buffer::GlRenderBuffer, texture::GlTexture},
|
|
||||||
Framebuffer, RenderContext, RenderError, Texture,
|
|
||||||
},
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Image {
|
|
||||||
pub(super) ctx: Rc<RenderContext>,
|
|
||||||
pub(super) gl: Rc<EglImage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Image {
|
|
||||||
pub fn width(&self) -> i32 {
|
|
||||||
self.gl.width
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(&self) -> i32 {
|
|
||||||
self.gl.height
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_texture(self: &Rc<Self>) -> Result<Rc<Texture>, RenderError> {
|
|
||||||
Ok(Rc::new(Texture {
|
|
||||||
ctx: self.ctx.clone(),
|
|
||||||
gl: GlTexture::import_img(&self.ctx.ctx, &self.gl)?,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_framebuffer(&self) -> Result<Rc<Framebuffer>, RenderError> {
|
|
||||||
self.ctx.ctx.with_current(|| unsafe {
|
|
||||||
let rb = GlRenderBuffer::from_image(&self.gl, &self.ctx.ctx)?;
|
|
||||||
let fb = rb.create_framebuffer()?;
|
|
||||||
Ok(Rc::new(Framebuffer {
|
|
||||||
ctx: self.ctx.clone(),
|
|
||||||
gl: fb,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
format::Format,
|
|
||||||
rect::Rect,
|
|
||||||
render::{
|
|
||||||
gl::{
|
|
||||||
frame_buffer::GlFrameBuffer,
|
|
||||||
sys::{
|
|
||||||
glActiveTexture, glBindTexture, glDisableVertexAttribArray, glDrawArrays,
|
|
||||||
glEnableVertexAttribArray, glTexParameteri, glUniform1i, glUniform4f,
|
|
||||||
glUseProgram, glVertexAttribPointer, GL_FALSE, GL_FLOAT, GL_LINEAR,
|
|
||||||
GL_TEXTURE0, GL_TEXTURE_MIN_FILTER, GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
|
||||||
},
|
|
||||||
texture::image_target,
|
|
||||||
},
|
|
||||||
renderer::context::RenderContext,
|
|
||||||
sys::{glClear, glClearColor, glDisable, glEnable, GL_BLEND, GL_COLOR_BUFFER_BIT},
|
|
||||||
Texture,
|
|
||||||
},
|
|
||||||
scale::Scale,
|
|
||||||
theme::Color,
|
|
||||||
utils::rc_eq::rc_eq,
|
|
||||||
},
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct RendererBase<'a> {
|
|
||||||
pub(super) ctx: &'a Rc<RenderContext>,
|
|
||||||
pub(super) fb: &'a GlFrameBuffer,
|
|
||||||
pub(super) scaled: bool,
|
|
||||||
pub(super) scale: Scale,
|
|
||||||
pub(super) scalef: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RendererBase<'_> {
|
|
||||||
pub fn scale(&self) -> Scale {
|
|
||||||
self.scale
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn physical_extents(&self) -> Rect {
|
|
||||||
Rect::new_sized(0, 0, self.fb.width, self.fb.height).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_point(&self, mut x: i32, mut y: i32) -> (i32, i32) {
|
|
||||||
if self.scaled {
|
|
||||||
x = (x as f64 * self.scalef).round() as _;
|
|
||||||
y = (y as f64 * self.scalef).round() as _;
|
|
||||||
}
|
|
||||||
(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_point_f(&self, mut x: f32, mut y: f32) -> (f32, f32) {
|
|
||||||
if self.scaled {
|
|
||||||
x = (x as f64 * self.scalef) as _;
|
|
||||||
y = (y as f64 * self.scalef) as _;
|
|
||||||
}
|
|
||||||
(x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_rect(&self, mut rect: Rect) -> Rect {
|
|
||||||
if self.scaled {
|
|
||||||
let x1 = (rect.x1() as f64 * self.scalef).round() as _;
|
|
||||||
let y1 = (rect.y1() as f64 * self.scalef).round() as _;
|
|
||||||
let x2 = (rect.x2() as f64 * self.scalef).round() as _;
|
|
||||||
let y2 = (rect.y2() as f64 * self.scalef).round() as _;
|
|
||||||
rect = Rect::new(x1, y1, x2, y2).unwrap();
|
|
||||||
}
|
|
||||||
rect
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_rect_f(&self, mut rect: (f32, f32, f32, f32)) -> (f32, f32, f32, f32) {
|
|
||||||
if self.scaled {
|
|
||||||
let x1 = (rect.0 as f64 * self.scalef).round() as _;
|
|
||||||
let y1 = (rect.1 as f64 * self.scalef).round() as _;
|
|
||||||
let x2 = (rect.2 as f64 * self.scalef).round() as _;
|
|
||||||
let y2 = (rect.3 as f64 * self.scalef).round() as _;
|
|
||||||
rect = (x1, y1, x2, y2)
|
|
||||||
}
|
|
||||||
rect
|
|
||||||
}
|
|
||||||
|
|
||||||
fn xf_to_f(&self, x: f32) -> f32 {
|
|
||||||
2.0 * (x / self.fb.width as f32) - 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn yf_to_f(&self, y: f32) -> f32 {
|
|
||||||
2.0 * (y / self.fb.height as f32) - 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn x_to_f(&self, x: i32) -> f32 {
|
|
||||||
2.0 * (x as f32 / self.fb.width as f32) - 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn y_to_f(&self, y: i32) -> f32 {
|
|
||||||
2.0 * (y as f32 / self.fb.height as f32) - 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&self, c: &Color) {
|
|
||||||
unsafe {
|
|
||||||
glClearColor(c.r, c.g, c.b, c.a);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_boxes(&self, boxes: &[Rect], color: &Color) {
|
|
||||||
self.fill_boxes2(boxes, color, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_boxes2(&self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) {
|
|
||||||
if boxes.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (dx, dy) = self.scale_point(dx, dy);
|
|
||||||
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
|
||||||
for bx in boxes {
|
|
||||||
let bx = self.scale_rect(*bx);
|
|
||||||
let x1 = self.x_to_f(bx.x1() + dx);
|
|
||||||
let y1 = self.y_to_f(bx.y1() + dy);
|
|
||||||
let x2 = self.x_to_f(bx.x2() + dx);
|
|
||||||
let y2 = self.y_to_f(bx.y2() + dy);
|
|
||||||
pos.extend_from_slice(&[
|
|
||||||
// triangle 1
|
|
||||||
x2, y1, // top right
|
|
||||||
x1, y1, // top left
|
|
||||||
x1, y2, // bottom left
|
|
||||||
// triangle 2
|
|
||||||
x2, y1, // top right
|
|
||||||
x1, y2, // bottom left
|
|
||||||
x2, y2, // bottom right
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
self.fill_boxes3(&pos, color)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_boxes_f(&self, boxes: &[(f32, f32, f32, f32)], color: &Color) {
|
|
||||||
self.fill_boxes2_f(boxes, color, 0.0, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_boxes2_f(&self, boxes: &[(f32, f32, f32, f32)], color: &Color, dx: f32, dy: f32) {
|
|
||||||
if boxes.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (dx, dy) = self.scale_point_f(dx, dy);
|
|
||||||
let mut pos = Vec::with_capacity(boxes.len() * 12);
|
|
||||||
for bx in boxes {
|
|
||||||
let (x1, y1, x2, y2) = self.scale_rect_f(*bx);
|
|
||||||
let x1 = self.xf_to_f(x1 + dx);
|
|
||||||
let y1 = self.yf_to_f(y1 + dy);
|
|
||||||
let x2 = self.xf_to_f(x2 + dx);
|
|
||||||
let y2 = self.yf_to_f(y2 + dy);
|
|
||||||
pos.extend_from_slice(&[
|
|
||||||
// triangle 1
|
|
||||||
x2, y1, // top right
|
|
||||||
x1, y1, // top left
|
|
||||||
x1, y2, // bottom left
|
|
||||||
// triangle 2
|
|
||||||
x2, y1, // top right
|
|
||||||
x1, y2, // bottom left
|
|
||||||
x2, y2, // bottom right
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
self.fill_boxes3(&pos, color)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_boxes3(&self, boxes: &[f32], color: &Color) {
|
|
||||||
unsafe {
|
|
||||||
glUseProgram(self.ctx.fill_prog.prog);
|
|
||||||
glUniform4f(self.ctx.fill_prog_color, color.r, color.g, color.b, color.a);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
self.ctx.fill_prog_pos as _,
|
|
||||||
2,
|
|
||||||
GL_FLOAT,
|
|
||||||
GL_FALSE,
|
|
||||||
0,
|
|
||||||
boxes.as_ptr() as _,
|
|
||||||
);
|
|
||||||
glEnableVertexAttribArray(self.ctx.fill_prog_pos as _);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, (boxes.len() / 2) as _);
|
|
||||||
glDisableVertexAttribArray(self.ctx.fill_prog_pos as _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_texture(
|
|
||||||
&mut self,
|
|
||||||
texture: &Texture,
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
format: &Format,
|
|
||||||
tpoints: Option<&[f32; 8]>,
|
|
||||||
tsize: Option<(i32, i32)>,
|
|
||||||
tscale: Scale,
|
|
||||||
) {
|
|
||||||
assert!(rc_eq(&self.ctx.ctx, &texture.ctx.ctx));
|
|
||||||
unsafe {
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
let target = image_target(texture.gl.external_only);
|
|
||||||
|
|
||||||
glBindTexture(target, texture.gl.tex);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
let progs = match texture.gl.external_only {
|
|
||||||
true => match &self.ctx.tex_external {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => {
|
|
||||||
log::error!("Trying to render an external-only texture but context does not support the required extension");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => &self.ctx.tex_internal,
|
|
||||||
};
|
|
||||||
let prog = match format.has_alpha {
|
|
||||||
true => {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
&progs.alpha
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
&progs.solid
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
glUseProgram(prog.prog.prog);
|
|
||||||
|
|
||||||
glUniform1i(prog.tex, 0);
|
|
||||||
|
|
||||||
static DEFAULT_TEXCOORD: [f32; 8] = [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0];
|
|
||||||
|
|
||||||
let texcoord: &[f32; 8] = match tpoints {
|
|
||||||
None => &DEFAULT_TEXCOORD,
|
|
||||||
Some(tp) => tp,
|
|
||||||
};
|
|
||||||
|
|
||||||
let f_width = self.fb.width as f32;
|
|
||||||
let f_height = self.fb.height as f32;
|
|
||||||
|
|
||||||
let (twidth, theight) = if let Some(size) = tsize {
|
|
||||||
size
|
|
||||||
} else {
|
|
||||||
let (mut w, mut h) = (texture.gl.width, texture.gl.height);
|
|
||||||
if tscale != self.scale {
|
|
||||||
let tscale = tscale.to_f64();
|
|
||||||
w = (w as f64 * self.scalef / tscale).round() as _;
|
|
||||||
h = (h as f64 * self.scalef / tscale).round() as _;
|
|
||||||
}
|
|
||||||
(w, h)
|
|
||||||
};
|
|
||||||
|
|
||||||
let x1 = 2.0 * (x as f32 / f_width) - 1.0;
|
|
||||||
let y1 = 2.0 * (y as f32 / f_height) - 1.0;
|
|
||||||
let x2 = 2.0 * ((x + twidth) as f32 / f_width) - 1.0;
|
|
||||||
let y2 = 2.0 * ((y + theight) as f32 / f_height) - 1.0;
|
|
||||||
|
|
||||||
let pos: [f32; 8] = [
|
|
||||||
x2, y1, // top right
|
|
||||||
x1, y1, // top left
|
|
||||||
x2, y2, // bottom right
|
|
||||||
x1, y2, // bottom left
|
|
||||||
];
|
|
||||||
|
|
||||||
glVertexAttribPointer(
|
|
||||||
prog.texcoord as _,
|
|
||||||
2,
|
|
||||||
GL_FLOAT,
|
|
||||||
GL_FALSE,
|
|
||||||
0,
|
|
||||||
texcoord.as_ptr() as _,
|
|
||||||
);
|
|
||||||
glVertexAttribPointer(prog.pos as _, 2, GL_FLOAT, GL_FALSE, 0, pos.as_ptr() as _);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(prog.texcoord as _);
|
|
||||||
glEnableVertexAttribArray(prog.pos as _);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
||||||
|
|
||||||
glDisableVertexAttribArray(prog.texcoord as _);
|
|
||||||
glDisableVertexAttribArray(prog.pos as _);
|
|
||||||
|
|
||||||
glBindTexture(target, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
use {
|
|
||||||
crate::render::{gl::texture::GlTexture, renderer::context::RenderContext},
|
|
||||||
std::{
|
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
rc::Rc,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Texture {
|
|
||||||
pub(super) ctx: Rc<RenderContext>,
|
|
||||||
pub(super) gl: GlTexture,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Texture {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("Texture").finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Texture {
|
|
||||||
pub fn width(&self) -> i32 {
|
|
||||||
self.gl.width
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(&self) -> i32 {
|
|
||||||
self.gl.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::ARGB8888,
|
format::ARGB8888,
|
||||||
|
gfx_api::{BufferPoints, GfxApiOpt},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::WlBuffer,
|
wl_buffer::WlBuffer,
|
||||||
wl_callback::WlCallback,
|
wl_callback::WlCallback,
|
||||||
|
|
@ -10,7 +11,7 @@ use {
|
||||||
wp_presentation_feedback::WpPresentationFeedback,
|
wp_presentation_feedback::WpPresentationFeedback,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{gl::frame_buffer::with_scissor, renderer::renderer_base::RendererBase},
|
renderer::renderer_base::RendererBase,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
|
|
@ -27,6 +28,8 @@ use {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod renderer_base;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RenderResult {
|
pub struct RenderResult {
|
||||||
pub frame_requests: Vec<Rc<WlCallback>>,
|
pub frame_requests: Vec<Rc<WlCallback>>,
|
||||||
|
|
@ -41,10 +44,11 @@ impl Debug for RenderResult {
|
||||||
|
|
||||||
pub struct Renderer<'a> {
|
pub struct Renderer<'a> {
|
||||||
pub base: RendererBase<'a>,
|
pub base: RendererBase<'a>,
|
||||||
pub(super) state: &'a State,
|
pub state: &'a State,
|
||||||
pub(super) on_output: bool,
|
pub on_output: bool,
|
||||||
pub(super) result: &'a mut RenderResult,
|
pub result: &'a mut RenderResult,
|
||||||
pub(super) logical_extents: Rect,
|
pub logical_extents: Rect,
|
||||||
|
pub physical_extents: Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer<'_> {
|
impl Renderer<'_> {
|
||||||
|
|
@ -53,7 +57,7 @@ impl Renderer<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn physical_extents(&self) -> Rect {
|
pub fn physical_extents(&self) -> Rect {
|
||||||
self.base.physical_extents()
|
self.physical_extents
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logical_extents(&self) -> Rect {
|
pub fn logical_extents(&self) -> Rect {
|
||||||
|
|
@ -74,7 +78,7 @@ impl Renderer<'_> {
|
||||||
if self.state.lock.locked.get() {
|
if self.state.lock.locked.get() {
|
||||||
if let Some(surface) = output.lock_surface.get() {
|
if let Some(surface) = output.lock_surface.get() {
|
||||||
if surface.surface.buffer.get().is_some() {
|
if surface.surface.buffer.get().is_some() {
|
||||||
self.render_surface(&surface.surface, x, y);
|
self.render_surface(&surface.surface, x, y, i32::MAX, i32::MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -94,7 +98,7 @@ impl Renderer<'_> {
|
||||||
}
|
}
|
||||||
if let Some(ws) = output.workspace.get() {
|
if let Some(ws) = output.workspace.get() {
|
||||||
if let Some(fs) = ws.fullscreen.get() {
|
if let Some(fs) = ws.fullscreen.get() {
|
||||||
fs.tl_as_node().node_render(self, x, y);
|
fs.tl_as_node().node_render(self, x, y, i32::MAX, i32::MAX);
|
||||||
render_layer!(output.layers[2]);
|
render_layer!(output.layers[2]);
|
||||||
render_layer!(output.layers[3]);
|
render_layer!(output.layers[3]);
|
||||||
return;
|
return;
|
||||||
|
|
@ -136,13 +140,31 @@ impl Renderer<'_> {
|
||||||
let scale = output.preferred_scale.get();
|
let scale = output.preferred_scale.get();
|
||||||
for title in &rd.titles {
|
for title in &rd.titles {
|
||||||
let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y);
|
let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y);
|
||||||
self.base
|
self.base.render_texture(
|
||||||
.render_texture(&title.tex, x, y, ARGB8888, None, None, scale);
|
&title.tex,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(status) = &rd.status {
|
if let Some(status) = &rd.status {
|
||||||
let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y);
|
let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y);
|
||||||
self.base
|
self.base.render_texture(
|
||||||
.render_texture(&status.tex, x, y, ARGB8888, None, None, scale);
|
&status.tex,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ws) = output.workspace.get() {
|
if let Some(ws) = output.workspace.get() {
|
||||||
|
|
@ -150,10 +172,11 @@ impl Renderer<'_> {
|
||||||
}
|
}
|
||||||
for stacked in self.state.root.stacked.iter() {
|
for stacked in self.state.root.stacked.iter() {
|
||||||
if stacked.node_visible() {
|
if stacked.node_visible() {
|
||||||
|
self.base.ops.push(GfxApiOpt::Sync);
|
||||||
let pos = stacked.node_absolute_position();
|
let pos = stacked.node_absolute_position();
|
||||||
if pos.intersects(&opos) {
|
if pos.intersects(&opos) {
|
||||||
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
let (x, y) = opos.translate(pos.x1(), pos.y1());
|
||||||
stacked.node_render(self, x, y);
|
stacked.node_render(self, x, y, i32::MAX, i32::MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -176,8 +199,17 @@ impl Renderer<'_> {
|
||||||
if let Some(tex) = placeholder.textures.get(&self.base.scale) {
|
if let Some(tex) = placeholder.textures.get(&self.base.scale) {
|
||||||
let x = x + (pos.width() - tex.width()) / 2;
|
let x = x + (pos.width() - tex.width()) / 2;
|
||||||
let y = y + (pos.height() - tex.height()) / 2;
|
let y = y + (pos.height() - tex.height()) / 2;
|
||||||
self.base
|
self.base.render_texture(
|
||||||
.render_texture(&tex, x, y, ARGB8888, None, None, self.base.scale);
|
&tex,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
self.base.scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,21 +244,23 @@ impl Renderer<'_> {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
self.base.scale,
|
self.base.scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(child) = container.mono_child.get() {
|
if let Some(child) = container.mono_child.get() {
|
||||||
unsafe {
|
let body = container.mono_body.get().move_(x, y);
|
||||||
let body = container.mono_body.get().move_(x, y);
|
let body = self.base.scale_rect(body);
|
||||||
let body = self.base.scale_rect(body);
|
let content = container.mono_content.get();
|
||||||
with_scissor(&body, || {
|
child.node.node_render(
|
||||||
let content = container.mono_content.get();
|
self,
|
||||||
child
|
x + content.x1(),
|
||||||
.node
|
y + content.y1(),
|
||||||
.node_render(self, x + content.x1(), y + content.y1());
|
body.width(),
|
||||||
});
|
body.height(),
|
||||||
}
|
);
|
||||||
} else {
|
} else {
|
||||||
for child in container.children.iter() {
|
for child in container.children.iter() {
|
||||||
let body = child.body.get();
|
let body = child.body.get();
|
||||||
|
|
@ -235,31 +269,45 @@ impl Renderer<'_> {
|
||||||
}
|
}
|
||||||
let body = body.move_(x, y);
|
let body = body.move_(x, y);
|
||||||
let body = self.base.scale_rect(body);
|
let body = self.base.scale_rect(body);
|
||||||
unsafe {
|
let content = child.content.get();
|
||||||
with_scissor(&body, || {
|
child.node.node_render(
|
||||||
let content = child.content.get();
|
self,
|
||||||
child
|
x + content.x1(),
|
||||||
.node
|
y + content.y1(),
|
||||||
.node_render(self, x + content.x1(), y + content.y1());
|
body.width(),
|
||||||
});
|
body.height(),
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_xdg_surface(&mut self, xdg: &XdgSurface, mut x: i32, mut y: i32) {
|
pub fn render_xdg_surface(
|
||||||
|
&mut self,
|
||||||
|
xdg: &XdgSurface,
|
||||||
|
mut x: i32,
|
||||||
|
mut y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
let surface = &xdg.surface;
|
let surface = &xdg.surface;
|
||||||
if let Some(geo) = xdg.geometry() {
|
if let Some(geo) = xdg.geometry() {
|
||||||
let (xt, yt) = geo.translate(x, y);
|
let (xt, yt) = geo.translate(x, y);
|
||||||
x = xt;
|
x = xt;
|
||||||
y = yt;
|
y = yt;
|
||||||
}
|
}
|
||||||
self.render_surface(surface, x, y);
|
self.render_surface(surface, x, y, max_width, max_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32) {
|
pub fn render_surface(
|
||||||
|
&mut self,
|
||||||
|
surface: &WlSurface,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
let (x, y) = self.base.scale_point(x, y);
|
let (x, y) = self.base.scale_point(x, y);
|
||||||
self.render_surface_scaled(surface, x, y, None);
|
self.render_surface_scaled(surface, x, y, None, max_width, max_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_surface_scaled(
|
pub fn render_surface_scaled(
|
||||||
|
|
@ -268,6 +316,8 @@ impl Renderer<'_> {
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
pos_rel: Option<(i32, i32)>,
|
pos_rel: Option<(i32, i32)>,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
) {
|
) {
|
||||||
let children = surface.children.borrow();
|
let children = surface.children.borrow();
|
||||||
let buffer = match surface.buffer.get() {
|
let buffer = match surface.buffer.get() {
|
||||||
|
|
@ -302,15 +352,17 @@ impl Renderer<'_> {
|
||||||
x + x1,
|
x + x1,
|
||||||
y + y1,
|
y + y1,
|
||||||
Some((pos.x1(), pos.y1())),
|
Some((pos.x1(), pos.y1())),
|
||||||
|
max_width,
|
||||||
|
max_height,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
render!(&children.below);
|
render!(&children.below);
|
||||||
self.render_buffer(&buffer, x, y, &tpoints, size);
|
self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height);
|
||||||
render!(&children.above);
|
render!(&children.above);
|
||||||
} else {
|
} else {
|
||||||
self.render_buffer(&buffer, x, y, &tpoints, size);
|
self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height);
|
||||||
}
|
}
|
||||||
if self.on_output {
|
if self.on_output {
|
||||||
{
|
{
|
||||||
|
|
@ -329,8 +381,10 @@ impl Renderer<'_> {
|
||||||
buffer: &WlBuffer,
|
buffer: &WlBuffer,
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
tpoints: &[f32; 8],
|
tpoints: BufferPoints,
|
||||||
tsize: (i32, i32),
|
tsize: (i32, i32),
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
) {
|
) {
|
||||||
if let Some(tex) = buffer.texture.get() {
|
if let Some(tex) = buffer.texture.get() {
|
||||||
self.base.render_texture(
|
self.base.render_texture(
|
||||||
|
|
@ -341,6 +395,8 @@ impl Renderer<'_> {
|
||||||
Some(tpoints),
|
Some(tpoints),
|
||||||
Some(tsize),
|
Some(tsize),
|
||||||
self.base.scale,
|
self.base.scale,
|
||||||
|
max_width,
|
||||||
|
max_height,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -374,8 +430,17 @@ impl Renderer<'_> {
|
||||||
self.base.fill_boxes(&title_underline, &uc);
|
self.base.fill_boxes(&title_underline, &uc);
|
||||||
if let Some(title) = floating.title_textures.get(&self.base.scale) {
|
if let Some(title) = floating.title_textures.get(&self.base.scale) {
|
||||||
let (x, y) = self.base.scale_point(x + bw, y + bw);
|
let (x, y) = self.base.scale_point(x + bw, y + bw);
|
||||||
self.base
|
self.base.render_texture(
|
||||||
.render_texture(&title, x, y, ARGB8888, None, None, self.base.scale);
|
&title,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
ARGB8888,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
self.base.scale,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let body = Rect::new_sized(
|
let body = Rect::new_sized(
|
||||||
x + bw,
|
x + bw,
|
||||||
|
|
@ -385,20 +450,18 @@ impl Renderer<'_> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let scissor_body = self.base.scale_rect(body);
|
let scissor_body = self.base.scale_rect(body);
|
||||||
unsafe {
|
child.node_render(
|
||||||
with_scissor(&scissor_body, || {
|
self,
|
||||||
child.node_render(self, body.x1(), body.y1());
|
body.x1(),
|
||||||
});
|
body.y1(),
|
||||||
}
|
scissor_body.width(),
|
||||||
|
scissor_body.height(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
|
||||||
unsafe {
|
let body = surface.position().at_point(x, y);
|
||||||
let body = surface.position().at_point(x, y);
|
let body = self.base.scale_rect(body);
|
||||||
let body = self.base.scale_rect(body);
|
self.render_surface(&surface.surface, x, y, body.width(), body.height());
|
||||||
with_scissor(&body, || {
|
|
||||||
self.render_surface(&surface.surface, x, y);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
199
src/renderer/renderer_base.rs
Normal file
199
src/renderer/renderer_base.rs
Normal file
|
|
@ -0,0 +1,199 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
format::Format,
|
||||||
|
gfx_api::{
|
||||||
|
AbsoluteRect, BufferPoint, BufferPoints, Clear, CopyTexture, FillRect, GfxApiOpt,
|
||||||
|
GfxTexture,
|
||||||
|
},
|
||||||
|
rect::Rect,
|
||||||
|
scale::Scale,
|
||||||
|
theme::Color,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct RendererBase<'a> {
|
||||||
|
pub ops: &'a mut Vec<GfxApiOpt>,
|
||||||
|
pub scaled: bool,
|
||||||
|
pub scale: Scale,
|
||||||
|
pub scalef: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererBase<'_> {
|
||||||
|
pub fn scale(&self) -> Scale {
|
||||||
|
self.scale
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_point(&self, mut x: i32, mut y: i32) -> (i32, i32) {
|
||||||
|
if self.scaled {
|
||||||
|
x = (x as f64 * self.scalef).round() as _;
|
||||||
|
y = (y as f64 * self.scalef).round() as _;
|
||||||
|
}
|
||||||
|
(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_point_f(&self, mut x: f32, mut y: f32) -> (f32, f32) {
|
||||||
|
if self.scaled {
|
||||||
|
x = (x as f64 * self.scalef) as _;
|
||||||
|
y = (y as f64 * self.scalef) as _;
|
||||||
|
}
|
||||||
|
(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_rect(&self, mut rect: Rect) -> Rect {
|
||||||
|
if self.scaled {
|
||||||
|
let x1 = (rect.x1() as f64 * self.scalef).round() as _;
|
||||||
|
let y1 = (rect.y1() as f64 * self.scalef).round() as _;
|
||||||
|
let x2 = (rect.x2() as f64 * self.scalef).round() as _;
|
||||||
|
let y2 = (rect.y2() as f64 * self.scalef).round() as _;
|
||||||
|
rect = Rect::new(x1, y1, x2, y2).unwrap();
|
||||||
|
}
|
||||||
|
rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_rect_f(&self, mut rect: (f32, f32, f32, f32)) -> (f32, f32, f32, f32) {
|
||||||
|
if self.scaled {
|
||||||
|
let x1 = (rect.0 as f64 * self.scalef).round() as _;
|
||||||
|
let y1 = (rect.1 as f64 * self.scalef).round() as _;
|
||||||
|
let x2 = (rect.2 as f64 * self.scalef).round() as _;
|
||||||
|
let y2 = (rect.3 as f64 * self.scalef).round() as _;
|
||||||
|
rect = (x1, y1, x2, y2)
|
||||||
|
}
|
||||||
|
rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self, c: &Color) {
|
||||||
|
self.ops.push(GfxApiOpt::Clear(Clear { color: *c }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_boxes(&mut self, boxes: &[Rect], color: &Color) {
|
||||||
|
self.fill_boxes2(boxes, color, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_boxes2(&mut self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) {
|
||||||
|
if boxes.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (dx, dy) = self.scale_point(dx, dy);
|
||||||
|
for bx in boxes {
|
||||||
|
let bx = self.scale_rect(*bx);
|
||||||
|
self.ops.push(GfxApiOpt::FillRect(FillRect {
|
||||||
|
rect: AbsoluteRect {
|
||||||
|
x1: (bx.x1() + dx) as f32,
|
||||||
|
y1: (bx.y1() + dy) as f32,
|
||||||
|
x2: (bx.x2() + dx) as f32,
|
||||||
|
y2: (bx.y2() + dy) as f32,
|
||||||
|
},
|
||||||
|
color: *color,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_boxes_f(&mut self, boxes: &[(f32, f32, f32, f32)], color: &Color) {
|
||||||
|
self.fill_boxes2_f(boxes, color, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill_boxes2_f(
|
||||||
|
&mut self,
|
||||||
|
boxes: &[(f32, f32, f32, f32)],
|
||||||
|
color: &Color,
|
||||||
|
dx: f32,
|
||||||
|
dy: f32,
|
||||||
|
) {
|
||||||
|
if boxes.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (dx, dy) = self.scale_point_f(dx, dy);
|
||||||
|
for bx in boxes {
|
||||||
|
let (x1, y1, x2, y2) = self.scale_rect_f(*bx);
|
||||||
|
self.ops.push(GfxApiOpt::FillRect(FillRect {
|
||||||
|
rect: AbsoluteRect {
|
||||||
|
x1: x1 + dx,
|
||||||
|
y1: y1 + dy,
|
||||||
|
x2: x2 + dx,
|
||||||
|
y2: y2 + dy,
|
||||||
|
},
|
||||||
|
color: *color,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_texture(
|
||||||
|
&mut self,
|
||||||
|
texture: &Rc<dyn GfxTexture>,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
format: &'static Format,
|
||||||
|
tpoints: Option<BufferPoints>,
|
||||||
|
tsize: Option<(i32, i32)>,
|
||||||
|
tscale: Scale,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
|
let mut texcoord = tpoints.unwrap_or(BufferPoints {
|
||||||
|
top_left: BufferPoint { x: 0.0, y: 0.0 },
|
||||||
|
top_right: BufferPoint { x: 1.0, y: 0.0 },
|
||||||
|
bottom_left: BufferPoint { x: 0.0, y: 1.0 },
|
||||||
|
bottom_right: BufferPoint { x: 1.0, y: 1.0 },
|
||||||
|
});
|
||||||
|
|
||||||
|
let (twidth, theight) = if let Some(size) = tsize {
|
||||||
|
size
|
||||||
|
} else {
|
||||||
|
let (mut w, mut h) = (texture.width(), texture.height());
|
||||||
|
if tscale != self.scale {
|
||||||
|
let tscale = tscale.to_f64();
|
||||||
|
w = (w as f64 * self.scalef / tscale).round() as _;
|
||||||
|
h = (h as f64 * self.scalef / tscale).round() as _;
|
||||||
|
}
|
||||||
|
(w, h)
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! clamp {
|
||||||
|
($desired:ident, $max:ident, $([$far:ident, $near:ident]),*) => {
|
||||||
|
if $desired > $max {
|
||||||
|
let $desired = $desired as f32;
|
||||||
|
let $max = $max as f32;
|
||||||
|
let factor = $max / $desired;
|
||||||
|
$(
|
||||||
|
let dx = (texcoord.$far.x - texcoord.$near.x) * factor;
|
||||||
|
texcoord.$far.x = texcoord.$near.x + dx;
|
||||||
|
let dy = (texcoord.$far.y - texcoord.$near.y) * factor;
|
||||||
|
texcoord.$far.y = texcoord.$near.y + dy;
|
||||||
|
)*
|
||||||
|
$max
|
||||||
|
} else {
|
||||||
|
$desired as f32
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let twidth = clamp!(
|
||||||
|
twidth,
|
||||||
|
max_width,
|
||||||
|
[top_right, top_left],
|
||||||
|
[bottom_right, bottom_left]
|
||||||
|
);
|
||||||
|
let theight = clamp!(
|
||||||
|
theight,
|
||||||
|
max_height,
|
||||||
|
[bottom_left, top_left],
|
||||||
|
[bottom_right, top_right]
|
||||||
|
);
|
||||||
|
|
||||||
|
let x = x as f32;
|
||||||
|
let y = y as f32;
|
||||||
|
|
||||||
|
self.ops.push(GfxApiOpt::CopyTexture(CopyTexture {
|
||||||
|
tex: texture.clone(),
|
||||||
|
format,
|
||||||
|
source: texcoord,
|
||||||
|
target: AbsoluteRect {
|
||||||
|
x1: x,
|
||||||
|
y1: y,
|
||||||
|
x2: x + twidth,
|
||||||
|
y2: y + theight,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
render::RenderError,
|
gfx_api::GfxError,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
video::{
|
video::{
|
||||||
|
|
@ -24,7 +24,7 @@ pub enum ScreenshooterError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
GbmError(#[from] GbmError),
|
GbmError(#[from] GbmError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
RenderError(#[from] RenderError),
|
RenderError(#[from] GfxError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
DrmError(#[from] DrmError),
|
DrmError(#[from] DrmError),
|
||||||
}
|
}
|
||||||
|
|
@ -47,13 +47,14 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
||||||
format: XRGB8888,
|
format: XRGB8888,
|
||||||
modifier: INVALID_MODIFIER,
|
modifier: INVALID_MODIFIER,
|
||||||
};
|
};
|
||||||
let bo = ctx.gbm.create_bo(
|
let gbm = ctx.gbm();
|
||||||
|
let bo = gbm.create_bo(
|
||||||
extents.width(),
|
extents.width(),
|
||||||
extents.height(),
|
extents.height(),
|
||||||
&format,
|
&format,
|
||||||
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
||||||
)?;
|
)?;
|
||||||
let fb = ctx.dmabuf_fb(bo.dmabuf())?;
|
let fb = ctx.clone().dmabuf_fb(bo.dmabuf())?;
|
||||||
fb.render(
|
fb.render(
|
||||||
state.root.deref(),
|
state.root.deref(),
|
||||||
state,
|
state,
|
||||||
|
|
@ -63,6 +64,6 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
||||||
Scale::from_int(1),
|
Scale::from_int(1),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
let drm = ctx.gbm.drm.dup_render()?.fd().clone();
|
let drm = gbm.drm.dup_render()?.fd().clone();
|
||||||
Ok(Screenshot { drm, bo })
|
Ok(Screenshot { drm, bo })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/state.rs
10
src/state.rs
|
|
@ -13,6 +13,7 @@ use {
|
||||||
cursor::{Cursor, ServerCursors},
|
cursor::{Cursor, ServerCursors},
|
||||||
dbus::Dbus,
|
dbus::Dbus,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
|
gfx_api::GfxContext,
|
||||||
globals::{Globals, GlobalsError, WaylandGlobal},
|
globals::{Globals, GlobalsError, WaylandGlobal},
|
||||||
ifs::{
|
ifs::{
|
||||||
ext_session_lock_v1::ExtSessionLockV1,
|
ext_session_lock_v1::ExtSessionLockV1,
|
||||||
|
|
@ -31,7 +32,6 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::RenderContext,
|
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
theme::Theme,
|
theme::Theme,
|
||||||
tree::{
|
tree::{
|
||||||
|
|
@ -69,7 +69,7 @@ pub struct State {
|
||||||
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
||||||
pub default_keymap: Rc<XkbKeymap>,
|
pub default_keymap: Rc<XkbKeymap>,
|
||||||
pub eng: Rc<AsyncEngine>,
|
pub eng: Rc<AsyncEngine>,
|
||||||
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
pub render_ctx: CloneCell<Option<Rc<dyn GfxContext>>>,
|
||||||
pub render_ctx_version: NumCell<u32>,
|
pub render_ctx_version: NumCell<u32>,
|
||||||
pub render_ctx_ever_initialized: Cell<bool>,
|
pub render_ctx_ever_initialized: Cell<bool>,
|
||||||
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
|
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
|
||||||
|
|
@ -305,8 +305,8 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_render_ctx(&self, ctx: Option<&Rc<RenderContext>>) {
|
pub fn set_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
|
||||||
self.render_ctx.set(ctx.cloned());
|
self.render_ctx.set(ctx.clone());
|
||||||
self.render_ctx_version.fetch_add(1);
|
self.render_ctx_version.fetch_add(1);
|
||||||
self.cursors.set(None);
|
self.cursors.set(None);
|
||||||
|
|
||||||
|
|
@ -364,7 +364,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
for watcher in self.render_ctx_watchers.lock().values() {
|
for watcher in self.render_ctx_watchers.lock().values() {
|
||||||
watcher.send_render_ctx(ctx);
|
watcher.send_render_ctx(ctx.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scs = vec![];
|
let mut scs = vec![];
|
||||||
|
|
|
||||||
25
src/text.rs
25
src/text.rs
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::ARGB8888,
|
format::ARGB8888,
|
||||||
|
gfx_api::{GfxContext, GfxError, GfxTexture},
|
||||||
pango::{
|
pango::{
|
||||||
consts::{
|
consts::{
|
||||||
CAIRO_FORMAT_ARGB32, CAIRO_OPERATOR_SOURCE, PANGO_ELLIPSIZE_END, PANGO_SCALE,
|
CAIRO_FORMAT_ARGB32, CAIRO_OPERATOR_SOURCE, PANGO_ELLIPSIZE_END, PANGO_SCALE,
|
||||||
|
|
@ -9,7 +10,6 @@ use {
|
||||||
PangoLayout,
|
PangoLayout,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{RenderContext, RenderError, Texture},
|
|
||||||
theme::Color,
|
theme::Color,
|
||||||
},
|
},
|
||||||
std::{ops::Neg, rc::Rc},
|
std::{ops::Neg, rc::Rc},
|
||||||
|
|
@ -27,7 +27,7 @@ pub enum TextError {
|
||||||
#[error("Could not create a pango layout")]
|
#[error("Could not create a pango layout")]
|
||||||
CreateLayout(#[source] PangoError),
|
CreateLayout(#[source] PangoError),
|
||||||
#[error("Could not import the rendered text")]
|
#[error("Could not import the rendered text")]
|
||||||
RenderError(#[source] RenderError),
|
RenderError(#[source] GfxError),
|
||||||
#[error("Could not access the cairo image data")]
|
#[error("Could not access the cairo image data")]
|
||||||
ImageData(#[source] PangoError),
|
ImageData(#[source] PangoError),
|
||||||
}
|
}
|
||||||
|
|
@ -94,21 +94,21 @@ pub fn measure(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
font: &str,
|
font: &str,
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Color,
|
color: Color,
|
||||||
scale: Option<f64>,
|
scale: Option<f64>,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<dyn GfxTexture>, TextError> {
|
||||||
render2(
|
render2(
|
||||||
ctx, 1, None, width, height, 1, font, text, color, true, false, scale,
|
ctx, 1, None, width, height, 1, font, text, color, true, false, scale,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render2(
|
fn render2(
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
x: i32,
|
x: i32,
|
||||||
y: Option<i32>,
|
y: Option<i32>,
|
||||||
width: i32,
|
width: i32,
|
||||||
|
|
@ -120,7 +120,7 @@ fn render2(
|
||||||
ellipsize: bool,
|
ellipsize: bool,
|
||||||
markup: bool,
|
markup: bool,
|
||||||
scale: Option<f64>,
|
scale: Option<f64>,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<dyn GfxTexture>, TextError> {
|
||||||
let data = create_data(font, width, height, scale)?;
|
let data = create_data(font, width, height, scale)?;
|
||||||
if ellipsize {
|
if ellipsize {
|
||||||
data.layout
|
data.layout
|
||||||
|
|
@ -144,21 +144,24 @@ fn render2(
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => return Err(TextError::ImageData(e)),
|
Err(e) => return Err(TextError::ImageData(e)),
|
||||||
};
|
};
|
||||||
match ctx.shmem_texture(bytes, ARGB8888, width, height, data.image.stride()) {
|
match ctx
|
||||||
|
.clone()
|
||||||
|
.shmem_texture(bytes, ARGB8888, width, height, data.image.stride())
|
||||||
|
{
|
||||||
Ok(t) => Ok(t),
|
Ok(t) => Ok(t),
|
||||||
Err(e) => Err(TextError::RenderError(e)),
|
Err(e) => Err(TextError::RenderError(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_fitting(
|
pub fn render_fitting(
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
height: Option<i32>,
|
height: Option<i32>,
|
||||||
font: &str,
|
font: &str,
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Color,
|
color: Color,
|
||||||
markup: bool,
|
markup: bool,
|
||||||
scale: Option<f64>,
|
scale: Option<f64>,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<dyn GfxTexture>, TextError> {
|
||||||
render_fitting2(ctx, height, font, text, color, markup, scale, false).map(|(a, _)| a)
|
render_fitting2(ctx, height, font, text, color, markup, scale, false).map(|(a, _)| a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +173,7 @@ pub struct TextMeasurement {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_fitting2(
|
pub fn render_fitting2(
|
||||||
ctx: &Rc<RenderContext>,
|
ctx: &Rc<dyn GfxContext>,
|
||||||
height: Option<i32>,
|
height: Option<i32>,
|
||||||
font: &str,
|
font: &str,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
|
@ -178,7 +181,7 @@ pub fn render_fitting2(
|
||||||
markup: bool,
|
markup: bool,
|
||||||
scale: Option<f64>,
|
scale: Option<f64>,
|
||||||
include_measurements: bool,
|
include_measurements: bool,
|
||||||
) -> Result<(Rc<Texture>, TextMeasurement), TextError> {
|
) -> Result<(Rc<dyn GfxTexture>, TextMeasurement), TextError> {
|
||||||
let measurement = measure(font, text, markup, scale, include_measurements)?;
|
let measurement = measure(font, text, markup, scale, include_measurements)?;
|
||||||
let y = match height {
|
let y = match height {
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
|
|
|
||||||
25
src/theme.rs
25
src/theme.rs
|
|
@ -1,6 +1,9 @@
|
||||||
use std::cell::{Cell, RefCell};
|
use std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
cmp::Ordering,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub r: f32,
|
pub r: f32,
|
||||||
pub g: f32,
|
pub g: f32,
|
||||||
|
|
@ -8,6 +11,24 @@ pub struct Color {
|
||||||
pub a: f32,
|
pub a: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for Color {}
|
||||||
|
|
||||||
|
impl Ord for Color {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.r
|
||||||
|
.total_cmp(&other.r)
|
||||||
|
.then_with(|| self.g.total_cmp(&other.g))
|
||||||
|
.then_with(|| self.b.total_cmp(&other.b))
|
||||||
|
.then_with(|| self.a.total_cmp(&other.a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Color {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_f32(c: u8) -> f32 {
|
fn to_f32(c: u8) -> f32 {
|
||||||
c as f32 / 255f32
|
c as f32 / 255f32
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
src/tree.rs
13
src/tree.rs
|
|
@ -8,7 +8,7 @@ use {
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
utils::numcell::NumCell,
|
utils::numcell::NumCell,
|
||||||
xkbcommon::ModifierState,
|
xkbcommon::ModifierState,
|
||||||
},
|
},
|
||||||
|
|
@ -137,10 +137,19 @@ pub trait Node: 'static {
|
||||||
let _ = (child, active, depth);
|
let _ = (child, active, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
max_width: i32,
|
||||||
|
max_height: i32,
|
||||||
|
) {
|
||||||
let _ = renderer;
|
let _ = renderer;
|
||||||
let _ = x;
|
let _ = x;
|
||||||
let _ = y;
|
let _ = y;
|
||||||
|
let _ = max_width;
|
||||||
|
let _ = max_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_client(&self) -> Option<Rc<Client>> {
|
fn node_client(&self) -> Option<Rc<Client>> {
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ use {
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::GfxTexture,
|
||||||
ifs::wl_seat::{
|
ifs::wl_seat::{
|
||||||
collect_kb_foci, collect_kb_foci2, wl_pointer::PendingScroll, NodeSeatState, SeatId,
|
collect_kb_foci, collect_kb_foci2, wl_pointer::PendingScroll, NodeSeatState, SeatId,
|
||||||
WlSeatGlobal, BTN_LEFT,
|
WlSeatGlobal, BTN_LEFT,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Renderer, Texture},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
|
|
@ -76,7 +77,7 @@ tree_id!(ContainerNodeId);
|
||||||
pub struct ContainerTitle {
|
pub struct ContainerTitle {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
pub tex: Rc<Texture>,
|
pub tex: Rc<dyn GfxTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -736,7 +737,6 @@ impl ContainerNode {
|
||||||
child.node.tl_set_visible(true);
|
child.node.tl_set_visible(true);
|
||||||
// log::info!("activate_child2");
|
// log::info!("activate_child2");
|
||||||
self.schedule_layout();
|
self.schedule_layout();
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1086,7 +1086,14 @@ impl Node for ContainerNode {
|
||||||
.node_child_active_changed(self.deref(), active, depth + 1);
|
.node_child_active_changed(self.deref(), active, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_container(self, x, y);
|
renderer.render_container(self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use {
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
ifs::wl_seat::{NodeSeatState, WlSeatGlobal},
|
ifs::wl_seat::{NodeSeatState, WlSeatGlobal},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode,
|
walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode,
|
||||||
},
|
},
|
||||||
|
|
@ -111,7 +111,14 @@ impl Node for DisplayNode {
|
||||||
FindTreeResult::AcceptsInput
|
FindTreeResult::AcceptsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_display(self, x, y);
|
renderer.render_display(self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ use {
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::GfxTexture,
|
||||||
ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT},
|
ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Renderer, Texture},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
|
|
@ -43,7 +44,7 @@ pub struct FloatNode {
|
||||||
pub layout_scheduled: Cell<bool>,
|
pub layout_scheduled: Cell<bool>,
|
||||||
pub render_titles_scheduled: Cell<bool>,
|
pub render_titles_scheduled: Cell<bool>,
|
||||||
pub title: RefCell<String>,
|
pub title: RefCell<String>,
|
||||||
pub title_textures: CopyHashMap<Scale, Rc<Texture>>,
|
pub title_textures: CopyHashMap<Scale, Rc<dyn GfxTexture>>,
|
||||||
seats: RefCell<AHashMap<SeatId, SeatState>>,
|
seats: RefCell<AHashMap<SeatId, SeatState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,7 +421,14 @@ impl Node for FloatNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_floating(self, x, y)
|
renderer.render_floating(self, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::{GfxFramebuffer, GfxTexture},
|
||||||
ifs::{
|
ifs::{
|
||||||
jay_output::JayOutput,
|
jay_output::JayOutput,
|
||||||
jay_screencast::JayScreencast,
|
jay_screencast::JayScreencast,
|
||||||
|
|
@ -19,7 +20,7 @@ use {
|
||||||
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP},
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Framebuffer, Renderer, Texture},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
|
|
@ -77,7 +78,7 @@ pub async fn output_render_data(state: Rc<State>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputNode {
|
impl OutputNode {
|
||||||
pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) {
|
pub fn perform_screencopies(&self, fb: &dyn GfxFramebuffer, tex: &Rc<dyn GfxTexture>) {
|
||||||
if let Some(workspace) = self.workspace.get() {
|
if let Some(workspace) = self.workspace.get() {
|
||||||
if !workspace.capture.get() {
|
if !workspace.capture.get() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -464,14 +465,14 @@ pub struct OutputTitle {
|
||||||
pub x2: i32,
|
pub x2: i32,
|
||||||
pub tex_x: i32,
|
pub tex_x: i32,
|
||||||
pub tex_y: i32,
|
pub tex_y: i32,
|
||||||
pub tex: Rc<Texture>,
|
pub tex: Rc<dyn GfxTexture>,
|
||||||
pub ws: Rc<WorkspaceNode>,
|
pub ws: Rc<WorkspaceNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputStatus {
|
pub struct OutputStatus {
|
||||||
pub tex_x: i32,
|
pub tex_x: i32,
|
||||||
pub tex_y: i32,
|
pub tex_y: i32,
|
||||||
pub tex: Rc<Texture>,
|
pub tex: Rc<dyn GfxTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
|
@ -620,7 +621,14 @@ impl Node for OutputNode {
|
||||||
FindTreeResult::AcceptsInput
|
FindTreeResult::AcceptsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_output(self, x, y);
|
renderer.render_output(self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ use {
|
||||||
client::Client,
|
client::Client,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
gfx_api::GfxTexture,
|
||||||
ifs::wl_seat::{NodeSeatState, WlSeatGlobal},
|
ifs::wl_seat::{NodeSeatState, WlSeatGlobal},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Renderer, Texture},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
|
|
@ -24,7 +25,7 @@ pub struct PlaceholderNode {
|
||||||
id: PlaceholderNodeId,
|
id: PlaceholderNodeId,
|
||||||
toplevel: ToplevelData,
|
toplevel: ToplevelData,
|
||||||
destroyed: Cell<bool>,
|
destroyed: Cell<bool>,
|
||||||
pub textures: SmallMap<Scale, Rc<Texture>, 2>,
|
pub textures: SmallMap<Scale, Rc<dyn GfxTexture>, 2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlaceholderNode {
|
impl PlaceholderNode {
|
||||||
|
|
@ -122,7 +123,14 @@ impl Node for PlaceholderNode {
|
||||||
FindTreeResult::AcceptsInput
|
FindTreeResult::AcceptsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_placeholder(self, x, y);
|
renderer.render_placeholder(self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use {
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
renderer::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction,
|
container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction,
|
||||||
FindTreeResult, FoundNode, Node, NodeId, NodeVisitorBase, OutputNode, StackedNode,
|
FindTreeResult, FoundNode, Node, NodeId, NodeVisitorBase, OutputNode, StackedNode,
|
||||||
|
|
@ -170,7 +170,14 @@ impl Node for WorkspaceNode {
|
||||||
FindTreeResult::AcceptsInput
|
FindTreeResult::AcceptsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) {
|
fn node_render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
_max_width: i32,
|
||||||
|
_max_height: i32,
|
||||||
|
) {
|
||||||
renderer.render_workspace(self, x, y);
|
renderer.render_workspace(self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -814,7 +814,7 @@ pub fn mode_getconnector(
|
||||||
modes: modes.into_iter().map(|m| m.into()).collect(),
|
modes: modes.into_iter().map(|m| m.into()).collect(),
|
||||||
props: props
|
props: props
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(prop_values.into_iter())
|
.zip(prop_values)
|
||||||
.map(|(id, value)| DrmPropertyValue {
|
.map(|(id, value)| DrmPropertyValue {
|
||||||
id: DrmProperty(id),
|
id: DrmProperty(id),
|
||||||
value,
|
value,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue