diff --git a/build/build.rs b/build/build.rs index 360f5165..1d97d571 100644 --- a/build/build.rs +++ b/build/build.rs @@ -18,6 +18,7 @@ use std::io::BufWriter; use std::path::PathBuf; use std::{env, io}; +mod egl; mod enums; mod tokens; mod wire; @@ -41,6 +42,7 @@ fn main() -> anyhow::Result<()> { wire_dbus::main()?; wire_xcon::main()?; enums::main()?; + egl::main()?; println!("cargo:rerun-if-changed=build/build.rs"); Ok(()) diff --git a/build/egl.rs b/build/egl.rs new file mode 100644 index 00000000..aef86616 --- /dev/null +++ b/build/egl.rs @@ -0,0 +1,143 @@ +use crate::open; +use std::fmt::Write as FmtWrite; +use std::io::Write; + +fn write_egl_procs(f: &mut W) -> anyhow::Result<()> { + let map = [ + ( + "eglGetPlatformDisplayEXT", + "EGLDisplay", + &[ + ("platform", "EGLenum"), + ("native_display", "*mut u8"), + ("attrib_list", "*const EGLint"), + ][..], + ), + ( + "eglCreateImageKHR", + "EGLImageKHR", + &[ + ("dpy", "EGLDisplay"), + ("ctx", "EGLContext"), + ("target", "EGLenum"), + ("buffer", "EGLClientBuffer"), + ("attrib_list", "*const EGLint"), + ][..], + ), + ( + "eglDestroyImageKHR", + "EGLBoolean", + &[("dpy", "EGLDisplay"), ("image", "EGLImageKHR")][..], + ), + ( + "eglQueryDmaBufFormatsEXT", + "EGLBoolean", + &[ + ("dpy", "EGLDisplay"), + ("max_formats", "EGLint"), + ("formats", "*mut EGLint"), + ("num_formats", "*mut EGLint"), + ][..], + ), + ( + "eglQueryDmaBufModifiersEXT", + "EGLBoolean", + &[ + ("dpy", "EGLDisplay"), + ("format", "EGLint"), + ("max_modifiers", "EGLint"), + ("modifiers", "*mut EGLuint64KHR"), + ("external_only", "*mut EGLBoolean"), + ("num_modifiers", "*mut EGLint"), + ][..], + ), + ( + "eglDebugMessageControlKHR", + "EGLint", + &[ + ("callback", "EGLDEBUGPROCKHR"), + ("attrib_list", "*const EGLAttrib"), + ][..], + ), + ( + "eglQueryDisplayAttribEXT", + "EGLBoolean", + &[ + ("dpy", "EGLDisplay"), + ("attribute", "EGLint"), + ("value", "*mut EGLAttrib"), + ][..], + ), + ( + "glEGLImageTargetRenderbufferStorageOES", + "()", + &[("target", "GLenum"), ("image", "GLeglImageOES")][..], + ), + ( + "glEGLImageTargetTexture2DOES", + "()", + &[("target", "GLenum"), ("image", "GLeglImageOES")][..], + ), + ]; + + writeln!(f, "use std::ptr;")?; + writeln!(f, "use super::gl::sys::*;")?; + writeln!(f, "use super::egl::sys::*;")?; + writeln!(f)?; + writeln!(f, "#[derive(Copy, Clone, Debug)]")?; + writeln!(f, "pub struct ExtProc {{")?; + for (name, _, _) in map.iter() { + writeln!(f, " {}: *mut u8,", name)?; + } + writeln!(f, "}}")?; + writeln!(f)?; + writeln!(f, "unsafe impl Sync for ExtProc {{ }}")?; + writeln!(f, "unsafe impl Send for ExtProc {{ }}")?; + writeln!(f)?; + writeln!(f, "impl ExtProc {{")?; + writeln!(f, " pub fn load() -> Self {{")?; + writeln!(f, " Self {{")?; + for (name, _, _) in map.iter().copied() { + writeln!( + f, + " {}: unsafe {{ eglGetProcAddress(\"{}\\0\".as_ptr() as _) }},", + name, name + )?; + } + writeln!(f, " }}")?; + writeln!(f, " }}")?; + for (name, ret, args) in map.iter().copied() { + let mut args_names = String::new(); + let mut args_full = String::new(); + let mut args_tys = String::new(); + for (name, ty) in args.iter().copied() { + write!(args_full, "{}: {}, ", name, ty)?; + write!(args_names, "{}, ", name)?; + write!(args_tys, "{}, ", ty)?; + } + writeln!(f)?; + writeln!( + f, + " pub(super) unsafe fn {}(&self, {}) -> {} {{", + name, args_full, ret + )?; + writeln!(f, " if self.{}.is_null() {{", name)?; + writeln!(f, " panic!(\"Could not load `{}`\");", name)?; + writeln!(f, " }}")?; + writeln!( + f, + " ptr::read(&self.{} as *const *mut u8 as *const unsafe extern fn({}) -> {})({})", + name, args_tys, ret, args_names + )?; + writeln!(f, " }}")?; + } + writeln!(f, "}}")?; + Ok(()) +} + +pub fn main() -> anyhow::Result<()> { + let mut f = open("egl_procs.rs")?; + write_egl_procs(&mut f)?; + + Ok(()) +} diff --git a/build/enums.rs b/build/enums.rs index 540b5b24..7ec9bb49 100644 --- a/build/enums.rs +++ b/build/enums.rs @@ -1,7 +1,6 @@ use crate::open; use repc::layout::{Type, TypeVariant}; use std::env; -use std::fmt::Write as FmtWrite; use std::io::Write; #[allow(unused_macros)] @@ -9,9 +8,6 @@ use std::io::Write; #[path = "../src/macros.rs"] mod macros; -#[path = "../src/pixman/consts.rs"] -mod pixman; - #[path = "../src/xkbcommon/consts.rs"] mod xkbcommon; @@ -51,153 +47,6 @@ fn write_ty(f: &mut W, vals: &[i32], ty: &str) -> anyhow::Result<()> { Ok(()) } -fn write_egl_procs(f: &mut W) -> anyhow::Result<()> { - let map = [ - ( - "eglGetPlatformDisplayEXT", - "EGLDisplay", - &[ - ("platform", "EGLenum"), - ("native_display", "*mut u8"), - ("attrib_list", "*const EGLint"), - ][..], - ), - ( - "eglCreateImageKHR", - "EGLImageKHR", - &[ - ("dpy", "EGLDisplay"), - ("ctx", "EGLContext"), - ("target", "EGLenum"), - ("buffer", "EGLClientBuffer"), - ("attrib_list", "*const EGLint"), - ][..], - ), - ( - "eglDestroyImageKHR", - "EGLBoolean", - &[("dpy", "EGLDisplay"), ("image", "EGLImageKHR")][..], - ), - ( - "eglQueryDmaBufFormatsEXT", - "EGLBoolean", - &[ - ("dpy", "EGLDisplay"), - ("max_formats", "EGLint"), - ("formats", "*mut EGLint"), - ("num_formats", "*mut EGLint"), - ][..], - ), - ( - "eglQueryDmaBufModifiersEXT", - "EGLBoolean", - &[ - ("dpy", "EGLDisplay"), - ("format", "EGLint"), - ("max_modifiers", "EGLint"), - ("modifiers", "*mut EGLuint64KHR"), - ("external_only", "*mut EGLBoolean"), - ("num_modifiers", "*mut EGLint"), - ][..], - ), - ( - "eglDebugMessageControlKHR", - "EGLint", - &[ - ("callback", "EGLDEBUGPROCKHR"), - ("attrib_list", "*const EGLAttrib"), - ][..], - ), - ( - "eglQueryDisplayAttribEXT", - "EGLBoolean", - &[ - ("dpy", "EGLDisplay"), - ("attribute", "EGLint"), - ("value", "*mut EGLAttrib"), - ][..], - ), - ( - "eglQueryDeviceStringEXT", - "*const c::c_char", - &[("device", "EGLDeviceEXT"), ("name", "EGLint")][..], - ), - ( - "eglQueryDevicesEXT", - "EGLBoolean", - &[ - ("max_devices", "EGLint"), - ("devices", "*mut EGLDeviceEXT"), - ("num_devices", "*mut EGLint"), - ][..], - ), - ( - "glEGLImageTargetRenderbufferStorageOES", - "()", - &[("target", "GLenum"), ("image", "GLeglImageOES")][..], - ), - ( - "glEGLImageTargetTexture2DOES", - "()", - &[("target", "GLenum"), ("image", "GLeglImageOES")][..], - ), - ]; - - writeln!(f, "use std::ptr;")?; - writeln!(f, "use super::gl::sys::*;")?; - writeln!(f, "use super::egl::sys::*;")?; - writeln!(f)?; - writeln!(f, "#[derive(Copy, Clone, Debug)]")?; - writeln!(f, "pub struct ExtProc {{")?; - for (name, _, _) in map.iter() { - writeln!(f, " {}: *mut u8,", name)?; - } - writeln!(f, "}}")?; - writeln!(f)?; - writeln!(f, "unsafe impl Sync for ExtProc {{ }}")?; - writeln!(f, "unsafe impl Send for ExtProc {{ }}")?; - writeln!(f)?; - writeln!(f, "impl ExtProc {{")?; - writeln!(f, " pub fn load() -> Self {{")?; - writeln!(f, " Self {{")?; - for (name, _, _) in map.iter().copied() { - writeln!( - f, - " {}: unsafe {{ eglGetProcAddress(\"{}\\0\".as_ptr() as _) }},", - name, name - )?; - } - writeln!(f, " }}")?; - writeln!(f, " }}")?; - for (name, ret, args) in map.iter().copied() { - let mut args_names = String::new(); - let mut args_full = String::new(); - let mut args_tys = String::new(); - for (name, ty) in args.iter().copied() { - write!(args_full, "{}: {}, ", name, ty)?; - write!(args_names, "{}, ", name)?; - write!(args_tys, "{}, ", ty)?; - } - writeln!(f)?; - writeln!( - f, - " pub(super) unsafe fn {}(&self, {}) -> {} {{", - name, args_full, ret - )?; - writeln!(f, " if self.{}.is_null() {{", name)?; - writeln!(f, " panic!(\"Could not load `{}`\");", name)?; - writeln!(f, " }}")?; - writeln!( - f, - " ptr::read(&self.{} as *const *mut u8 as *const unsafe extern fn({}) -> {})({})", - name, args_tys, ret, args_names - )?; - writeln!(f, " }}")?; - } - writeln!(f, "}}")?; - Ok(()) -} - pub fn main() -> anyhow::Result<()> { let mut f = open("libinput_tys.rs")?; write_ty( @@ -270,10 +119,6 @@ pub fn main() -> anyhow::Result<()> { "libinput_config_accel_profile", )?; - let mut f = open("pixman_tys.rs")?; - write_ty(&mut f, pixman::FORMATS, "PixmanFormat")?; - write_ty(&mut f, pixman::OPS, "PixmanOp")?; - let mut f = open("pango_tys.rs")?; write_ty(&mut f, pango::CAIRO_FORMATS, "cairo_format_t")?; write_ty(&mut f, pango::CAIRO_STATUSES, "cairo_status_t")?; @@ -296,8 +141,5 @@ pub fn main() -> anyhow::Result<()> { )?; write_ty(&mut f, xkbcommon::XKB_KEY_DIRECTION, "xkb_key_direction")?; - let mut f = open("egl_procs.rs")?; - write_egl_procs(&mut f)?; - Ok(()) } diff --git a/src/format.rs b/src/format.rs index 9864d3a7..ee89588d 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,4 +1,3 @@ -use crate::pixman; use crate::render::sys::{GLint, GL_BGRA_EXT, GL_UNSIGNED_BYTE}; use crate::utils::debug_fn::debug_fn; use ahash::AHashMap; @@ -9,7 +8,6 @@ use std::fmt::{Debug, Write}; pub struct Format { pub name: &'static str, pub bpp: u32, - pub pixman: Option, pub gl_format: GLint, pub gl_type: GLint, pub drm: u32, @@ -66,7 +64,6 @@ pub static FORMATS: &[Format] = &[ Format { name: "argb8888", bpp: 4, - pixman: Some(pixman::A8R8G8B8), gl_format: GL_BGRA_EXT, gl_type: GL_UNSIGNED_BYTE, drm: ARGB8888_DRM, @@ -76,7 +73,6 @@ pub static FORMATS: &[Format] = &[ Format { name: "xrgb8888", bpp: 4, - pixman: Some(pixman::X8R8G8B8), gl_format: GL_BGRA_EXT, gl_type: GL_UNSIGNED_BYTE, drm: XRGB8888_DRM, diff --git a/src/ifs/wl_region.rs b/src/ifs/wl_region.rs index 4d18619b..80206685 100644 --- a/src/ifs/wl_region.rs +++ b/src/ifs/wl_region.rs @@ -1,7 +1,6 @@ use crate::client::{Client, ClientError}; use crate::leaks::Tracker; use crate::object::Object; -use crate::pixman::Region; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; use crate::wire::wl_region::*; @@ -9,11 +8,12 @@ use crate::wire::WlRegionId; use std::cell::RefCell; use std::rc::Rc; use thiserror::Error; +use crate::rect::{Rect, Region, RegionBuilder}; pub struct WlRegion { id: WlRegionId, client: Rc, - rect: RefCell, + region: RefCell, pub tracker: Tracker, } @@ -22,13 +22,13 @@ impl WlRegion { Self { id, client: client.clone(), - rect: RefCell::new(Region::new()), + region: Default::default(), tracker: Default::default(), } } - pub fn region(&self) -> Region { - self.rect.borrow().clone() + pub fn region(&self) -> Rc { + self.region.borrow_mut().get() } fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { @@ -42,23 +42,18 @@ impl WlRegion { if add.width < 0 || add.height < 0 { return Err(AddError::NegativeExtents); } - let mut rect = self.rect.borrow_mut(); - *rect = rect.add(&Region::rect(add.x, add.y, add.width as _, add.height as _)); + let mut region = self.region.borrow_mut(); + region.add(Rect::new_sized(add.x, add.y, add.width, add.height).unwrap()); Ok(()) } fn subtract(&self, parser: MsgParser<'_, '_>) -> Result<(), SubtractError> { - let subtract: Subtract = self.client.parse(self, parser)?; - if subtract.width < 0 || subtract.height < 0 { + let req: Subtract = self.client.parse(self, parser)?; + if req.width < 0 || req.height < 0 { return Err(SubtractError::NegativeExtents); } - let mut rect = self.rect.borrow_mut(); - *rect = rect.subtract(&Region::rect( - subtract.x, - subtract.y, - subtract.width as _, - subtract.height as _, - )); + let mut region = self.region.borrow_mut(); + region.sub(Rect::new_sized(req.x, req.y, req.width, req.height).unwrap()); Ok(()) } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index e6cb0fd5..fc453a3f 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -16,8 +16,7 @@ use crate::ifs::wl_surface::xdg_surface::XdgSurfaceError; use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error; use crate::leaks::Tracker; use crate::object::Object; -use crate::pixman::Region; -use crate::rect::Rect; +use crate::rect::{Rect, Region}; use crate::render::Renderer; use crate::tree::toplevel::ToplevelNode; use crate::tree::walker::NodeVisitor; @@ -77,8 +76,8 @@ pub struct WlSurface { pub client: Rc, role: Cell, pending: PendingState, - input_region: Cell>, - opaque_region: Cell>, + input_region: Cell>>, + opaque_region: Cell>>, pub extents: Cell, pub buffer_abs_pos: Cell, pub need_extents_update: Cell, @@ -167,8 +166,8 @@ impl SurfaceExt for NoneSurfaceExt { #[derive(Default)] struct PendingState { buffer: Cell)>>>, - opaque_region: Cell>>, - input_region: Cell>>, + opaque_region: Cell>>>, + input_region: Cell>>>, frame_request: RefCell>>, } diff --git a/src/main.rs b/src/main.rs index 97d1e775..23cf9940 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,6 @@ mod logger; mod logind; mod object; mod pango; -mod pixman; mod rect; mod render; mod sighand; diff --git a/src/pixman.rs b/src/pixman.rs deleted file mode 100644 index 0011b11b..00000000 --- a/src/pixman.rs +++ /dev/null @@ -1,110 +0,0 @@ -mod consts; - -include!(concat!(env!("OUT_DIR"), "/pixman_tys.rs")); - -pub use consts::*; -use std::ptr; -use uapi::c; - -#[link(name = "pixman-1")] -#[allow(improper_ctypes)] -extern "C" { - fn pixman_region32_init(region: *mut Region); - fn pixman_region32_init_rect( - region: *mut Region, - x: c::c_int, - y: c::c_int, - width: c::c_uint, - height: c::c_uint, - ); - fn pixman_region32_fini(region: *mut Region); - fn pixman_region32_copy(dst: *mut Region, src: *const Region); - fn pixman_region32_union(dst: *mut Region, a: *const Region, b: *const Region); - fn pixman_region32_subtract(dst: *mut Region, a: *const Region, b: *const Region); -} - -#[repr(C)] -#[derive(Copy, Clone, Default, Debug)] -pub struct Box32 { - pub x1: i32, - pub y1: i32, - pub x2: i32, - pub y2: i32, -} - -#[repr(C)] -#[derive(Copy, Clone, Default, Debug)] -pub struct Color { - red: u16, - green: u16, - blue: u16, - alpha: u16, -} - -#[repr(C)] -struct RegionData { - size: c::c_long, - num_rects: c::c_long, - // rects: [Box32; size], -} - -#[repr(C)] -pub struct Region { - extents: Box32, - data: *mut RegionData, -} - -impl Region { - pub fn new() -> Self { - let mut slf = Region { - extents: Default::default(), - data: ptr::null_mut(), - }; - unsafe { - pixman_region32_init(&mut slf); - } - slf - } - - pub fn rect(x: i32, y: i32, width: i32, height: i32) -> Self { - let mut new = Region::new(); - unsafe { - pixman_region32_init_rect(&mut new, x as _, y as _, width as _, height as _); - } - new - } - - pub fn add(&self, region: &Self) -> Self { - let mut new = Region::new(); - unsafe { - pixman_region32_union(&mut new, self, region); - } - new - } - - pub fn subtract(&self, region: &Self) -> Self { - let mut new = Region::new(); - unsafe { - pixman_region32_subtract(&mut new, self, region); - } - new - } -} - -impl Clone for Region { - fn clone(&self) -> Self { - let mut new = Region::new(); - unsafe { - pixman_region32_copy(&mut new, self); - } - new - } -} - -impl Drop for Region { - fn drop(&mut self) { - unsafe { - pixman_region32_fini(self); - } - } -} diff --git a/src/pixman/consts.rs b/src/pixman/consts.rs deleted file mode 100644 index bbd8d993..00000000 --- a/src/pixman/consts.rs +++ /dev/null @@ -1,192 +0,0 @@ -#![allow(dead_code)] - -pub const fn format(bpp: u32, ty: u32, a: u32, r: u32, g: u32, b: u32) -> i32 { - ((bpp << 24) | (ty << 16) | (a << 12) | (r << 8) | (g << 4) | b) as i32 -} - -pub const fn format_byte(bpp: u32, ty: u32, a: u32, r: u32, g: u32, b: u32) -> i32 { - (((bpp >> 3) << 24) - | (3 << 22) - | (ty << 16) - | ((a >> 3) << 12) - | ((r >> 3) << 8) - | ((g >> 3) << 4) - | (b >> 3)) as i32 -} - -pub const fn format_reshift(val: u32, ofs: u32, num: u32) -> u32 { - ((val >> (ofs)) & ((1 << (num)) - 1)) << ((val >> 22) & 3) -} - -pub const fn format_bpp(f: u32) -> u32 { - format_reshift(f, 24, 8) -} - -pub const fn format_shift(f: u32) -> u32 { - (f >> 22) & 3 -} - -pub const fn format_type(f: u32) -> u32 { - (f >> 16) & 0x3f -} - -pub const fn format_a(f: u32) -> u32 { - format_reshift(f, 12, 4) -} - -pub const fn format_r(f: u32) -> u32 { - format_reshift(f, 8, 4) -} - -pub const fn format_g(f: u32) -> u32 { - format_reshift(f, 4, 4) -} - -pub const fn format_b(f: u32) -> u32 { - format_reshift(f, 0, 4) -} - -pub const fn format_rgb(f: u32) -> u32 { - f & 0xfff -} - -pub const fn format_vis(f: u32) -> u32 { - f & 0xffff -} - -pub const fn format_depth(f: u32) -> u32 { - format_a(f) + format_r(f) + format_g(f) + format_b(f) -} - -pub const TYPE_OTHER: u32 = 0; -pub const TYPE_A: u32 = 1; -pub const TYPE_ARGB: u32 = 2; -pub const TYPE_ABGR: u32 = 3; -pub const TYPE_COLOR: u32 = 4; -pub const TYPE_GRAY: u32 = 5; -pub const TYPE_YUY2: u32 = 6; -pub const TYPE_YV12: u32 = 7; -pub const TYPE_BGRA: u32 = 8; -pub const TYPE_RGBA: u32 = 9; -pub const TYPE_ARGB_SRGB: u32 = 10; -pub const TYPE_RGBA_FLOAT: u32 = 11; - -pub const fn format_color(f: u32) -> bool { - format_type(f) == TYPE_ARGB - || format_type(f) == TYPE_ABGR - || format_type(f) == TYPE_BGRA - || format_type(f) == TYPE_RGBA - || format_type(f) == TYPE_RGBA_FLOAT -} - -cenum! { - Format, FORMATS; - - RGBA_FLOAT = format_byte(128, TYPE_RGBA_FLOAT, 32, 32, 32, 32), - RGB_FLOAT = format_byte(96, TYPE_RGBA_FLOAT, 0, 32, 32, 32), - A8R8G8B8 = format(32, TYPE_ARGB, 8, 8, 8, 8), - X8R8G8B8 = format(32, TYPE_ARGB, 0, 8, 8, 8), - A8B8G8R8 = format(32, TYPE_ABGR, 8, 8, 8, 8), - X8B8G8R8 = format(32, TYPE_ABGR, 0, 8, 8, 8), - B8G8R8A8 = format(32, TYPE_BGRA, 8, 8, 8, 8), - B8G8R8X8 = format(32, TYPE_BGRA, 0, 8, 8, 8), - R8G8B8A8 = format(32, TYPE_RGBA, 8, 8, 8, 8), - R8G8B8X8 = format(32, TYPE_RGBA, 0, 8, 8, 8), - X14R6G6B6 = format(32, TYPE_ARGB, 0, 6, 6, 6), - X2R10G10B10 = format(32, TYPE_ARGB, 0, 10, 10, 10), - A2R10G10B10 = format(32, TYPE_ARGB, 2, 10, 10, 10), - X2B10G10R10 = format(32, TYPE_ABGR, 0, 10, 10, 10), - A2B10G10R10 = format(32, TYPE_ABGR, 2, 10, 10, 10), - A8R8G8B8_SRGB = format(32, TYPE_ARGB_SRGB, 8, 8, 8, 8), - R8G8B8 = format(24, TYPE_ARGB, 0, 8, 8, 8), - B8G8R8 = format(24, TYPE_ABGR, 0, 8, 8, 8), - R5G6B5 = format(16, TYPE_ARGB, 0, 5, 6, 5), - B5G6R5 = format(16, TYPE_ABGR, 0, 5, 6, 5), - A1R5G5B5 = format(16, TYPE_ARGB, 1, 5, 5, 5), - X1R5G5B5 = format(16, TYPE_ARGB, 0, 5, 5, 5), - A1B5G5R5 = format(16, TYPE_ABGR, 1, 5, 5, 5), - X1B5G5R5 = format(16, TYPE_ABGR, 0, 5, 5, 5), - A4R4G4B4 = format(16, TYPE_ARGB, 4, 4, 4, 4), - X4R4G4B4 = format(16, TYPE_ARGB, 0, 4, 4, 4), - A4B4G4R4 = format(16, TYPE_ABGR, 4, 4, 4, 4), - X4B4G4R4 = format(16, TYPE_ABGR, 0, 4, 4, 4), - A8 = format(8, TYPE_A, 8, 0, 0, 0), - R3G3B2 = format(8, TYPE_ARGB, 0, 3, 3, 2), - B2G3R3 = format(8, TYPE_ABGR, 0, 3, 3, 2), - A2R2G2B2 = format(8, TYPE_ARGB, 2, 2, 2, 2), - A2B2G2R2 = format(8, TYPE_ABGR, 2, 2, 2, 2), - C8 = format(8, TYPE_COLOR, 0, 0, 0, 0), - G8 = format(8, TYPE_GRAY, 0, 0, 0, 0), - X4A4 = format(8, TYPE_A, 4, 0, 0, 0), - X4C4 = format(8, TYPE_COLOR, 0, 0, 0, 0), - X4G4 = format(8, TYPE_GRAY, 0, 0, 0, 0), - A4 = format(4, TYPE_A, 4, 0, 0, 0), - R1G2B1 = format(4, TYPE_ARGB, 0, 1, 2, 1), - B1G2R1 = format(4, TYPE_ABGR, 0, 1, 2, 1), - A1R1G1B1 = format(4, TYPE_ARGB, 1, 1, 1, 1), - A1B1G1R1 = format(4, TYPE_ABGR, 1, 1, 1, 1), - C4 = format(4, TYPE_COLOR, 0, 0, 0, 0), - G4 = format(4, TYPE_GRAY, 0, 0, 0, 0), - A1 = format(1, TYPE_A, 1, 0, 0, 0), - G1 = format(1, TYPE_GRAY, 0, 0, 0, 0), - YUY2 = format(16, TYPE_YUY2, 0, 0, 0, 0), - YV12 = format(12, TYPE_YV12, 0, 0, 0, 0), -} - -cenum! { - Op, OPS; - - OP_CLEAR = 0x00, - OP_SRC = 0x01, - OP_DST = 0x02, - OP_OVER = 0x03, - OP_OVER_REVERSE = 0x04, - OP_IN = 0x05, - OP_IN_REVERSE = 0x06, - OP_OUT = 0x07, - OP_OUT_REVERSE = 0x08, - OP_ATOP = 0x09, - OP_ATOP_REVERSE = 0x0a, - OP_XOR = 0x0b, - OP_ADD = 0x0c, - OP_SATURATE = 0x0d, - OP_DISJOINT_CLEAR = 0x10, - OP_DISJOINT_SRC = 0x11, - OP_DISJOINT_DST = 0x12, - OP_DISJOINT_OVER = 0x13, - OP_DISJOINT_OVER_REVERSE = 0x14, - OP_DISJOINT_IN = 0x15, - OP_DISJOINT_IN_REVERSE = 0x16, - OP_DISJOINT_OUT = 0x17, - OP_DISJOINT_OUT_REVERSE = 0x18, - OP_DISJOINT_ATOP = 0x19, - OP_DISJOINT_ATOP_REVERSE = 0x1a, - OP_DISJOINT_XOR = 0x1b, - OP_CONJOINT_CLEAR = 0x20, - OP_CONJOINT_SRC = 0x21, - OP_CONJOINT_DST = 0x22, - OP_CONJOINT_OVER = 0x23, - OP_CONJOINT_OVER_REVERSE = 0x24, - OP_CONJOINT_IN = 0x25, - OP_CONJOINT_IN_REVERSE = 0x26, - OP_CONJOINT_OUT = 0x27, - OP_CONJOINT_OUT_REVERSE = 0x28, - OP_CONJOINT_ATOP = 0x29, - OP_CONJOINT_ATOP_REVERSE = 0x2a, - OP_CONJOINT_XOR = 0x2b, - OP_MULTIPLY = 0x30, - OP_SCREEN = 0x31, - OP_OVERLAY = 0x32, - OP_DARKEN = 0x33, - OP_LIGHTEN = 0x34, - OP_COLOR_DODGE = 0x35, - OP_COLOR_BURN = 0x36, - OP_HARD_LIGHT = 0x37, - OP_SOFT_LIGHT = 0x38, - OP_DIFFERENCE = 0x39, - OP_EXCLUSION = 0x3a, - OP_HSL_HUE = 0x3b, - OP_HSL_SATURATION = 0x3c, - OP_HSL_COLOR = 0x3d, - OP_HSL_LUMINOSITY = 0x3e, -} diff --git a/src/rect.rs b/src/rect.rs index a81e5683..20a15d82 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -1,3 +1,10 @@ +mod region; + +#[cfg(test)] +mod tests; + +pub use region::RegionBuilder; +use smallvec::SmallVec; use std::fmt::{Debug, Formatter}; #[derive(Copy, Clone, Eq, PartialEq, Default)] @@ -8,6 +15,14 @@ pub struct Rect { y2: i32, } +type Container = SmallVec<[Rect; 1]>; + +#[derive(Default)] +pub struct Region { + rects: Container, + extents: Rect, +} + impl Debug for Rect { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("Rect") @@ -60,6 +75,10 @@ impl Rect { Some(Self { x1, y1, x2, y2 }) } + fn new_unchecked(x1: i32, y1: i32, x2: i32, y2: i32) -> Self { + Self { x1, y1, x2, y2 } + } + pub fn new_sized(x1: i32, y1: i32, width: i32, height: i32) -> Option { if width < 0 || height < 0 { return None; diff --git a/src/rect/region.rs b/src/rect/region.rs new file mode 100644 index 00000000..b83a3700 --- /dev/null +++ b/src/rect/region.rs @@ -0,0 +1,571 @@ +use crate::rect::{Container, Rect, Region}; +use crate::utils::windows::WindowsExt; +use smallvec::SmallVec; +use std::cmp::Ordering; +use std::collections::{BinaryHeap}; +use std::mem; +use std::ops::Deref; +use std::rc::Rc; + +impl Region { + pub fn new(rect: Rect) -> Self { + let mut rects = SmallVec::new(); + rects.push(rect); + Self { + rects, + extents: rect, + } + } + + pub fn from_rects(rects: &[Rect]) -> Self { + if rects.is_empty() { + return Self::default(); + } + if rects.len() == 1 { + return Self::new(rects[0]); + } + let rects = rects_to_bands(rects); + Self { + extents: extents(&rects), + rects, + } + } + + pub fn union(&self, other: &Self) -> Self { + let rects = op::(&self.rects, &other.rects); + Self { + rects, + extents: self.extents.union(other.extents), + } + } + + pub fn subtract(&self, other: &Self) -> Self { + let rects = op::(&self.rects, &other.rects); + Self { + extents: extents(&rects), + rects, + } + } + + pub fn extents(&self) -> Rect { + self.extents + } +} + +impl Deref for Region { + type Target = [Rect]; + + fn deref(&self) -> &Self::Target { + &self.rects + } +} + +struct Bands<'a> { + rects: &'a [Rect], +} + +#[derive(Copy, Clone)] +struct Band<'a> { + rects: &'a [Rect], + y1: i32, + y2: i32, +} + +impl<'a> Band<'a> { + fn can_merge_with(&self, next: &Band) -> bool { + next.rects.len() == self.rects.len() + && next.y1 == self.y2 + && next + .rects + .iter() + .zip(self.rects.iter()) + .all(|(a, b)| (a.x1, a.x2) == (b.x1, b.x2)) + } +} + +impl<'a> Iterator for Bands<'a> { + type Item = Band<'a>; + + fn next(&mut self) -> Option { + if self.rects.is_empty() { + return None; + } + let y1 = self.rects[0].y1(); + let y2 = self.rects[0].y2(); + for (pos, rect) in self.rects[1..].iter().enumerate() { + if rect.y1() != y1 { + let (res, rects) = self.rects.split_at(pos + 1); + self.rects = rects; + return Some(Band { rects: res, y1, y2 }); + } + } + Some(Band { + rects: mem::replace(&mut self.rects, &[]), + y1, + y2, + }) + } +} + +fn extents(a: &[Rect]) -> Rect { + let mut a = a.iter(); + let mut res = match a.next() { + Some(a) => *a, + _ => return Rect::default(), + }; + for a in a { + res.x1 = res.x1.min(a.x1); + res.y1 = res.y1.min(a.y1); + res.x2 = res.x2.max(a.x2); + res.y2 = res.y2.max(a.y2); + } + res +} + +fn op(a: &[Rect], b: &[Rect]) -> Container { + let mut res = Container::new(); + + let mut prev_band_y2 = 0; + let mut prev_band_start = 0; + let mut cur_band_start; + + let mut a_bands = Bands { rects: a }; + let mut b_bands = Bands { rects: b }; + + let mut a_opt = a_bands.next(); + let mut b_opt = b_bands.next(); + + macro_rules! fixup_new_band { + ($y1:expr, $y2:expr) => {{ + if prev_band_y2 != $y1 || !coalesce(&mut res, prev_band_start, cur_band_start, $y2) { + prev_band_start = cur_band_start; + } + prev_band_y2 = $y2; + }}; + } + + macro_rules! append_nonoverlapping { + ($append_opt:expr, $a:expr, $a_opt:expr, $a_bands:expr, $b:expr) => {{ + if $append_opt { + let y2 = $a.y2.min($b.y1); + cur_band_start = res.len(); + res.reserve($a.rects.len()); + for rect in $a.rects { + res.push(Rect { + x1: rect.x1, + y1: $a.y1, + x2: rect.x2, + y2, + }); + } + fixup_new_band!($a.y1, y2); + } + if $a.y2 <= $b.y1 { + $a_opt = $a_bands.next(); + } else { + $a.y1 = $b.y1; + } + }}; + } + + while let (Some(a), Some(b)) = (&mut a_opt, &mut b_opt) { + if a.y1 < b.y1 { + append_nonoverlapping!(O::APPEND_NON_A, a, a_opt, a_bands, b); + } else if b.y1 < a.y1 { + append_nonoverlapping!(O::APPEND_NON_B, b, b_opt, b_bands, a); + } else { + let y2 = a.y2.min(b.y2); + cur_band_start = res.len(); + O::handle_band(&mut res, a.rects, b.rects, a.y1, y2); + if res.len() > cur_band_start { + fixup_new_band!(a.y1, y2); + } + if a.y2 == y2 { + a_opt = a_bands.next(); + } else { + a.y1 = y2; + } + if b.y2 == y2 { + b_opt = b_bands.next(); + } else { + b.y1 = y2; + } + } + } + + macro_rules! push_trailing { + ($a_opt:expr, $a_bands:expr) => {{ + while let Some(a) = $a_opt { + cur_band_start = res.len(); + res.reserve(a.rects.len()); + for rect in a.rects { + res.push(Rect { + x1: rect.x1, + y1: a.y1, + x2: rect.x2, + y2: a.y2, + }); + } + fixup_new_band!(a.y1, a.y2); + $a_opt = $a_bands.next(); + } + }}; + } + + if O::APPEND_NON_A { + push_trailing!(a_opt, a_bands); + } + + if O::APPEND_NON_B { + push_trailing!(b_opt, b_bands); + } + + res.shrink_to_fit(); + res +} + +fn coalesce(new: &mut Container, a: usize, b: usize, y2: i32) -> bool { + if new.len() - b != b - a { + return false; + } + let slice_a = &new[a..b]; + let slice_b = &new[b..]; + for (a, b) in slice_a.iter().zip(slice_b.iter()) { + if (a.x1(), a.x2()) != (b.x1(), b.x2()) { + return false; + } + } + for rect in &mut new[a..b] { + rect.y2 = y2; + } + new.truncate(b); + true +} + +trait Op { + const APPEND_NON_A: bool; + const APPEND_NON_B: bool; + + fn handle_band(new: &mut Container, a: &[Rect], b: &[Rect], y1: i32, y2: i32); +} + +struct Union; + +impl Op for Union { + const APPEND_NON_A: bool = true; + const APPEND_NON_B: bool = true; + + fn handle_band(new: &mut Container, mut a: &[Rect], mut b: &[Rect], y1: i32, y2: i32) { + let mut x1; + let mut x2; + + macro_rules! push { + () => { + new.push(Rect { x1, y1, x2, y2 }); + }; + } + + macro_rules! merge { + ($r:expr) => { + if $r.x1 <= x2 { + if $r.x2 > x2 { + x2 = $r.x2; + } + } else { + push!(); + x1 = $r.x1; + x2 = $r.x2; + } + }; + } + + if a[0].x1 < b[0].x1 { + x1 = a[0].x1; + x2 = a[0].x2; + a = &a[1..]; + } else { + x1 = b[0].x1; + x2 = b[0].x2; + b = &b[1..]; + } + + let mut a_iter = a.iter(); + let mut b_iter = b.iter(); + + let mut a_opt = a_iter.next(); + let mut b_opt = b_iter.next(); + + while let (Some(a), Some(b)) = (a_opt, b_opt) { + if a.x1 < b.x1 { + merge!(a); + a_opt = a_iter.next(); + } else { + merge!(b); + b_opt = b_iter.next(); + } + } + + while let Some(a) = a_opt { + merge!(a); + a_opt = a_iter.next(); + } + + while let Some(b) = b_opt { + merge!(b); + b_opt = b_iter.next(); + } + + push!(); + } +} + +struct Subtract; + +impl Op for Subtract { + const APPEND_NON_A: bool = true; + const APPEND_NON_B: bool = false; + + fn handle_band(new: &mut Container, a: &[Rect], b: &[Rect], y1: i32, y2: i32) { + let mut x1; + let mut x2; + + macro_rules! push { + ($x2:expr) => { + new.push(Rect { + x1, + y1, + x2: $x2, + y2, + }); + }; + } + + let mut a_iter = a.iter(); + let mut b_iter = b.iter(); + + macro_rules! pull { + () => { + match a_iter.next() { + Some(n) => { + x1 = n.x1; + x2 = n.x2; + } + _ => return, + } + }; + } + + pull!(); + + let mut b_opt = b_iter.next(); + + while let Some(b) = b_opt { + if b.x2 <= x1 { + b_opt = b_iter.next(); + } else if b.x1 >= x2 { + push!(x2); + pull!(); + } else { + if b.x1 > x1 { + push!(b.x1); + } + if b.x2 < x2 { + x1 = b.x2; + } else { + pull!(); + } + } + } + + loop { + push!(x2); + pull!(); + } + } +} + +fn rects_to_bands(rects_tmp: &[Rect]) -> Container { + #[derive(Copy, Clone)] + struct W(Rect); + impl Eq for W {} + impl PartialEq for W { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + impl PartialOrd for W { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + impl Ord for W { + fn cmp(&self, other: &Self) -> Ordering { + self.0 + .y1 + .cmp(&other.0.y1) + .then_with(|| self.0.x1.cmp(&other.0.x1)) + .reverse() + } + } + impl Deref for W { + type Target = Rect; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let ys = { + let mut tmp: Vec<_> = rects_tmp.iter().flat_map(|r| [r.y1, r.y2]).collect(); + tmp.sort_unstable(); + let mut last = None; + let mut res = vec![]; + for y in tmp { + if Some(y) != last { + last = Some(y); + res.push(y); + } + } + res + }; + + let mut rects = BinaryHeap::with_capacity(rects_tmp.len()); + for rect in rects_tmp.iter().copied() { + if !rect.is_empty() { + rects.push(W(rect)); + } + } + + let mut res = Container::new(); + + for &[y1, y2] in ys.array_windows_ext::<2>() { + loop { + macro_rules! check_rect { + ($rect:expr) => {{ + if $rect.y1 != y1 { + break; + } + rects.pop(); + if y2 < $rect.y2 { + $rect.0.y1 = y2; + rects.push($rect); + } + }}; + } + if let Some(mut rect) = rects.peek().copied() { + check_rect!(rect); + let mut x1 = rect.x1; + let mut x2 = rect.x2; + while let Some(mut rect) = rects.peek().copied() { + check_rect!(rect); + if rect.x1 > x2 { + res.push(Rect { x1, x2, y1, y2 }); + x1 = rect.x1; + x2 = rect.x2; + } else { + x2 = x2.max(rect.x2); + } + } + res.push(Rect { x1, x2, y1, y2 }); + } + break; + } + } + + let mut needs_merge = false; + let mut num_elements = res.len(); + let mut bands = Bands { rects: &res }.peekable(); + while let Some(band) = bands.next() { + let next = match bands.peek() { + Some(next) => next, + _ => break, + }; + if band.can_merge_with(next) { + needs_merge = true; + num_elements -= band.rects.len(); + } + } + + if !needs_merge { + res.shrink_to_fit(); + return res; + } + + let mut merged = Container::with_capacity(num_elements); + let mut bands = Bands { rects: &res }.peekable(); + while let Some(mut band) = bands.next() { + while let Some(next) = bands.peek() { + if band.can_merge_with(next) { + band.y2 = next.y2; + bands.next(); + } else { + break; + } + } + for mut rect in band.rects.iter().copied() { + rect.y2 = band.y2; + merged.push(rect); + } + } + + merged +} + +#[derive(Copy, Clone, Eq, PartialEq)] +enum BuilderOp { + Add, + Sub, +} + +impl Default for BuilderOp { + fn default() -> Self { + Self::Add + } +} + +#[derive(Default)] +pub struct RegionBuilder { + base: Rc, + op: BuilderOp, + pending: Vec, +} + +impl RegionBuilder { + pub fn add(&mut self, rect: Rect) { + self.set_op(BuilderOp::Add); + self.pending.push(rect); + } + + pub fn sub(&mut self, rect: Rect) { + self.set_op(BuilderOp::Sub); + self.pending.push(rect); + } + + pub fn get(&mut self) -> Rc { + self.flush(); + self.base.clone() + } + + pub fn clear(&mut self) { + self.pending.clear(); + self.base = Rc::new(Region::default()); + } + + fn set_op(&mut self, op: BuilderOp) { + if self.op != op { + self.flush(); + self.op = op; + } + } + + fn flush(&mut self) { + if self.pending.is_empty() { + return; + } + let region = Region::from_rects(&self.pending); + let base = match self.op { + BuilderOp::Add => self.base.union(®ion), + BuilderOp::Sub => self.base.subtract(®ion), + }; + self.base = Rc::new(base); + } +} diff --git a/src/rect/tests.rs b/src/rect/tests.rs new file mode 100644 index 00000000..8965e2e9 --- /dev/null +++ b/src/rect/tests.rs @@ -0,0 +1,60 @@ +use crate::rect::{Rect, Region}; + +#[test] +fn union1() { + let r1 = Region::new(Rect::new(0, 0, 10, 10).unwrap()); + let r2_ = Region::new(Rect::new(5, 5, 15, 15).unwrap()); + let r2 = Region::new(Rect::new(10, 10, 20, 20).unwrap()); + let r3 = r1.union(&r2).union(&r2_); + assert_eq!(r3.extents, Rect::new(0, 0, 20, 20).unwrap()); + assert_eq!( + &r3.rects[..], + &[ + Rect::new(0, 0, 10, 5).unwrap(), + Rect::new(0, 5, 15, 10).unwrap(), + Rect::new(5, 10, 20, 15).unwrap(), + Rect::new(10, 15, 20, 20).unwrap(), + ] + ); +} + +#[test] +fn union2() { + let r1 = Region::new(Rect::new(0, 0, 10, 10).unwrap()); + let r2 = Region::new(Rect::new(0, 10, 10, 20).unwrap()); + let r3 = r1.union(&r2); + assert_eq!(r3.extents, Rect::new(0, 0, 10, 20).unwrap()); + assert_eq!(&r3.rects[..], &[Rect::new(0, 0, 10, 20).unwrap(),]); +} + +#[test] +fn subtract1() { + let r1 = Region::new(Rect::new(0, 0, 20, 20).unwrap()); + let r2 = Region::new(Rect::new(5, 5, 15, 15).unwrap()); + let r3 = r1.subtract(&r2); + assert_eq!(r3.extents, Rect::new(0, 0, 20, 20).unwrap()); + assert_eq!(&r3.rects[..], &[Rect::new(0, 0, 10, 20).unwrap(),]); +} + +#[test] +fn rects_to_bands() { + let rects = [ + Rect::new_unchecked(0, 0, 10, 10), + Rect::new_unchecked(5, 0, 30, 10), + Rect::new_unchecked(30, 5, 50, 15), + ]; + let r = Region::from_rects(&rects[..]); + println!("{:#?}", r.rects); + assert_eq!(&r.rects[..], &[Rect::new(0, 0, 10, 20).unwrap(),]); +} + +#[test] +fn rects_to_bands2() { + let rects = [ + Rect::new_unchecked(0, 0, 10, 10), + Rect::new_unchecked(0, 10, 10, 20), + ]; + let r = Region::from_rects(&rects[..]); + println!("{:#?}", r.rects); + assert_eq!(&r.rects[..], &[Rect::new(0, 0, 10, 20).unwrap(),]); +} diff --git a/src/render.rs b/src/render.rs index 31fd49e7..ecbd4a19 100644 --- a/src/render.rs +++ b/src/render.rs @@ -19,9 +19,9 @@ macro_rules! egl_transparent { } use crate::drm::drm::DrmError; +use crate::drm::gbm::GbmError; pub use renderer::*; use thiserror::Error; -use crate::drm::gbm::GbmError; mod egl; mod ext; @@ -48,16 +48,10 @@ pub enum RenderError { ProgramLink, #[error("Could not bind to `EGL_OPENGL_ES_API`")] BindFailed, - #[error("EGL library does not support device enumeration")] - DeviceEnumeration, #[error("EGL library does not support the GBM platform")] GbmExt, #[error("Could not create a GBM device")] Gbm(#[source] GbmError), - #[error("EGL library does not support device querying")] - DeviceQuery, - #[error("`eglQueryDeviceStringEXT` failed")] - DeviceQueryString, #[error("`eglCreateContext` failed")] CreateContext, #[error("`eglMakeCurrent` failed")] @@ -68,8 +62,6 @@ pub enum RenderError { SmallImageBuffer, #[error("Binding a renderbuffer to a framebuffer failed")] CreateFramebuffer, - #[error("`eglQueryDevicesEXT` failed")] - QueryDevices, #[error("`eglGetPlatformDisplayEXT` failed")] GetDisplay, #[error("`eglInitialize` failed")] @@ -90,8 +82,6 @@ pub enum RenderError { QueryDmaBufFormats, #[error(transparent)] DrmError(#[from] DrmError), - #[error("Could not find the requested DRM device")] - UnknownDrmDevice, #[error("The GLES driver does not support the XRGB8888 format")] XRGB888, #[error("The DRM device does not have a render node")] diff --git a/src/render/egl.rs b/src/render/egl.rs index 12f10043..3414f6a6 100644 --- a/src/render/egl.rs +++ b/src/render/egl.rs @@ -1,19 +1,15 @@ -use crate::drm::drm::NodeType; -use crate::render::egl::device::EglDevice; use crate::render::egl::sys::{ 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_DRM_DEVICE_FILE_EXT, EGL_NONE, EGL_OPENGL_ES_API, EGL_TRUE, + EGL_DEBUG_MSG_ERROR_KHR, EGL_DEBUG_MSG_INFO_KHR, EGL_DEBUG_MSG_WARN_KHR, EGL_NONE, + EGL_OPENGL_ES_API, EGL_TRUE, }; -use crate::render::ext::{get_client_ext, get_device_ext, ClientExt, DeviceExt}; +use crate::render::ext::{get_client_ext, ClientExt}; use crate::render::proc::ExtProc; use crate::render::RenderError; -use ahash::AHashMap; use bstr::ByteSlice; use log::Level; use once_cell::sync::Lazy; -use std::ffi::{CStr, CString}; -use std::ptr; +use std::ffi::CStr; use sys::{ EGL_BAD_ACCESS, EGL_BAD_ALLOC, EGL_BAD_ATTRIBUTE, EGL_BAD_CONFIG, EGL_BAD_CONTEXT, EGL_BAD_CURRENT_SURFACE, EGL_BAD_DEVICE_EXT, EGL_BAD_DISPLAY, EGL_BAD_MATCH, @@ -23,7 +19,6 @@ use sys::{ use uapi::c; pub mod context; -pub mod device; pub mod display; pub mod image; pub mod sys; @@ -36,14 +31,8 @@ pub fn init() -> Result<(), RenderError> { if !EXTS.contains(ClientExt::EXT_PLATFORM_BASE) { return Err(RenderError::ExtPlatformBase); } - if !EXTS.device_query() { - return Err(RenderError::DeviceQuery); - } - if !EXTS.device_enumeration() { - return Err(RenderError::DeviceEnumeration); - } - if !EXTS.platform_gbm() { - return Err(RenderError::DeviceEnumeration); + if !EXTS.contains(ClientExt::KHR_PLATFORM_GBM) { + return Err(RenderError::GbmExt); } if EXTS.contains(ClientExt::KHR_DEBUG) { let attrib: &[EGLAttrib] = &[ @@ -67,49 +56,6 @@ pub fn init() -> Result<(), RenderError> { Ok(()) } -pub fn find_drm_device( - drm_dev: &AHashMap, -) -> Result, RenderError> { - for device in query_devices()? { - if device.exts.contains(DeviceExt::EXT_DEVICE_DRM) { - let device_file = device.query_string(EGL_DRM_DEVICE_FILE_EXT)?; - for name in drm_dev.values() { - if device_file == &**name { - return Ok(Some(device)); - } - } - } - } - Ok(None) -} - -pub fn query_devices() -> Result, RenderError> { - if !EXTS.device_enumeration() { - return Err(RenderError::DeviceEnumeration); - } - unsafe { - let mut devices = vec![]; - let mut num_devices = 0; - let res = PROCS.eglQueryDevicesEXT(num_devices, ptr::null_mut(), &mut num_devices); - if res != EGL_TRUE { - return Err(RenderError::QueryDevices); - } - devices.reserve_exact(num_devices as usize); - let res = PROCS.eglQueryDevicesEXT(num_devices, devices.as_mut_ptr(), &mut num_devices); - if res != EGL_TRUE { - return Err(RenderError::QueryDevices); - } - devices.set_len(num_devices as usize); - Ok(devices - .into_iter() - .map(|d| EglDevice { - exts: get_device_ext(d), - dev: d, - }) - .collect()) - } -} - unsafe extern "C" fn egl_log( error: EGLenum, command: *const c::c_char, diff --git a/src/render/egl/device.rs b/src/render/egl/device.rs deleted file mode 100644 index 51d92077..00000000 --- a/src/render/egl/device.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::format::{formats, Format}; -use crate::render::egl::display::EglDisplay; -use crate::render::egl::sys::{ - eglInitialize, EGLDeviceEXT, EGLDisplay, EGLint, EGL_PLATFORM_DEVICE_EXT, EGL_TRUE, -}; -use crate::render::egl::PROCS; -use crate::render::ext::{get_display_ext, DeviceExt, DisplayExt}; -use crate::render::RenderError; -use ahash::AHashMap; -use std::ffi::CStr; -use std::ptr; -use std::rc::Rc; - -#[derive(Debug, Copy, Clone)] -pub struct EglDevice { - pub exts: DeviceExt, - pub dev: EGLDeviceEXT, -} - -impl EglDevice { - pub fn query_string(&self, name: EGLint) -> Result<&'static CStr, RenderError> { - unsafe { - let res = PROCS.eglQueryDeviceStringEXT(self.dev, name); - if res.is_null() { - return Err(RenderError::DeviceQueryString); - } - Ok(CStr::from_ptr(res)) - } - } - - pub fn create_display(&self) -> Result, RenderError> { - unsafe { - let dpy = PROCS.eglGetPlatformDisplayEXT( - EGL_PLATFORM_DEVICE_EXT as _, - self.dev.0, - ptr::null(), - ); - if dpy.is_none() { - return Err(RenderError::GetDisplay); - } - let mut dpy = EglDisplay { - exts: DisplayExt::empty(), - formats: Rc::new(AHashMap::new()), - dev: Some(*self), - gbm: None, - dpy, - }; - let mut major = 0; - let mut minor = 0; - if eglInitialize(dpy.dpy, &mut major, &mut minor) != EGL_TRUE { - return Err(RenderError::Initialize); - } - dpy.exts = get_display_ext(dpy.dpy); - if !dpy.exts.intersects(DisplayExt::KHR_IMAGE_BASE) { - return Err(RenderError::ImageBase); - } - if !dpy - .exts - .intersects(DisplayExt::EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS) - { - return Err(RenderError::DmaBufImport); - } - if !dpy - .exts - .intersects(DisplayExt::KHR_NO_CONFIG_CONTEXT | DisplayExt::MESA_CONFIGLESS_CONTEXT) - { - return Err(RenderError::ConfiglessContext); - } - if !dpy.exts.intersects(DisplayExt::KHR_SURFACELESS_CONTEXT) { - return Err(RenderError::SurfacelessContext); - } - dpy.formats = Rc::new(query_formats(dpy.dpy)?); - - Ok(Rc::new(dpy)) - } - } -} - -unsafe fn query_formats(dpy: EGLDisplay) -> Result, RenderError> { - let mut vec = vec![]; - let mut num = 0; - let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num); - if res != EGL_TRUE { - return Err(RenderError::QueryDmaBufFormats); - } - vec.reserve_exact(num as usize); - let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, vec.as_mut_ptr(), &mut num); - if res != EGL_TRUE { - return Err(RenderError::QueryDmaBufFormats); - } - vec.set_len(num as usize); - let mut res = AHashMap::new(); - let formats = formats(); - for fmt in vec { - if let Some(format) = formats.get(&(fmt as u32)) { - res.insert(format.drm, *format); - } - } - Ok(res) -} diff --git a/src/render/egl/display.rs b/src/render/egl/display.rs index df4c6d2a..6fdeedc6 100644 --- a/src/render/egl/display.rs +++ b/src/render/egl/display.rs @@ -1,9 +1,9 @@ -use std::ptr; use crate::drm::dma::DmaBuf; +use crate::drm::drm::Drm; +use crate::drm::gbm::GbmDevice; use crate::drm::INVALID_MODIFIER; -use crate::format::{Format, formats}; +use crate::format::{formats, Format}; use crate::render::egl::context::EglContext; -use crate::render::egl::device::EglDevice; use crate::render::egl::image::EglImage; use crate::render::egl::sys::{ eglCreateContext, eglTerminate, EGLClientBuffer, EGLConfig, EGLContext, EGLDisplay, EGLint, @@ -19,20 +19,18 @@ use crate::render::egl::sys::{ EGL_LINUX_DRM_FOURCC_EXT, EGL_NONE, EGL_TRUE, EGL_WIDTH, }; use crate::render::egl::PROCS; -use crate::render::ext::{get_gl_ext, DisplayExt, GlExt, get_display_ext}; +use crate::render::ext::{get_display_ext, get_gl_ext, DisplayExt, GlExt}; +use crate::render::sys::{eglInitialize, EGL_PLATFORM_GBM_KHR}; use crate::render::RenderError; use ahash::AHashMap; +use std::ptr; use std::rc::Rc; -use crate::drm::drm::Drm; -use crate::drm::gbm::GbmDevice; -use crate::render::sys::{EGL_PLATFORM_GBM_KHR, eglInitialize}; #[derive(Debug)] pub struct EglDisplay { pub exts: DisplayExt, pub formats: Rc>, - pub dev: Option, - pub gbm: Option, + pub gbm: GbmDevice, pub dpy: EGLDisplay, } @@ -54,8 +52,7 @@ impl EglDisplay { let mut dpy = EglDisplay { exts: DisplayExt::empty(), formats: Rc::new(AHashMap::new()), - dev: None, - gbm: Some(gbm), + gbm, dpy, }; let mut major = 0; diff --git a/src/render/egl/sys.rs b/src/render/egl/sys.rs index 3a02ee09..0c90bdaa 100644 --- a/src/render/egl/sys.rs +++ b/src/render/egl/sys.rs @@ -14,7 +14,6 @@ egl_transparent!(EGLImageKHR); egl_transparent!(EGLContext); egl_transparent!(EGLClientBuffer); egl_transparent!(EGLLabelKHR); -egl_transparent!(EGLDeviceEXT); pub type EGLDEBUGPROCKHR = unsafe extern "C" fn( error: EGLenum, @@ -50,8 +49,6 @@ pub const EGL_BAD_SURFACE: EGLint = 0x300D; pub const EGL_CONTEXT_LOST: EGLint = 0x300E; pub const EGL_BAD_DEVICE_EXT: EGLint = 0x322B; pub const EGL_OPENGL_ES_API: EGLenum = 0x30A0; -pub const EGL_DRM_DEVICE_FILE_EXT: EGLint = 0x3233; -pub const EGL_PLATFORM_DEVICE_EXT: EGLint = 0x313F; pub const EGL_PLATFORM_GBM_KHR: EGLint = 0x31D7; pub const EGL_CONTEXT_CLIENT_VERSION: EGLint = 0x3098; diff --git a/src/render/ext.rs b/src/render/ext.rs index 4da91a66..04254a44 100644 --- a/src/render/ext.rs +++ b/src/render/ext.rs @@ -1,5 +1,4 @@ -use crate::render::egl::sys::{eglQueryString, EGLDeviceEXT, EGLDisplay, EGL_EXTENSIONS}; -use crate::render::egl::PROCS; +use crate::render::egl::sys::{eglQueryString, EGLDisplay, EGL_EXTENSIONS}; use crate::render::gl::sys::{glGetString, GL_EXTENSIONS}; use crate::utils::trim::AsciiTrim; use ahash::AHashSet; @@ -48,25 +47,7 @@ bitflags::bitflags! { const EXT_CLIENT_EXTENSION = 1 << 0; const EXT_PLATFORM_BASE = 1 << 1; const KHR_PLATFORM_GBM = 1 << 2; - const EXT_PLATFORM_DEVICE = 1 << 3; - const EXT_DEVICE_BASE = 1 << 4; - const EXT_DEVICE_ENUMERATION = 1 << 5; - const EXT_DEVICE_QUERY = 1 << 6; - const KHR_DEBUG = 1 << 7; - } -} - -impl ClientExt { - pub fn device_enumeration(self) -> bool { - self.contains(Self::EXT_DEVICE_BASE | Self::EXT_DEVICE_ENUMERATION) - } - - pub fn device_query(self) -> bool { - self.contains(Self::EXT_DEVICE_BASE | Self::EXT_DEVICE_QUERY) - } - - pub fn platform_gbm(self) -> bool { - self.contains(Self::KHR_PLATFORM_GBM) + const KHR_DEBUG = 1 << 3; } } @@ -74,13 +55,6 @@ pub fn get_client_ext() -> ClientExt { let map = [ ("EGL_EXT_platform_base", ClientExt::EXT_PLATFORM_BASE), ("EGL_KHR_platform_gbm", ClientExt::KHR_PLATFORM_GBM), - ("EGL_EXT_platform_device", ClientExt::EXT_PLATFORM_DEVICE), - ("EGL_EXT_device_base", ClientExt::EXT_DEVICE_BASE), - ( - "EGL_EXT_device_enumeration", - ClientExt::EXT_DEVICE_ENUMERATION, - ), - ("EGL_EXT_device_query", ClientExt::EXT_DEVICE_QUERY), ("EGL_KHR_debug", ClientExt::KHR_DEBUG), ]; match unsafe { get_dpy_extensions(EGLDisplay::none()) } { @@ -132,35 +106,6 @@ pub(super) unsafe fn get_display_ext(dpy: EGLDisplay) -> DisplayExt { } } -bitflags::bitflags! { - pub struct DeviceExt: u32 { - const MESA_DEVICE_SOFTWARE = 1 << 0; - const EXT_DEVICE_PERSISTENT_ID = 1 << 1; - const EXT_DEVICE_DRM = 1 << 2; - const EXT_DEVICE_DRM_RENDER_NODE = 1 << 3; - } -} - -pub(super) unsafe fn get_device_ext(dev: EGLDeviceEXT) -> DeviceExt { - let map = [ - ("EGL_MESA_device_software", DeviceExt::MESA_DEVICE_SOFTWARE), - ( - "EGL_EXT_device_persistent_id", - DeviceExt::EXT_DEVICE_PERSISTENT_ID, - ), - ("EGL_EXT_device_drm", DeviceExt::EXT_DEVICE_DRM), - ( - "EGL_EXT_device_drm_render_node", - DeviceExt::EXT_DEVICE_DRM_RENDER_NODE, - ), - ]; - let ext = PROCS.eglQueryDeviceStringEXT(dev, EGL_EXTENSIONS); - match get_extensions(ext) { - Some(exts) => get_typed_ext(&exts, DeviceExt::empty(), &map), - _ => DeviceExt::empty(), - } -} - bitflags::bitflags! { pub struct GlExt: u32 { const GL_OES_EGL_IMAGE = 1 << 0; diff --git a/src/render/renderer/context.rs b/src/render/renderer/context.rs index 3dc01ad0..ff26ae54 100644 --- a/src/render/renderer/context.rs +++ b/src/render/renderer/context.rs @@ -2,7 +2,7 @@ use crate::drm::dma::DmaBuf; use crate::drm::drm::{Drm, NodeType}; use crate::format::{Format, XRGB8888}; use crate::render::egl::context::EglContext; -use crate::render::egl::find_drm_device; +use crate::render::egl::display::EglDisplay; use crate::render::gl::program::GlProgram; use crate::render::gl::render_buffer::GlRenderBuffer; use crate::render::gl::sys::GLint; @@ -16,7 +16,6 @@ use std::ffi::CString; use std::fmt::{Debug, Formatter}; use std::rc::Rc; use uapi::ustr; -use crate::render::egl::display::EglDisplay; pub(super) struct TexProg { pub(super) prog: GlProgram, diff --git a/src/utils.rs b/src/utils.rs index 5c3e6be2..45a42bc8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,3 +26,4 @@ pub mod trim; pub mod vasprintf; pub mod vec_ext; pub mod vecstorage; +pub mod windows; diff --git a/src/utils/windows.rs b/src/utils/windows.rs new file mode 100644 index 00000000..d3472051 --- /dev/null +++ b/src/utils/windows.rs @@ -0,0 +1,40 @@ +use crate::utils::ptr_ext::PtrExt; + +pub trait WindowsExt { + type Windows<'a, const N: usize>: Iterator + where + Self: 'a, + T: 'a; + + fn array_windows_ext<'a, const N: usize>(&'a self) -> Self::Windows<'a, N>; +} + +impl WindowsExt for [T] { + type Windows<'a, const N: usize> + where + T: 'a, + = WindowsIter<'a, T, N>; + + fn array_windows_ext<'a, const N: usize>(&'a self) -> Self::Windows<'a, N> { + WindowsIter { slice: self } + } +} + +pub struct WindowsIter<'a, T, const N: usize> { + slice: &'a [T], +} + +impl<'a, T, const N: usize> Iterator for WindowsIter<'a, T, N> { + type Item = &'a [T; N]; + + fn next(&mut self) -> Option { + if self.slice.len() < N { + return None; + } + let res = unsafe { self.slice.as_ptr().cast::<[T; N]>().deref() }; + if N > 0 { + self.slice = &self.slice[1..]; + } + Some(res) + } +}