1
0
Fork 0
forked from wry/wry

autocommit 2022-04-04 23:09:39 CEST

This commit is contained in:
Julian Orth 2022-04-04 23:09:39 +02:00
parent e897d271af
commit 5f79aab15f
21 changed files with 870 additions and 731 deletions

View file

@ -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(())

143
build/egl.rs Normal file
View file

@ -0,0 +1,143 @@
use crate::open;
use std::fmt::Write as FmtWrite;
use std::io::Write;
fn write_egl_procs<W: Write>(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(())
}

View file

@ -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<W: Write>(f: &mut W, vals: &[i32], ty: &str) -> anyhow::Result<()> {
Ok(())
}
fn write_egl_procs<W: Write>(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(())
}

View file

@ -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<pixman::Format>,
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,

View file

@ -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<Client>,
rect: RefCell<Region>,
region: RefCell<RegionBuilder>,
pub tracker: Tracker<Self>,
}
@ -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<Region> {
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(())
}
}

View file

@ -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<Client>,
role: Cell<SurfaceRole>,
pending: PendingState,
input_region: Cell<Option<Region>>,
opaque_region: Cell<Option<Region>>,
input_region: Cell<Option<Rc<Region>>>,
opaque_region: Cell<Option<Rc<Region>>>,
pub extents: Cell<Rect>,
pub buffer_abs_pos: Cell<Rect>,
pub need_extents_update: Cell<bool>,
@ -167,8 +166,8 @@ impl SurfaceExt for NoneSurfaceExt {
#[derive(Default)]
struct PendingState {
buffer: Cell<Option<Option<(i32, i32, Rc<WlBuffer>)>>>,
opaque_region: Cell<Option<Option<Region>>>,
input_region: Cell<Option<Option<Region>>>,
opaque_region: Cell<Option<Option<Rc<Region>>>>,
input_region: Cell<Option<Option<Rc<Region>>>>,
frame_request: RefCell<Vec<Rc<WlCallback>>>,
}

View file

@ -59,7 +59,6 @@ mod logger;
mod logind;
mod object;
mod pango;
mod pixman;
mod rect;
mod render;
mod sighand;

View file

@ -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);
}
}
}

View file

@ -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,
}

View file

@ -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<Self> {
if width < 0 || height < 0 {
return None;

571
src/rect/region.rs Normal file
View file

@ -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::<Union>(&self.rects, &other.rects);
Self {
rects,
extents: self.extents.union(other.extents),
}
}
pub fn subtract(&self, other: &Self) -> Self {
let rects = op::<Subtract>(&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<Self::Item> {
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<O: 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<Self> for W {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl PartialOrd<Self> for W {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
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<Region>,
op: BuilderOp,
pending: Vec<Rect>,
}
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<Region> {
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(&region),
BuilderOp::Sub => self.base.subtract(&region),
};
self.base = Rc::new(base);
}
}

60
src/rect/tests.rs Normal file
View file

@ -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(),]);
}

View file

@ -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")]

View file

@ -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<NodeType, CString>,
) -> Result<Option<EglDevice>, 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<Vec<EglDevice>, 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,

View file

@ -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<Rc<EglDisplay>, 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<AHashMap<u32, &'static Format>, 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)
}

View file

@ -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<AHashMap<u32, &'static Format>>,
pub dev: Option<EglDevice>,
pub gbm: Option<GbmDevice>,
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;

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -26,3 +26,4 @@ pub mod trim;
pub mod vasprintf;
pub mod vec_ext;
pub mod vecstorage;
pub mod windows;

40
src/utils/windows.rs Normal file
View file

@ -0,0 +1,40 @@
use crate::utils::ptr_ext::PtrExt;
pub trait WindowsExt<T> {
type Windows<'a, const N: usize>: Iterator<Item = &'a [T; N]>
where
Self: 'a,
T: 'a;
fn array_windows_ext<'a, const N: usize>(&'a self) -> Self::Windows<'a, N>;
}
impl<T> WindowsExt<T> 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<Self::Item> {
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)
}
}