Compare commits
8 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc62d2240f | |||
| bfc2a525de | |||
| 5db14936e7 | |||
| f777b4c521 | |||
| b6502e1d8a | |||
| d756c8a6a2 | |||
| 5c2f631fdb | |||
| ce14169d6b |
767 changed files with 30529 additions and 21079 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "toml-config/toml-test"]
|
||||
path = toml-config/toml-test
|
||||
[submodule "crates/toml-config/toml-test"]
|
||||
path = crates/toml-config/toml-test
|
||||
url = https://github.com/mahkoh/toml-tests.git
|
||||
|
|
|
|||
499
Cargo.lock
generated
499
Cargo.lock
generated
|
|
@ -625,11 +625,21 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
|||
|
||||
[[package]]
|
||||
name = "jay-algorithms"
|
||||
version = "0.4.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-allocator"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-formats",
|
||||
"jay-video-types",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-ash"
|
||||
version = "0.3.0+1.4.344"
|
||||
|
|
@ -639,6 +649,52 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-async-engine"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-time",
|
||||
"jay-tracy",
|
||||
"jay-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-bufio"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-bugs"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-clientmem"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-cpu-worker",
|
||||
"jay-gfx-types",
|
||||
"jay-tracy",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-cmm"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-compositor"
|
||||
version = "1.12.0"
|
||||
|
|
@ -664,9 +720,48 @@ dependencies = [
|
|||
"indexmap",
|
||||
"isnt 0.2.0",
|
||||
"jay-algorithms",
|
||||
"jay-allocator",
|
||||
"jay-ash",
|
||||
"jay-async-engine",
|
||||
"jay-bufio",
|
||||
"jay-bugs",
|
||||
"jay-clientmem",
|
||||
"jay-cmm",
|
||||
"jay-config",
|
||||
"jay-cpu-worker",
|
||||
"jay-criteria",
|
||||
"jay-damage",
|
||||
"jay-dbus-core",
|
||||
"jay-drm-feedback",
|
||||
"jay-edid",
|
||||
"jay-eventfd-cache",
|
||||
"jay-formats",
|
||||
"jay-geometry",
|
||||
"jay-gfx-types",
|
||||
"jay-input-types",
|
||||
"jay-io-uring",
|
||||
"jay-keyboard",
|
||||
"jay-layout-animation",
|
||||
"jay-libinput",
|
||||
"jay-logger",
|
||||
"jay-output-schedule",
|
||||
"jay-output-types",
|
||||
"jay-pango",
|
||||
"jay-pr-caps",
|
||||
"jay-sighand",
|
||||
"jay-theme",
|
||||
"jay-time",
|
||||
"jay-toml-config",
|
||||
"jay-tracy",
|
||||
"jay-tree-types",
|
||||
"jay-udmabuf",
|
||||
"jay-units",
|
||||
"jay-utils",
|
||||
"jay-video-types",
|
||||
"jay-wheel",
|
||||
"jay-wire-buf",
|
||||
"jay-wire-types",
|
||||
"jay-xcon",
|
||||
"kbvm",
|
||||
"libloading",
|
||||
"linearize",
|
||||
|
|
@ -682,13 +777,11 @@ dependencies = [
|
|||
"regex",
|
||||
"repc",
|
||||
"run-on-drop",
|
||||
"rustc-demangle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"tiny-skia",
|
||||
"tracy-client-sys",
|
||||
"uapi",
|
||||
"walkdir",
|
||||
"with_builtin_macros",
|
||||
|
|
@ -696,10 +789,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jay-config"
|
||||
version = "1.10.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bincode",
|
||||
"bstr",
|
||||
"error_reporter",
|
||||
"futures-util",
|
||||
|
|
@ -711,24 +803,409 @@ dependencies = [
|
|||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-config-schema"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"jay-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-cpu-worker"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-async-engine",
|
||||
"jay-geometry",
|
||||
"jay-io-uring",
|
||||
"jay-tracy",
|
||||
"jay-utils",
|
||||
"jay-wheel",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-criteria"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-damage"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-geometry",
|
||||
"jay-tree-types",
|
||||
"jay-units",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-dbus-core"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"jay-bufio",
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-drm-feedback"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"byteorder",
|
||||
"jay-video-types",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-edid"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-eventfd-cache"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-async-engine",
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-formats"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"clap",
|
||||
"jay-ash",
|
||||
"jay-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-geometry"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-algorithms",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-gfx-types"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-input-types"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-output-types",
|
||||
"jay-units",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-io-uring"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-async-engine",
|
||||
"jay-time",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"run-on-drop",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-keyboard"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"jay-input-types",
|
||||
"jay-utils",
|
||||
"kbvm",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-layout-animation"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-geometry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-libinput"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cc",
|
||||
"isnt 0.2.0",
|
||||
"jay-utils",
|
||||
"libloading",
|
||||
"log",
|
||||
"repc",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-logger"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bstr",
|
||||
"clap",
|
||||
"dirs",
|
||||
"humantime",
|
||||
"jay-config",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-output-schedule"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"jay-async-engine",
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-output-types"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"jay-cmm",
|
||||
"jay-formats",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-pango"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"jay-geometry",
|
||||
"repc",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-pr-caps"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-utils",
|
||||
"opera",
|
||||
"parking_lot",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-sighand"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-async-engine",
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-theme"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-cmm",
|
||||
"jay-config",
|
||||
"jay-gfx-types",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-time"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-toml"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"indexmap",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-toml-config"
|
||||
version = "0.12.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bstr",
|
||||
"error_reporter",
|
||||
"indexmap",
|
||||
"jay-config",
|
||||
"jay-config-schema",
|
||||
"jay-toml",
|
||||
"kbvm",
|
||||
"log",
|
||||
"phf",
|
||||
"run-on-drop",
|
||||
"serde_json",
|
||||
"simplelog",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-tracy"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"parking_lot",
|
||||
"rustc-demangle",
|
||||
"tracy-client-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-tree-types"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-config",
|
||||
"jay-utils",
|
||||
"linearize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-udmabuf"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-allocator",
|
||||
"jay-formats",
|
||||
"jay-utils",
|
||||
"jay-video-types",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-units"
|
||||
version = "1.12.0"
|
||||
|
||||
[[package]]
|
||||
name = "jay-utils"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"arrayvec",
|
||||
"bstr",
|
||||
"cfg-if",
|
||||
"isnt 0.2.0",
|
||||
"jay-config",
|
||||
"linearize",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"rand 0.10.0",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-video-types"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"jay-formats",
|
||||
"jay-utils",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-wheel"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"jay-async-engine",
|
||||
"jay-io-uring",
|
||||
"jay-time",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-wire-buf"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"jay-io-uring",
|
||||
"jay-time",
|
||||
"jay-units",
|
||||
"jay-utils",
|
||||
"jay-wire-types",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jay-wire-types"
|
||||
version = "1.12.0"
|
||||
|
||||
[[package]]
|
||||
name = "jay-xcon"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"jay-bufio",
|
||||
"jay-io-uring",
|
||||
"jay-utils",
|
||||
"log",
|
||||
"thiserror",
|
||||
"uapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1522,7 +1999,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml-spec"
|
||||
version = "0.1.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"error_reporter",
|
||||
|
|
@ -1934,7 +2411,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|||
|
||||
[[package]]
|
||||
name = "wire-to-xml"
|
||||
version = "0.1.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
@ -2051,7 +2528,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "xml-to-wire"
|
||||
version = "0.1.0"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"quick-xml",
|
||||
"thiserror",
|
||||
|
|
|
|||
113
Cargo.toml
113
Cargo.toml
|
|
@ -1,9 +1,9 @@
|
|||
[package]
|
||||
name = "jay-compositor"
|
||||
version = "1.12.0"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
build = "build/build.rs"
|
||||
license = "GPL-3.0-only"
|
||||
license.workspace = true
|
||||
description = "The Jay compositor"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
default-run = "jay"
|
||||
|
|
@ -13,7 +13,61 @@ name = "jay"
|
|||
path = "src/main.rs"
|
||||
|
||||
[workspace]
|
||||
members = ["jay-config", "toml-config", "algorithms", "toml-spec", "wire-to-xml", "xml-to-wire"]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"crates/jay-config",
|
||||
"crates/jay-config-schema",
|
||||
"crates/geometry",
|
||||
"crates/layout-animation",
|
||||
"crates/formats",
|
||||
"crates/edid",
|
||||
"crates/units",
|
||||
"crates/utils",
|
||||
"crates/criteria",
|
||||
"crates/cmm",
|
||||
"crates/time",
|
||||
"crates/tracy",
|
||||
"crates/async-engine",
|
||||
"crates/io-uring",
|
||||
"crates/bufio",
|
||||
"crates/dbus-core",
|
||||
"crates/xcon",
|
||||
"crates/wire-types",
|
||||
"crates/wire-buf",
|
||||
"crates/tree-types",
|
||||
"crates/eventfd-cache",
|
||||
"crates/wheel",
|
||||
"crates/cpu-worker",
|
||||
"crates/sighand",
|
||||
"crates/pr-caps",
|
||||
"crates/bugs",
|
||||
"crates/logger",
|
||||
"crates/video-types",
|
||||
"crates/output-types",
|
||||
"crates/input-types",
|
||||
"crates/keyboard",
|
||||
"crates/gfx-types",
|
||||
"crates/theme",
|
||||
"crates/clientmem",
|
||||
"crates/allocator",
|
||||
"crates/output-schedule",
|
||||
"crates/drm-feedback",
|
||||
"crates/udmabuf",
|
||||
"crates/damage",
|
||||
"crates/pango",
|
||||
"crates/libinput",
|
||||
"crates/toml-config",
|
||||
"crates/toml-parser",
|
||||
"crates/algorithms",
|
||||
"crates/toml-spec",
|
||||
"crates/wire-to-xml",
|
||||
"crates/xml-to-wire",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.12.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
|
@ -23,9 +77,48 @@ debug = "full"
|
|||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
jay-config = { version = "1.10.0", path = "jay-config" }
|
||||
jay-toml-config = { version = "0.12.0", path = "toml-config" }
|
||||
jay-algorithms = { version = "0.4.0", path = "algorithms" }
|
||||
jay-config = { path = "crates/jay-config" }
|
||||
jay-toml-config = { path = "crates/toml-config" }
|
||||
jay-algorithms = { path = "crates/algorithms" }
|
||||
jay-geometry = { path = "crates/geometry" }
|
||||
jay-layout-animation = { path = "crates/layout-animation" }
|
||||
jay-formats = { path = "crates/formats" }
|
||||
jay-edid = { path = "crates/edid" }
|
||||
jay-units = { path = "crates/units" }
|
||||
jay-utils = { path = "crates/utils" }
|
||||
jay-criteria = { path = "crates/criteria" }
|
||||
jay-cmm = { path = "crates/cmm" }
|
||||
jay-time = { path = "crates/time" }
|
||||
jay-tracy = { path = "crates/tracy" }
|
||||
jay-async-engine = { path = "crates/async-engine" }
|
||||
jay-io-uring = { path = "crates/io-uring" }
|
||||
jay-bufio = { path = "crates/bufio" }
|
||||
jay-dbus-core = { path = "crates/dbus-core" }
|
||||
jay-xcon = { path = "crates/xcon" }
|
||||
jay-wire-types = { path = "crates/wire-types" }
|
||||
jay-wire-buf = { path = "crates/wire-buf" }
|
||||
jay-tree-types = { path = "crates/tree-types" }
|
||||
jay-eventfd-cache = { path = "crates/eventfd-cache" }
|
||||
jay-wheel = { path = "crates/wheel" }
|
||||
jay-cpu-worker = { path = "crates/cpu-worker" }
|
||||
jay-sighand = { path = "crates/sighand" }
|
||||
jay-pr-caps = { path = "crates/pr-caps" }
|
||||
jay-bugs = { path = "crates/bugs" }
|
||||
jay-logger = { path = "crates/logger" }
|
||||
jay-video-types = { path = "crates/video-types" }
|
||||
jay-output-types = { path = "crates/output-types" }
|
||||
jay-input-types = { path = "crates/input-types" }
|
||||
jay-keyboard = { path = "crates/keyboard" }
|
||||
jay-gfx-types = { path = "crates/gfx-types" }
|
||||
jay-theme = { path = "crates/theme" }
|
||||
jay-clientmem = { path = "crates/clientmem" }
|
||||
jay-allocator = { path = "crates/allocator" }
|
||||
jay-output-schedule = { path = "crates/output-schedule" }
|
||||
jay-drm-feedback = { path = "crates/drm-feedback" }
|
||||
jay-udmabuf = { path = "crates/udmabuf" }
|
||||
jay-damage = { path = "crates/damage" }
|
||||
jay-pango = { path = "crates/pango" }
|
||||
jay-libinput = { path = "crates/libinput" }
|
||||
|
||||
uapi = "0.2.13"
|
||||
thiserror = "2.0.11"
|
||||
|
|
@ -58,8 +151,6 @@ serde = { version = "1.0.196", features = ["derive"] }
|
|||
serde_json = "1.0.128"
|
||||
linearize = { version = "0.1.3", features = ["derive"] }
|
||||
png = "0.18.0"
|
||||
rustc-demangle = { version = "0.1.24", optional = true }
|
||||
tracy-client-sys = { version = "0.24.1", features = ["ondemand", "manual-lifetime", "debuginfod", "demangle"], optional = true }
|
||||
kbvm = { version = "0.1.6", features = ["compose"] }
|
||||
tiny-skia = { version = "0.12.0", default-features = false, features = ["std"] }
|
||||
regex = "1.11.1"
|
||||
|
|
@ -90,5 +181,5 @@ opt-level = 3
|
|||
|
||||
[features]
|
||||
rc_tracking = []
|
||||
it = []
|
||||
tracy = ["dep:tracy-client-sys", "dep:rustc-demangle"]
|
||||
it = ["jay-async-engine/it", "jay-cpu-worker/it"]
|
||||
tracy = ["jay-tracy/tracy", "jay-async-engine/tracy", "jay-cpu-worker/tracy", "jay-clientmem/tracy"]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
[](http://crates.io/crates/jay-compositor)
|
||||
|
||||
Jay is a Wayland compositor for Linux with an i3-like tiling layout,
|
||||
Vulkan and OpenGL rendering, multi-GPU support, screen sharing, and more.
|
||||
Vulkan and OpenGL rendering, multi-GPU support, and more.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ The table of contents is `SUMMARY.md`. Key chapter-to-topic mapping:
|
|||
|
||||
| File | What it tells you |
|
||||
|------|-------------------|
|
||||
| `toml-spec/spec/spec.yaml` | **Canonical** TOML config spec: every key, action, match criterion, type |
|
||||
| `toml-config/src/default-config.toml` | Built-in default config (keybindings, startup actions) |
|
||||
| `toml-config/src/config/parsers/action.rs` | Action parser — see which `type` strings are accepted |
|
||||
| `toml-config/src/lib.rs` | Action dispatch — `window_or_seat!` macro shows which actions work in window rules |
|
||||
| `crates/toml-spec/spec/spec.yaml` | **Canonical** TOML config spec: every key, action, match criterion, type |
|
||||
| `crates/toml-config/src/default-config.toml` | Built-in default config (keybindings, startup actions) |
|
||||
| `crates/toml-config/src/config/parsers/action.rs` | Action parser — see which `type` strings are accepted |
|
||||
| `crates/toml-config/src/lib.rs` | Action dispatch — `window_or_seat!` macro shows which actions work in window rules |
|
||||
| `src/config/handler.rs` | Config handler; `update_capabilities` shows capability replacement semantics |
|
||||
| `src/cli/*.rs` | CLI subcommands (clap definitions) |
|
||||
| `src/control_center/cc_*.rs` | Control center pane implementations (verify field names/ordering here) |
|
||||
| `toml-config/src/config/parsers/exec.rs` | Exec parser (string, array, or table forms) |
|
||||
| `crates/toml-config/src/config/parsers/exec.rs` | Exec parser (string, array, or table forms) |
|
||||
|
||||
### Known spec.yaml bugs
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ The table of contents is `SUMMARY.md`. Key chapter-to-topic mapping:
|
|||
- **Definition lists** for two-column term/description. Tables only for 3+ data columns.
|
||||
- **TOML formatting:** multiline with trailing commas, 4-space indent.
|
||||
- **Examples:** practical, not abstract. Link to
|
||||
[spec.generated.md](https://github.com/mahkoh/jay/blob/master/toml-spec/spec/spec.generated.md)
|
||||
[spec.generated.md](https://github.com/mahkoh/jay/blob/master/crates/toml-spec/spec/spec.generated.md)
|
||||
for exhaustive listings.
|
||||
- **Control center docs:** verify field names, ordering, and conditional
|
||||
visibility against `cc_*.rs` source files. Labels must match exactly.
|
||||
|
|
@ -91,10 +91,10 @@ The table of contents is `SUMMARY.md`. Key chapter-to-topic mapping:
|
|||
### Documenting a new action
|
||||
|
||||
1. Read `git diff` for the commit introducing the action. Key files:
|
||||
- `toml-spec/spec/spec.yaml` — spec entry (description, fields, examples)
|
||||
- `toml-config/src/config/parsers/action.rs` — parser (field names, types, defaults)
|
||||
- `toml-config/src/lib.rs` — dispatch (check if `window_or_seat!` is used)
|
||||
- `jay-config/src/input.rs` and/or `jay-config/src/window.rs` — Rust API
|
||||
- `crates/toml-spec/spec/spec.yaml` — spec entry (description, fields, examples)
|
||||
- `crates/toml-config/src/config/parsers/action.rs` — parser (field names, types, defaults)
|
||||
- `crates/toml-config/src/lib.rs` — dispatch (check if `window_or_seat!` is used)
|
||||
- `crates/jay-config/src/input.rs` and/or `crates/jay-config/src/window.rs` — Rust API
|
||||
|
||||
2. Edit `book/src/configuration/shortcuts.md`:
|
||||
- **Simple actions** (no fields): add to the appropriate list in the
|
||||
|
|
@ -110,7 +110,7 @@ The table of contents is `SUMMARY.md`. Key chapter-to-topic mapping:
|
|||
|
||||
### Documenting a new config field
|
||||
|
||||
1. Read `toml-spec/spec/spec.yaml` for the field definition.
|
||||
1. Read `crates/toml-spec/spec/spec.yaml` for the field definition.
|
||||
2. Identify which book chapter covers that config section (see table above).
|
||||
3. Add the field with a definition-list entry or example, matching the
|
||||
existing style of that chapter.
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
- [Mouse Interactions](mouse.md)
|
||||
- [Input Modes](input-modes.md)
|
||||
- [Window & Client Rules](window-rules.md)
|
||||
- [Screen Sharing](screen-sharing.md)
|
||||
- [HDR & Color Management](hdr.md)
|
||||
|
||||
# Reference
|
||||
|
|
|
|||
|
|
@ -674,18 +674,6 @@ Show color management status:
|
|||
|
||||
## Other Commands
|
||||
|
||||
### `jay portal`
|
||||
|
||||
Run the Jay desktop portal (provides screen sharing and other XDG desktop
|
||||
portal interfaces):
|
||||
|
||||
```shell
|
||||
~$ jay portal
|
||||
```
|
||||
|
||||
Normally the portal is started automatically. This command is for running it
|
||||
manually or debugging.
|
||||
|
||||
### `jay seat-test`
|
||||
|
||||
Test input events from a seat. Prints all keyboard, pointer, touch, gesture,
|
||||
|
|
@ -697,24 +685,6 @@ tablet, and switch events to stdout:
|
|||
~$ jay seat-test -a # test all seats simultaneously
|
||||
```
|
||||
|
||||
### `jay run-privileged`
|
||||
|
||||
Run a program with access to a privileged Wayland socket:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged my-program --arg1
|
||||
```
|
||||
|
||||
### `jay run-tagged`
|
||||
|
||||
Run a program with a tagged Wayland connection. All Wayland connections from the
|
||||
spawned process tree will carry the specified tag, which can be matched in
|
||||
[client rules](window-rules.md):
|
||||
|
||||
```shell
|
||||
~$ jay run-tagged my-tag firefox
|
||||
```
|
||||
|
||||
### `jay generate-completion`
|
||||
|
||||
Generate shell completion scripts:
|
||||
|
|
|
|||
|
|
@ -62,16 +62,10 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Screen lockers that use the Wayland session lock protocol (like swaylock)
|
||||
> need `privileged = true` in the exec configuration. This grants the process
|
||||
> the necessary permissions to lock the session.
|
||||
|
||||
You can also combine multiple actions:
|
||||
|
||||
```toml
|
||||
|
|
@ -80,7 +74,6 @@ on-idle = [
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
},
|
||||
{ type = "exec", exec = ["notify-send", "System locked"] },
|
||||
|
|
@ -100,7 +93,6 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ the color management protocol.
|
|||
## Libei
|
||||
|
||||
[libei](https://gitlab.freedesktop.org/libinput/libei) allows applications to
|
||||
emulate input events. By default, applications can only access libei through
|
||||
the portal (which prompts the user for permission). Setting `enable-socket`
|
||||
exposes an unauthenticated socket that any application can use without a prompt.
|
||||
emulate input events. Setting `enable-socket` exposes an unauthenticated socket
|
||||
that any application can use.
|
||||
|
||||
```toml
|
||||
libei.enable-socket = false # default
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ alt-shift-r = "reload-config-toml"
|
|||
(the next pressed key identifies the mark). See [Marks](#marks) below.
|
||||
- `enable-window-management`, `disable-window-management` -- programmatically
|
||||
enable or disable [window management mode](../floating.md#window-management-mode)
|
||||
- `reload-config-so` -- reload the shared-library configuration (`config.so`)
|
||||
|
||||
See the [specification](https://github.com/mahkoh/jay/blob/master/toml-spec/spec/spec.generated.md) for the full list of simple
|
||||
actions.
|
||||
|
|
@ -309,7 +308,6 @@ alt-s = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
shell = "grim - | wl-copy",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
@ -328,12 +326,6 @@ Table fields:
|
|||
`env`
|
||||
: Per-process environment variables
|
||||
|
||||
`privileged`
|
||||
: If `true`, grants access to privileged Wayland protocols (default: `false`)
|
||||
|
||||
`tag`
|
||||
: Tag to apply to all Wayland connections spawned by this process
|
||||
|
||||
### Practical examples
|
||||
|
||||
Volume control with `pactl`:
|
||||
|
|
@ -362,7 +354,6 @@ Print = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
shell = "grim - | wl-copy",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -63,15 +63,10 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Screen lockers need `privileged = true` to access the privileged Wayland
|
||||
> protocols required for locking the session.
|
||||
|
||||
You can combine idle with a grace period. The idle timeout and grace period are
|
||||
configured separately in the `[idle]` section (see [Idle & Screen
|
||||
Locking](idle.md)):
|
||||
|
|
@ -83,7 +78,6 @@ on-idle = {
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
|
@ -97,7 +91,6 @@ on-idle = [
|
|||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ The available color keys in the `[theme]` table are:
|
|||
|
||||
"Focused-inactive" refers to a window that was most recently focused in its
|
||||
container but whose container is not the active one. The "captured" colors apply
|
||||
when a window is being recorded (e.g. via screen sharing).
|
||||
when a window is being captured.
|
||||
|
||||
### Example
|
||||
|
||||
|
|
|
|||
|
|
@ -87,5 +87,5 @@ Xwayland client itself:
|
|||
```toml
|
||||
[[clients]]
|
||||
match.is-xwayland = true
|
||||
# ... grant capabilities, etc.
|
||||
# ... configure client-specific behavior
|
||||
```
|
||||
|
|
|
|||
|
|
@ -61,10 +61,7 @@ Commands:
|
|||
unlock Unlocks the compositor
|
||||
screenshot Take a screenshot
|
||||
idle Inspect/modify the idle (screensaver) settings
|
||||
run-privileged Run a privileged program
|
||||
run-tagged Run a program with a connection tag
|
||||
seat-test Tests the events produced by a seat
|
||||
portal Run the desktop portal
|
||||
randr Inspect/modify graphics card and connector settings
|
||||
input Inspect/modify input settings
|
||||
xwayland Inspect/modify xwayland settings
|
||||
|
|
@ -101,17 +98,6 @@ runtime.
|
|||
|
||||
See [GPUs](configuration/gpu.md) for details.
|
||||
|
||||
## Screen Sharing
|
||||
|
||||
Jay supports screen sharing via xdg-desktop-portal. Three capture modes are
|
||||
available:
|
||||
|
||||
- **Window capture** -- share a single window.
|
||||
- **Output capture** -- share an entire monitor.
|
||||
- **Workspace capture** -- like output capture, but only one workspace is shown.
|
||||
|
||||
See [Screen Sharing](screen-sharing.md) for setup instructions.
|
||||
|
||||
## Screen Locking
|
||||
|
||||
Jay can automatically lock your screen and disable outputs after inactivity.
|
||||
|
|
@ -154,20 +140,6 @@ Jay supports running X11 applications seamlessly through Xwayland. See
|
|||
Jay supports clipboard managers via the `zwlr_data_control_manager_v1` and
|
||||
`ext_data_control_manager_v1` protocols.
|
||||
|
||||
## Privilege Separation
|
||||
|
||||
Jay splits protocols into unprivileged and privileged protocols. By default,
|
||||
applications only have access to unprivileged protocols. This means that tools
|
||||
like screen lockers, status bars, and clipboard managers need to be explicitly
|
||||
granted access.
|
||||
|
||||
Jay provides several ways to grant privileges, from giving a program full
|
||||
access to all privileged protocols down to granting individual capabilities to
|
||||
specific tagged processes. See
|
||||
[Granting Privileges](window-rules.md#granting-privileges) for a detailed
|
||||
guide and the [Protocol Support](#protocol-support) section below for the full
|
||||
list of protocols and their privilege requirements.
|
||||
|
||||
## Push to Talk
|
||||
|
||||
Jay's shortcut system allows you to execute an action when a key is pressed and
|
||||
|
|
@ -252,7 +224,6 @@ granted access. See
|
|||
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
||||
| wp_pointer_warp_v1 | 1 | |
|
||||
| wp_presentation | 2 | |
|
||||
| wp_security_context_manager_v1 | 1 | |
|
||||
| wp_single_pixel_buffer_manager_v1 | 1 | |
|
||||
| wp_tearing_control_manager_v1 | 1 | |
|
||||
| wp_viewporter | 1 | |
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ For Vulkan, you also need the driver for your GPU:
|
|||
|
||||
- **Linux 6.7 or later** -- required for explicit sync (needed for Nvidia GPUs).
|
||||
- **Xwayland** -- required for running X11 applications.
|
||||
- **PipeWire** -- required for screen sharing.
|
||||
- **logind** (part of systemd) -- required when running Jay from a virtual terminal or display manager.
|
||||
|
||||
## Building
|
||||
|
|
@ -129,14 +128,7 @@ retains `CAP_SYS_NICE` solely for creating elevated Vulkan queues later.
|
|||
> [!NOTE]
|
||||
> You need to re-run the `setcap` command each time you update the Jay binary.
|
||||
|
||||
### SCHED_RR and config.so
|
||||
|
||||
`SCHED_RR` and `config.so` are mutually exclusive: running untrusted code at
|
||||
real-time priority would be a security risk. Jay enforces this as follows:
|
||||
|
||||
- If `config.so` exists in the config directory, Jay skips the `SCHED_RR`
|
||||
elevation (elevated Vulkan queues are still created).
|
||||
- If Jay has already elevated to `SCHED_RR`, it refuses to load `config.so`.
|
||||
### SCHED_RR
|
||||
|
||||
You can also skip `SCHED_RR` explicitly by setting `JAY_NO_REALTIME=1`:
|
||||
|
||||
|
|
@ -144,11 +136,7 @@ You can also skip `SCHED_RR` explicitly by setting `JAY_NO_REALTIME=1`:
|
|||
~$ JAY_NO_REALTIME=1 jay run
|
||||
```
|
||||
|
||||
This still allows elevated Vulkan queues and does not affect `config.so`
|
||||
loading.
|
||||
|
||||
The mutual exclusion can be overridden at compile time by building Jay with
|
||||
`JAY_ALLOW_REALTIME_CONFIG_SO=1`.
|
||||
This still allows elevated Vulkan queues.
|
||||
|
||||
## Recommended Applications
|
||||
|
||||
|
|
@ -156,7 +144,6 @@ The following applications work well with Jay:
|
|||
|
||||
- **[Alacritty](https://alacritty.org/)** -- the default terminal emulator in the built-in configuration.
|
||||
- **[bemenu](https://github.com/Cloudef/bemenu)** -- the default application launcher in the built-in configuration.
|
||||
- **[xdg-desktop-portal-gtk4](https://github.com/mahkoh/xdg-desktop-portal-gtk4)** -- a file-picker portal with thumbnail support. Used automatically when installed.
|
||||
- **[wl-tray-bridge](https://github.com/mahkoh/wl-tray-bridge)** -- shows D-Bus StatusNotifierItem applications as tray icons.
|
||||
- **[mako](https://github.com/emersion/mako)** -- a notification daemon. Launched automatically by the default configuration.
|
||||
- **[window-to-tray](https://github.com/mahkoh/wl-proxy/tree/master/apps/window-to-tray)** -- run most Wayland applications as tray applications (e.g. `window-to-tray pavucontrol-qt`).
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@
|
|||
|
||||
Jay is a Wayland compositor for Linux with an i3-inspired tiling layout. It
|
||||
supports Vulkan and OpenGL rendering, multi-GPU setups, fractional scaling,
|
||||
variable refresh rate (VRR), tearing presentation, HDR, and screen sharing via
|
||||
xdg-desktop-portal. X11 applications are supported through Xwayland.
|
||||
variable refresh rate (VRR), tearing presentation, and HDR. X11 applications
|
||||
are supported through Xwayland.
|
||||
|
||||
Jay is configured through a declarative TOML file, with an optional advanced
|
||||
mode that uses a shared library for programmatic control. A comprehensive
|
||||
command-line interface makes scripting and automation straightforward.
|
||||
Jay is configured through a declarative TOML file. A comprehensive command-line
|
||||
interface makes scripting and automation straightforward.
|
||||
|
||||
See the [Features](features.md) chapter for a comprehensive overview of what
|
||||
Jay can do, or jump straight to [Installation](installation.md) to get started.
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ This is especially useful for:
|
|||
|
||||
## Other
|
||||
|
||||
**Toplevel selection.** Some actions (like screen sharing) ask you to select a
|
||||
window, indicated by a purple overlay. During this selection, right-click a
|
||||
**Toplevel selection.** Some actions ask you to select a window, indicated by a
|
||||
purple overlay. During this selection, right-click a
|
||||
tile's title to select the entire container instead of an individual tile.
|
||||
|
||||
**Canceling interactions.** Press `Escape` to cancel any in-progress mouse
|
||||
|
|
|
|||
|
|
@ -1,111 +0,0 @@
|
|||
# Screen Sharing
|
||||
|
||||
Jay supports screen sharing via
|
||||
[xdg-desktop-portal](https://github.com/flatpak/xdg-desktop-portal). Three
|
||||
capture types are available:
|
||||
|
||||
- **Window capture** -- share a single window.
|
||||
- **Output capture** -- share an entire monitor.
|
||||
- **Workspace capture** -- like output capture, but only a single workspace is
|
||||
shown.
|
||||
|
||||
## Requirements
|
||||
|
||||
[PipeWire](https://pipewire.org/) must be installed and running. Verify with:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user status pipewire
|
||||
```
|
||||
|
||||
## Portal Setup
|
||||
|
||||
Jay implements its own portal backend for the `ScreenCast` and `RemoteDesktop`
|
||||
interfaces. Two configuration files must be installed so that
|
||||
`xdg-desktop-portal` knows to use Jay's backend.
|
||||
|
||||
### If the Repository is Checked Out
|
||||
|
||||
```shell
|
||||
~$ sudo cp etc/jay.portal /usr/share/xdg-desktop-portal/portals/jay.portal
|
||||
~$ sudo cp etc/jay-portals.conf /usr/share/xdg-desktop-portal/jay-portals.conf
|
||||
```
|
||||
|
||||
### If Installed via cargo install
|
||||
|
||||
Create the files manually:
|
||||
|
||||
```shell
|
||||
~$ sudo tee /usr/share/xdg-desktop-portal/portals/jay.portal > /dev/null << 'EOF'
|
||||
[portal]
|
||||
DBusName=org.freedesktop.impl.portal.desktop.jay
|
||||
Interfaces=org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.RemoteDesktop;
|
||||
EOF
|
||||
```
|
||||
|
||||
```shell
|
||||
~$ sudo tee /usr/share/xdg-desktop-portal/jay-portals.conf > /dev/null << 'EOF'
|
||||
[preferred]
|
||||
default=gtk
|
||||
org.freedesktop.impl.portal.ScreenCast=jay
|
||||
org.freedesktop.impl.portal.RemoteDesktop=jay
|
||||
org.freedesktop.impl.portal.Inhibit=none
|
||||
org.freedesktop.impl.portal.FileChooser=gtk4
|
||||
EOF
|
||||
```
|
||||
|
||||
### Restart the Portal
|
||||
|
||||
After installing the files, restart the portal service:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user restart xdg-desktop-portal
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### workspace-capture
|
||||
|
||||
The top-level `workspace-capture` setting controls whether newly created
|
||||
workspaces can be captured via workspace capture. The default is `true`:
|
||||
|
||||
```toml
|
||||
workspace-capture = false
|
||||
```
|
||||
|
||||
Set this to `false` if you want to prevent workspace-level capture by default.
|
||||
|
||||
### Capture Indicator Colors
|
||||
|
||||
When a window is being recorded, its title bar color changes to make the
|
||||
capture visually obvious. You can customize these colors in the `[theme]`
|
||||
table:
|
||||
|
||||
```toml
|
||||
[theme]
|
||||
captured-focused-title-bg-color = "#900000"
|
||||
captured-unfocused-title-bg-color = "#5f0000"
|
||||
```
|
||||
|
||||
- `captured-focused-title-bg-color` -- background color of focused title bars
|
||||
that are being recorded.
|
||||
- `captured-unfocused-title-bg-color` -- background color of unfocused title
|
||||
bars that are being recorded.
|
||||
|
||||
## The jay portal Command
|
||||
|
||||
Jay's portal backend is normally started automatically when a screen-sharing
|
||||
request comes in via D-Bus activation. If you need to start it manually for
|
||||
debugging purposes:
|
||||
|
||||
```shell
|
||||
~$ jay portal
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If screen sharing does not work:
|
||||
|
||||
1. Verify PipeWire is running: `systemctl --user status pipewire`
|
||||
2. Verify the portal files are installed in `/usr/share/xdg-desktop-portal/`.
|
||||
3. Restart the portal: `systemctl --user restart xdg-desktop-portal`
|
||||
4. Check the Jay log for errors: `jay log`
|
||||
|
|
@ -77,6 +77,20 @@ You can also right-click any title in a container to toggle mono mode.
|
|||
In mono mode, scroll over the title bar to cycle between windows in the
|
||||
container.
|
||||
|
||||
## Autotiling
|
||||
|
||||
Autotiling makes newly tiled windows alternate split direction from the focused
|
||||
tiled window. The first split uses the containing group direction, then later
|
||||
windows wrap the focused tile in the opposite direction, producing a horizontal,
|
||||
vertical, horizontal pattern as the layout grows.
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-a = "toggle-autotile"
|
||||
```
|
||||
|
||||
Manual grouping and split commands still use the direction you request.
|
||||
|
||||
## Fullscreen
|
||||
|
||||
Press `alt-u` (`toggle-fullscreen`) to make the focused window fill the entire
|
||||
|
|
|
|||
|
|
@ -54,57 +54,6 @@ bindings.
|
|||
> when any config file exists. Always use `jay config init` to start with a
|
||||
> working configuration.
|
||||
|
||||
## Application doesn't have access to a protocol
|
||||
|
||||
Jay splits Wayland protocols into unprivileged and privileged. By default,
|
||||
applications only have access to unprivileged protocols. If a program like a
|
||||
screen locker, status bar, clipboard manager, or screen-capture tool is not
|
||||
working, it likely needs access to one or more privileged protocols.
|
||||
|
||||
Common symptoms include:
|
||||
|
||||
- **swaylock** does nothing or fails to lock the screen (needs `session-lock`).
|
||||
- **waybar** or **i3bar** shows no workspace information (needs
|
||||
`foreign-toplevel-list`).
|
||||
- **wl-copy** / **cliphist** cannot access the clipboard (needs
|
||||
`data-control`).
|
||||
- **grim** or **slurp** cannot capture the screen (needs `screencopy`).
|
||||
|
||||
**Quick fix -- grant all privileges:**
|
||||
|
||||
The simplest approach is to launch the program with full access to all
|
||||
privileged protocols. In your config, set `privileged = true` in the exec
|
||||
action:
|
||||
|
||||
```toml
|
||||
on-idle = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Or from the command line:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged waybar
|
||||
```
|
||||
|
||||
**Better fix -- grant only the capabilities needed:**
|
||||
|
||||
Use a client rule to grant specific capabilities:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
See [Granting Privileges](window-rules.md#granting-privileges) for the full
|
||||
list of capabilities and more advanced approaches using connection tags.
|
||||
|
||||
## Wrong keyboard layout
|
||||
|
||||
The default keyboard layout is US QWERTY. To change it:
|
||||
|
|
@ -132,45 +81,6 @@ layout = "de"
|
|||
This takes effect immediately but does not persist across restarts unless
|
||||
configured in the config file.
|
||||
|
||||
## Screen sharing doesn't work
|
||||
|
||||
Screen sharing requires PipeWire and the Jay desktop portal.
|
||||
|
||||
**1. Check that PipeWire is running:**
|
||||
|
||||
```shell
|
||||
~$ systemctl --user status pipewire
|
||||
```
|
||||
|
||||
If it is not running, start it:
|
||||
|
||||
```shell
|
||||
~$ systemctl --user start pipewire
|
||||
```
|
||||
|
||||
**2. Check that the portal files are installed:**
|
||||
|
||||
Jay needs two files to be found by the XDG desktop portal framework:
|
||||
|
||||
- A portal definition file (e.g. `/usr/share/xdg-desktop-portal/portals/jay.portal`).
|
||||
- A portal configuration file (e.g. `/usr/share/xdg-desktop-portal/jay-portals.conf`).
|
||||
|
||||
These files are included in the Jay repository under `etc/`. If you built Jay
|
||||
from source and did not install them, copy them manually:
|
||||
|
||||
```shell
|
||||
~$ sudo cp etc/jay.portal /usr/share/xdg-desktop-portal/portals/
|
||||
~$ sudo cp etc/jay-portals.conf /usr/share/xdg-desktop-portal/
|
||||
```
|
||||
|
||||
**3. Restart the portal:**
|
||||
|
||||
```shell
|
||||
~$ systemctl --user restart xdg-desktop-portal
|
||||
```
|
||||
|
||||
See the [Screen Sharing](screen-sharing.md) chapter for more details.
|
||||
|
||||
## X11 applications don't work
|
||||
|
||||
Jay uses Xwayland to run X11 applications.
|
||||
|
|
|
|||
|
|
@ -31,12 +31,6 @@ Each client rule can have the following fields:
|
|||
`latch`
|
||||
: An action to run when a client stops matching.
|
||||
|
||||
`capabilities`
|
||||
: Wayland protocol access granted to matching clients.
|
||||
|
||||
`sandbox-bounding-capabilities`
|
||||
: Upper bounds for protocols available to child sandboxes.
|
||||
|
||||
### Client Match Criteria
|
||||
|
||||
All client match criteria are constant over the lifetime of a client. If no
|
||||
|
|
@ -70,142 +64,6 @@ implicitly AND-combined.
|
|||
`exe` / `exe-regex`
|
||||
: The client's `/proc/pid/exe` path.
|
||||
|
||||
`tag` / `tag-regex`
|
||||
: The connection tag of the client.
|
||||
|
||||
### Granting Privileges
|
||||
|
||||
Jay splits Wayland protocols into unprivileged and privileged. By default,
|
||||
applications only have access to unprivileged protocols. This means that tools
|
||||
like screen lockers, status bars, screen-capture utilities, and clipboard
|
||||
managers will not work unless you explicitly grant them the necessary
|
||||
privileges.
|
||||
|
||||
See the [Protocol Support](features.md#protocol-support) table in the Features
|
||||
chapter for the full list of protocols and whether they are privileged.
|
||||
|
||||
There are three ways to grant privileges, from simplest to most fine-grained.
|
||||
|
||||
#### 1. Grant all privileges via `privileged = true` (exec) or `jay run-privileged`
|
||||
|
||||
The simplest approach gives a program access to **all** privileged protocols.
|
||||
This is appropriate for trusted tools like screen lockers where you don't want
|
||||
to think about which specific protocols they need.
|
||||
|
||||
In the config, set `privileged = true` in the exec table:
|
||||
|
||||
```toml
|
||||
on-idle = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "swaylock",
|
||||
privileged = true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
From the command line, use `jay run-privileged`:
|
||||
|
||||
```shell
|
||||
~$ jay run-privileged waybar
|
||||
```
|
||||
|
||||
Both methods connect the program to a privileged Wayland socket that grants
|
||||
access to all privileged protocols.
|
||||
|
||||
#### 2. Grant capabilities via connection tags
|
||||
|
||||
Connection tags let you combine the CLI with client rules for precise control.
|
||||
You tag a program at launch time, then write a client rule that matches
|
||||
the tag and grants specific capabilities.
|
||||
|
||||
First, launch the program with a tag -- either from the command line:
|
||||
|
||||
```shell
|
||||
~$ jay run-tagged bar waybar
|
||||
```
|
||||
|
||||
Or from the config using the `tag` field in an exec action:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-w = {
|
||||
type = "exec",
|
||||
exec = {
|
||||
prog = "waybar",
|
||||
tag = "bar",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then write a client rule that matches the tag and grants capabilities:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.tag = "bar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
This way, only the specific instance you launched with the tag receives the
|
||||
privileges -- other programs with the same binary name do not.
|
||||
|
||||
Available capability values: `none`, `all`, `data-control`,
|
||||
`virtual-keyboard`, `foreign-toplevel-list`, `idle-notifier`, `session-lock`,
|
||||
`layer-shell`, `screencopy`, `seat-manager`, `drm-lease`, `input-method`,
|
||||
`workspace-manager`, `foreign-toplevel-manager`, `head-manager`,
|
||||
`gamma-control-manager`, `virtual-pointer`.
|
||||
|
||||
**Default capabilities:** unsandboxed clients receive `layer-shell` and
|
||||
`drm-lease`. Sandboxed clients receive only `drm-lease`. If any client rule
|
||||
matches, its capabilities **replace** the defaults entirely. If multiple rules
|
||||
match, their capabilities are unioned together, but the defaults are not
|
||||
included unless a matching rule also grants them.
|
||||
|
||||
#### 3. Grant capabilities via client match rules
|
||||
|
||||
Client rules can also match programs by properties like their executable name
|
||||
instead of a tag. This is convenient when you always want a given program to
|
||||
have certain capabilities, regardless of how it was launched:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
|
||||
# Vim 9.2 uses the data-control protocol for seamless wayland integration.
|
||||
[[clients]]
|
||||
match.comm = "vim"
|
||||
match.sandboxed = false
|
||||
capabilities = "data-control"
|
||||
|
||||
# Older versions use wl-copy and wl-paste.
|
||||
[[clients]]
|
||||
match.any = [
|
||||
{ comm = "wl-copy" },
|
||||
{ comm = "wl-paste" },
|
||||
]
|
||||
match.sandboxed = false
|
||||
capabilities = "data-control"
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Client match criteria like `comm`, `exe`, and `pid` are checked when a
|
||||
> client connects. Any process with a matching name receives the specified
|
||||
> capabilities. If you need to restrict privileges to programs you launch
|
||||
> yourself, use connection tags (method 2) instead.
|
||||
|
||||
#### Bounding capabilities (sandboxes)
|
||||
|
||||
Capabilities can never exceed the client's **bounding capabilities**. Use
|
||||
`sandbox-bounding-capabilities` on a client rule to set the upper bound for
|
||||
protocols available to sandboxes created by that client:
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "flatpak-portal"
|
||||
sandbox-bounding-capabilities = ["drm-lease", "layer-shell"]
|
||||
```
|
||||
|
||||
## Window Rules
|
||||
|
||||
Window rules operate on individual windows. They are defined with `[[windows]]`
|
||||
|
|
@ -456,18 +314,6 @@ action = {
|
|||
}
|
||||
```
|
||||
|
||||
### Grant Protocol Access to a Trusted App
|
||||
|
||||
```toml
|
||||
[[clients]]
|
||||
match.comm = "swaylock"
|
||||
capabilities = ["session-lock", "layer-shell"]
|
||||
|
||||
[[clients]]
|
||||
match.comm = "waybar"
|
||||
capabilities = ["layer-shell", "foreign-toplevel-list"]
|
||||
```
|
||||
|
||||
### Suppress Focus Stealing for Chromium Screen-Share Windows
|
||||
|
||||
```toml
|
||||
|
|
|
|||
|
|
@ -123,16 +123,15 @@ laptop.
|
|||
|
||||
## Workspace Capture
|
||||
|
||||
By default, newly created workspaces can be captured for screen sharing. You
|
||||
can disable this globally:
|
||||
By default, newly created workspaces can be captured by capture clients. You can
|
||||
disable this globally:
|
||||
|
||||
```toml
|
||||
workspace-capture = false
|
||||
```
|
||||
|
||||
When workspace capture is enabled, screen-sharing applications can share
|
||||
individual workspaces (in addition to full outputs and individual windows). See
|
||||
[Screen Sharing](screen-sharing.md) for more details.
|
||||
When workspace capture is enabled, compositor-native capture clients may capture
|
||||
individual workspaces instead of whole outputs.
|
||||
|
||||
## Matching Windows by Workspace
|
||||
|
||||
|
|
|
|||
129
build/enums.rs
129
build/enums.rs
|
|
@ -4,18 +4,27 @@ use {
|
|||
std::{env, io::Write},
|
||||
};
|
||||
|
||||
#[expect(unused_macros)]
|
||||
#[macro_use]
|
||||
#[path = "../src/macros.rs"]
|
||||
mod macros;
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! cenum {
|
||||
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct $name(pub i32);
|
||||
|
||||
#[path = "../src/libinput/consts.rs"]
|
||||
mod libinput;
|
||||
impl $name {
|
||||
pub fn raw(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "../src/pango/consts.rs"]
|
||||
mod pango;
|
||||
pub const $uc: &[i32] = &[$($val,)*];
|
||||
|
||||
#[path = "../src/fontconfig/consts.rs"]
|
||||
$(
|
||||
pub const $name2: $name = $name($val);
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "fontconfig_consts.rs"]
|
||||
mod fontconfig;
|
||||
|
||||
fn get_target() -> repc::Target {
|
||||
|
|
@ -49,108 +58,6 @@ fn write_ty<W: Write>(f: &mut W, vals: &[i32], ty: &str) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
let mut f = open("libinput_tys.rs")?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_LOG_PRIORITY,
|
||||
"libinput_log_priority",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_DEVICE_CAPABILITY,
|
||||
"libinput_device_capability",
|
||||
)?;
|
||||
write_ty(&mut f, libinput::LIBINPUT_KEY_STATE, "libinput_key_state")?;
|
||||
write_ty(&mut f, libinput::LIBINPUT_LED, "libinput_led")?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_BUTTON_STATE,
|
||||
"libinput_button_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_POINTER_AXIS,
|
||||
"libinput_pointer_axis",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_POINTER_AXIS_SOURCE,
|
||||
"libinput_pointer_axis_source",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_TABLET_PAD_RING_AXIS_SOURCE,
|
||||
"libinput_tablet_pad_ring_axis_source",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_TABLET_PAD_STRIP_AXIS_SOURCE,
|
||||
"libinput_tablet_pad_strip_axis_source",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_TABLET_TOOL_TYPE,
|
||||
"libinput_tablet_tool_type",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_TABLET_TOOL_PROXIMITY_STATE,
|
||||
"libinput_tablet_tool_proximity_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_TABLET_TOOL_TIP_STATE,
|
||||
"libinput_tablet_tool_tip_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_SWITCH_STATE,
|
||||
"libinput_switch_state",
|
||||
)?;
|
||||
write_ty(&mut f, libinput::LIBINPUT_SWITCH, "libinput_switch")?;
|
||||
write_ty(&mut f, libinput::LIBINPUT_EVENT_TYPE, "libinput_event_type")?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_STATUS,
|
||||
"libinput_config_status",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_ACCEL_PROFILE,
|
||||
"libinput_config_accel_profile",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_TAP_STATE,
|
||||
"libinput_config_tap_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_DRAG_STATE,
|
||||
"libinput_config_drag_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_DRAG_LOCK_STATE,
|
||||
"libinput_config_drag_lock_state",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_CLICK_METHOD,
|
||||
"libinput_config_click_method",
|
||||
)?;
|
||||
write_ty(
|
||||
&mut f,
|
||||
libinput::LIBINPUT_CONFIG_MIDDLE_EMULATION_STATE,
|
||||
"libinput_config_middle_emulation_state",
|
||||
)?;
|
||||
|
||||
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")?;
|
||||
write_ty(&mut f, pango::CAIRO_OPERATORS, "cairo_operator_t")?;
|
||||
write_ty(&mut f, pango::PANGO_ELLIPSIZE_MODES, "PangoEllipsizeMode_")?;
|
||||
|
||||
let mut f = open("fontconfig_tys.rs")?;
|
||||
write_ty(&mut f, fontconfig::FC_MATCH_KINDS, "FcMatchKind")?;
|
||||
write_ty(&mut f, fontconfig::FC_RESULTS, "FcResult")?;
|
||||
|
|
|
|||
|
|
@ -4,17 +4,10 @@ use {
|
|||
};
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
create_bridge()?;
|
||||
create_version()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_bridge() -> anyhow::Result<()> {
|
||||
println!("cargo:rerun-if-changed=src/bridge.c");
|
||||
cc::Build::new().file("src/bridge.c").compile("bridge");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_version() -> anyhow::Result<()> {
|
||||
let mut version_string = env!("CARGO_PKG_VERSION").to_string();
|
||||
if let Ok(output) = Command::new("git").arg("rev-parse").arg("HEAD").output()
|
||||
|
|
|
|||
|
|
@ -417,6 +417,7 @@ fn write_file<W: Write>(
|
|||
let messages = parse_messages(&contents)?;
|
||||
writeln!(f)?;
|
||||
writeln!(f, "pub mod {} {{", obj_name)?;
|
||||
writeln!(f, " #![allow(dead_code)]")?;
|
||||
writeln!(f, " use super::*;")?;
|
||||
for message in messages.requests.iter().chain(messages.events.iter()) {
|
||||
write_message(f, &camel_obj_name, &message.val)?;
|
||||
|
|
@ -442,7 +443,7 @@ pub fn main() -> Result<()> {
|
|||
writeln!(f, "use std::rc::Rc;")?;
|
||||
writeln!(f, "use uapi::OwnedFd;")?;
|
||||
writeln!(f, "use bstr::BStr;")?;
|
||||
writeln!(f, "use crate::fixed::Fixed;")?;
|
||||
writeln!(f, "use jay_units::fixed::Fixed;")?;
|
||||
writeln!(f, "use crate::client::{{EventFormatter, RequestParser}};")?;
|
||||
writeln!(f, "use crate::object::{{ObjectId, Interface}};")?;
|
||||
writeln!(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
[package]
|
||||
name = "jay-algorithms"
|
||||
version = "0.4.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
description = "Internal dependency of the Jay compositor"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
12
crates/allocator/Cargo.toml
Normal file
12
crates/allocator/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "jay-allocator"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-formats = { path = "../formats" }
|
||||
jay-video-types = { path = "../video-types" }
|
||||
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
95
crates/allocator/src/lib.rs
Normal file
95
crates/allocator/src/lib.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
use {
|
||||
jay_formats::Format,
|
||||
jay_video_types::{
|
||||
Modifier,
|
||||
dmabuf::{DmaBuf, DmaBufIds},
|
||||
},
|
||||
std::{
|
||||
error::Error,
|
||||
ops::{BitOr, BitOrAssign, Not},
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
uapi::{OwnedFd, c},
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error(transparent)]
|
||||
pub struct AllocatorError(#[from] pub Box<dyn Error + Send>);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct BufferUsage(u32);
|
||||
|
||||
impl BufferUsage {
|
||||
pub fn none() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn contains(self, other: Self) -> bool {
|
||||
self.0 & other.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for BufferUsage {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for BufferUsage {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for BufferUsage {
|
||||
type Output = Self;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
Self(!self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub const BO_USE_SCANOUT: BufferUsage = BufferUsage(1 << 0);
|
||||
pub const BO_USE_CURSOR: BufferUsage = BufferUsage(1 << 1);
|
||||
pub const BO_USE_RENDERING: BufferUsage = BufferUsage(1 << 2);
|
||||
pub const BO_USE_WRITE: BufferUsage = BufferUsage(1 << 3);
|
||||
pub const BO_USE_LINEAR: BufferUsage = BufferUsage(1 << 4);
|
||||
pub const BO_USE_PROTECTED: BufferUsage = BufferUsage(1 << 5);
|
||||
|
||||
pub trait Allocator {
|
||||
fn drm(&self) -> Option<&dyn AllocatorDrm>;
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError>;
|
||||
fn import_dmabuf(
|
||||
&self,
|
||||
dmabuf: &DmaBuf,
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError>;
|
||||
}
|
||||
|
||||
pub trait AllocatorDrm {
|
||||
fn dev(&self) -> c::dev_t;
|
||||
fn dup_render_fd(&self) -> Result<Rc<OwnedFd>, AllocatorError>;
|
||||
}
|
||||
|
||||
pub trait BufferObject {
|
||||
fn dmabuf(&self) -> &DmaBuf;
|
||||
fn map_read(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError>;
|
||||
fn map_write(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError>;
|
||||
}
|
||||
|
||||
pub trait MappedBuffer {
|
||||
unsafe fn data(&self) -> &[u8];
|
||||
fn data_ptr(&self) -> *mut u8;
|
||||
fn stride(&self) -> i32;
|
||||
}
|
||||
14
crates/async-engine/Cargo.toml
Normal file
14
crates/async-engine/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "jay-async-engine"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-time = { path = "../time" }
|
||||
jay-tracy = { path = "../tracy" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
[features]
|
||||
it = []
|
||||
tracy = ["jay-tracy/tracy"]
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, Phase},
|
||||
tracy::ZoneName,
|
||||
utils::{
|
||||
numcell::NumCell,
|
||||
ptr_ext::{MutPtrExt, PtrExt},
|
||||
},
|
||||
crate::{AsyncEngine, Phase},
|
||||
jay_tracy::ZoneName,
|
||||
jay_utils::{
|
||||
numcell::NumCell,
|
||||
ptr_ext::{MutPtrExt, PtrExt},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
|
|
@ -142,7 +140,7 @@ impl AsyncEngine {
|
|||
}),
|
||||
waker: Cell::new(None),
|
||||
queue: self.clone(),
|
||||
zone: create_zone_name!("task:{}", name),
|
||||
zone: jay_tracy::create_zone_name!("task:{}", name),
|
||||
});
|
||||
unsafe {
|
||||
f.schedule_run();
|
||||
|
|
@ -254,7 +252,7 @@ impl<T, F: Future<Output = T>> Task<T, F> {
|
|||
|
||||
let mut ctx = Context::from_waker(&waker);
|
||||
let poll = {
|
||||
dynamic_zone!(self.zone);
|
||||
jay_tracy::dynamic_zone!(self.zone);
|
||||
Pin::new_unchecked(&mut *data.future).poll(&mut ctx)
|
||||
};
|
||||
if let Poll::Ready(d) = poll {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::async_engine::AsyncEngine,
|
||||
crate::AsyncEngine,
|
||||
std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
mod ae_task;
|
||||
mod ae_yield;
|
||||
mod run_toplevel;
|
||||
|
||||
pub use {crate::async_engine::ae_yield::Yield, ae_task::SpawnedFuture};
|
||||
pub use {ae_task::SpawnedFuture, ae_yield::Yield, run_toplevel::*};
|
||||
use {
|
||||
crate::{
|
||||
async_engine::ae_task::Runnable,
|
||||
time::Time,
|
||||
utils::{array, numcell::NumCell, syncqueue::SyncQueue},
|
||||
},
|
||||
crate::ae_task::Runnable,
|
||||
jay_time::Time,
|
||||
jay_utils::{array, numcell::NumCell, syncqueue::SyncQueue},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::VecDeque,
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
utils::queue::AsyncQueue,
|
||||
},
|
||||
crate::{AsyncEngine, SpawnedFuture},
|
||||
jay_utils::queue::AsyncQueue,
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
12
crates/bufio/Cargo.toml
Normal file
12
crates/bufio/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "jay-bufio"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-io-uring = { path = "../io-uring" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
io_uring::{IoUring, IoUringError},
|
||||
utils::{
|
||||
buf::{Buf, DynamicBuf},
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
jay_io_uring::{IoUring, IoUringError},
|
||||
jay_utils::{
|
||||
buf::{Buf, DynamicBuf},
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
std::{
|
||||
collections::VecDeque,
|
||||
8
crates/bugs/Cargo.toml
Normal file
8
crates/bugs/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "jay-bugs"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ahash = "0.8.7"
|
||||
18
crates/clientmem/Cargo.toml
Normal file
18
crates/clientmem/Cargo.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "jay-clientmem"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-cpu-worker = { path = "../cpu-worker" }
|
||||
jay-gfx-types = { path = "../gfx-types" }
|
||||
jay-tracy = { path = "../tracy" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
log = "0.4.20"
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
|
||||
[features]
|
||||
tracy = ["jay-tracy/tracy"]
|
||||
331
crates/clientmem/src/lib.rs
Normal file
331
crates/clientmem/src/lib.rs
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
use {
|
||||
jay_cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker},
|
||||
jay_gfx_types::{ShmMemory, ShmMemoryBacking},
|
||||
jay_utils::{
|
||||
oserror::{OsError, OsErrorExt2},
|
||||
page_size::page_size,
|
||||
vec_ext::VecExt,
|
||||
},
|
||||
std::{
|
||||
cell::Cell,
|
||||
error::Error,
|
||||
mem::{ManuallyDrop, MaybeUninit},
|
||||
ops::Deref,
|
||||
ptr,
|
||||
rc::Rc,
|
||||
sync::atomic::{Ordering, compiler_fence},
|
||||
},
|
||||
thiserror::Error,
|
||||
uapi::{
|
||||
OwnedFd, Pod,
|
||||
c::{self, raise},
|
||||
ftruncate,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClientMemClient<'a> {
|
||||
pub comm: &'a str,
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ClientMemError {
|
||||
#[error("Could not install the sigbus handler")]
|
||||
SigactionFailed(#[source] jay_utils::oserror::OsError),
|
||||
#[error("A SIGBUS occurred while accessing mapped memory")]
|
||||
Sigbus,
|
||||
#[error("mmap failed")]
|
||||
MmapFailed(#[source] jay_utils::oserror::OsError),
|
||||
#[error("Length was not a multiple of the data element size")]
|
||||
InvalidLength,
|
||||
}
|
||||
|
||||
pub struct ClientMem {
|
||||
fd: ManuallyDrop<Rc<OwnedFd>>,
|
||||
failed: Cell<bool>,
|
||||
sigbus_impossible: bool,
|
||||
data: *const [Cell<u8>],
|
||||
cpu: Option<Rc<CpuWorker>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientMemOffset {
|
||||
mem: Rc<ClientMem>,
|
||||
offset: usize,
|
||||
data: *const [Cell<u8>],
|
||||
}
|
||||
|
||||
impl ClientMem {
|
||||
pub fn new(
|
||||
fd: &Rc<OwnedFd>,
|
||||
len: usize,
|
||||
read_only: bool,
|
||||
client: Option<ClientMemClient<'_>>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
is_udmabuf: bool,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_SHARED, is_udmabuf)
|
||||
}
|
||||
|
||||
pub fn new_private(
|
||||
fd: &Rc<OwnedFd>,
|
||||
len: usize,
|
||||
read_only: bool,
|
||||
client: Option<ClientMemClient<'_>>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
Self::new2(fd, len, read_only, client, cpu, c::MAP_PRIVATE, false)
|
||||
}
|
||||
|
||||
fn new2(
|
||||
fd: &Rc<OwnedFd>,
|
||||
len: usize,
|
||||
read_only: bool,
|
||||
client: Option<ClientMemClient<'_>>,
|
||||
cpu: Option<&Rc<CpuWorker>>,
|
||||
flags: c::c_int,
|
||||
is_udmabuf: bool,
|
||||
) -> Result<Self, ClientMemError> {
|
||||
let mut sigbus_impossible = is_udmabuf;
|
||||
let mut real_size = None;
|
||||
if !sigbus_impossible
|
||||
&& let Ok(seals) = uapi::fcntl_get_seals(fd.raw())
|
||||
&& seals & c::F_SEAL_SHRINK != 0
|
||||
&& let Ok(stat) = uapi::fstat(fd.raw())
|
||||
{
|
||||
real_size = Some(stat.st_size as usize);
|
||||
sigbus_impossible = stat.st_size as u64 >= len as u64;
|
||||
}
|
||||
if !sigbus_impossible && let Some(client) = client {
|
||||
log::debug!(
|
||||
"Client {} ({}) has created a shm buffer that might cause SIGBUS",
|
||||
client.comm,
|
||||
client.id,
|
||||
);
|
||||
}
|
||||
let len = len.next_multiple_of(page_size());
|
||||
if let Some(real_size) = real_size
|
||||
&& real_size < len
|
||||
{
|
||||
let _ = ftruncate(fd.raw(), len as _);
|
||||
}
|
||||
let data = if len == 0 {
|
||||
&mut [][..]
|
||||
} else {
|
||||
let prot = match read_only {
|
||||
true => c::PROT_READ,
|
||||
false => c::PROT_READ | c::PROT_WRITE,
|
||||
};
|
||||
unsafe {
|
||||
let data = c::mmap64(ptr::null_mut(), len, prot, flags, fd.raw(), 0);
|
||||
if data == c::MAP_FAILED {
|
||||
return Err(ClientMemError::MmapFailed(OsError::default()));
|
||||
}
|
||||
std::slice::from_raw_parts_mut(data as *mut Cell<u8>, len)
|
||||
}
|
||||
};
|
||||
Ok(Self {
|
||||
fd: ManuallyDrop::new(fd.clone()),
|
||||
failed: Cell::new(false),
|
||||
sigbus_impossible,
|
||||
data,
|
||||
cpu: cpu.cloned(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn offset(self: &Rc<Self>, offset: usize, len: usize) -> ClientMemOffset {
|
||||
let mem = unsafe { &*self.data };
|
||||
ClientMemOffset {
|
||||
mem: self.clone(),
|
||||
offset,
|
||||
data: &mem[offset..][..len],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fd(&self) -> &Rc<OwnedFd> {
|
||||
&self.fd
|
||||
}
|
||||
|
||||
pub fn is_sealed_memfd(&self) -> bool {
|
||||
self.sigbus_impossible
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientMemOffset {
|
||||
pub fn pool(&self) -> &ClientMem {
|
||||
&self.mem
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
|
||||
pub fn ptr(&self) -> *const [Cell<u8>] {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn access<T, F: FnOnce(&[Cell<u8>]) -> T>(&self, f: F) -> Result<T, ClientMemError> {
|
||||
unsafe {
|
||||
if self.mem.sigbus_impossible {
|
||||
return Ok(f(&*self.data));
|
||||
}
|
||||
let mref = MemRef {
|
||||
mem: &*self.mem,
|
||||
outer: MEM.get(),
|
||||
};
|
||||
MEM.set(&mref);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let res = f(&*self.data);
|
||||
MEM.set(mref.outer);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
match self.mem.failed.get() {
|
||||
true => Err(ClientMemError::Sigbus),
|
||||
_ => Ok(res),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<T: Pod>(&self, dst: &mut Vec<T>) -> Result<(), ClientMemError> {
|
||||
if self.data.len().checked_rem(std::mem::size_of::<T>()) != Some(0) {
|
||||
return Err(ClientMemError::InvalidLength);
|
||||
}
|
||||
self.access(|v| {
|
||||
let len_elements = v.len() / std::mem::size_of::<T>();
|
||||
dst.reserve(len_elements);
|
||||
let (_, unused) = dst.split_at_spare_mut_bytes_ext();
|
||||
unused[..v.len()].copy_from_slice(uapi::as_maybe_uninit_bytes(v));
|
||||
unsafe {
|
||||
dst.set_len(dst.len() + len_elements);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ClientMem {
|
||||
fn drop(&mut self) {
|
||||
let fd = unsafe { ManuallyDrop::take(&mut self.fd) };
|
||||
if let Some(cpu) = &self.cpu {
|
||||
let pending = cpu.submit(Box::new(CloseMemWork {
|
||||
fd: Rc::try_unwrap(fd).ok(),
|
||||
data: self.data,
|
||||
}));
|
||||
pending.detach();
|
||||
} else {
|
||||
unsafe {
|
||||
c::munmap(self.data as _, self.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MemRef {
|
||||
mem: *const ClientMem,
|
||||
outer: *const MemRef,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static MEM: Cell<*const MemRef> = const { Cell::new(ptr::null()) };
|
||||
}
|
||||
|
||||
unsafe fn kill() -> ! {
|
||||
unsafe {
|
||||
c::signal(c::SIGBUS, c::SIG_DFL);
|
||||
raise(c::SIGBUS);
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
unsafe extern "C" fn sigbus(sig: i32, info: &c::siginfo_t, _ucontext: *mut c::c_void) {
|
||||
unsafe {
|
||||
assert_eq!(sig, c::SIGBUS);
|
||||
let mut memr_ptr = MEM.get();
|
||||
while !memr_ptr.is_null() {
|
||||
let memr = &*memr_ptr;
|
||||
let mem = &*memr.mem;
|
||||
let lo = mem.data as *mut u8 as usize;
|
||||
let hi = lo + mem.len();
|
||||
let fault_addr = info.si_addr() as usize;
|
||||
if fault_addr < lo || fault_addr >= hi {
|
||||
memr_ptr = memr.outer;
|
||||
continue;
|
||||
}
|
||||
let res = c::mmap64(
|
||||
lo as _,
|
||||
hi - lo,
|
||||
c::PROT_WRITE | c::PROT_READ,
|
||||
c::MAP_ANONYMOUS | c::MAP_PRIVATE | c::MAP_FIXED,
|
||||
-1,
|
||||
0,
|
||||
);
|
||||
if res == c::MAP_FAILED {
|
||||
kill();
|
||||
}
|
||||
mem.failed.set(true);
|
||||
return;
|
||||
}
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() -> Result<(), ClientMemError> {
|
||||
unsafe {
|
||||
let mut action: c::sigaction = MaybeUninit::zeroed().assume_init();
|
||||
action.sa_sigaction =
|
||||
sigbus as unsafe extern "C" fn(i32, &c::siginfo_t, *mut c::c_void) as _;
|
||||
action.sa_flags = c::SA_NODEFER | c::SA_SIGINFO;
|
||||
let res = c::sigaction(c::SIGBUS, &action, ptr::null_mut());
|
||||
uapi::map_err!(res)
|
||||
.map(drop)
|
||||
.map_os_err(ClientMemError::SigactionFailed)
|
||||
}
|
||||
}
|
||||
|
||||
struct CloseMemWork {
|
||||
fd: Option<OwnedFd>,
|
||||
data: *const [Cell<u8>],
|
||||
}
|
||||
|
||||
unsafe impl Send for CloseMemWork {}
|
||||
|
||||
impl CpuJob for CloseMemWork {
|
||||
fn work(&mut self) -> &mut dyn CpuWork {
|
||||
self
|
||||
}
|
||||
|
||||
fn completed(self: Box<Self>) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuWork for CloseMemWork {
|
||||
fn run(&mut self) -> Option<Box<dyn AsyncCpuWork>> {
|
||||
jay_tracy::zone!("CloseMemWork");
|
||||
self.fd.take();
|
||||
unsafe {
|
||||
c::munmap(self.data as _, self.data.len());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ShmMemory for ClientMemOffset {
|
||||
fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
fn safe_access(&self) -> ShmMemoryBacking {
|
||||
match self.mem.is_sealed_memfd() {
|
||||
true => ShmMemoryBacking::Ptr(self.data),
|
||||
false => ShmMemoryBacking::Fd(self.mem.fd.deref().clone(), self.offset),
|
||||
}
|
||||
}
|
||||
|
||||
fn access(&self, f: &mut dyn FnMut(&[Cell<u8>])) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
self.access(f).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
8
crates/cmm/Cargo.toml
Normal file
8
crates/cmm/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "jay-cmm"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-utils = { path = "../utils" }
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance, white_balance},
|
||||
cmm_manager::Shared,
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
|
||||
},
|
||||
utils::ordered_float::F64,
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance, white_balance},
|
||||
cmm_manager::Shared,
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Local, Xyz, bradford_adjustment},
|
||||
},
|
||||
jay_utils::ordered_float::F64,
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::ordered_float::F32;
|
||||
use jay_utils::ordered_float::F32;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Eotf {
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
use crate::{
|
||||
cmm::{
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Xyz},
|
||||
},
|
||||
utils::ordered_float::F64,
|
||||
cmm_render_intent::RenderIntent,
|
||||
cmm_transform::{ColorMatrix, Xyz},
|
||||
};
|
||||
use jay_utils::ordered_float::F64;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Luminance {
|
||||
|
|
@ -38,7 +36,6 @@ impl Luminance {
|
|||
white: F64(203.0),
|
||||
};
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub const HLG: Self = Self {
|
||||
min: F64(0.005),
|
||||
max: F64(1000.0),
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{
|
||||
cmm_description::{
|
||||
ColorDescription, ColorDescriptionIds, LinearColorDescription,
|
||||
LinearColorDescriptionId, LinearColorDescriptionIds,
|
||||
},
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance},
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_description::{
|
||||
ColorDescription, ColorDescriptionIds, LinearColorDescription,
|
||||
LinearColorDescriptionId, LinearColorDescriptionIds,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
|
||||
cmm_eotf::Eotf,
|
||||
cmm_luminance::{Luminance, TargetLuminance},
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, numcell::NumCell, ordered_float::F64},
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use {crate::utils::ordered_float::F64, std::hash::Hash};
|
||||
use {jay_utils::ordered_float::F64, std::hash::Hash};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum NamedPrimaries {
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
use crate::{
|
||||
ifs::color_management::{
|
||||
ABSOLUTE_NO_ADAPTATION_SINCE, RENDER_INTENT_ABSOLUTE_NO_ADAPTATION,
|
||||
RENDER_INTENT_PERCEPTUAL, RENDER_INTENT_RELATIVE, RENDER_INTENT_RELATIVE_BPC,
|
||||
},
|
||||
object::Version,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
|
||||
pub enum RenderIntent {
|
||||
#[default]
|
||||
|
|
@ -16,19 +8,6 @@ pub enum RenderIntent {
|
|||
}
|
||||
|
||||
impl RenderIntent {
|
||||
pub fn from_wayland(intent: u32, version: Version) -> Option<Self> {
|
||||
let res = match intent {
|
||||
RENDER_INTENT_PERCEPTUAL => Self::Perceptual,
|
||||
RENDER_INTENT_RELATIVE => Self::Relative,
|
||||
RENDER_INTENT_RELATIVE_BPC => Self::RelativeBpc,
|
||||
RENDER_INTENT_ABSOLUTE_NO_ADAPTATION if version >= ABSOLUTE_NO_ADAPTATION_SINCE => {
|
||||
Self::AbsoluteNoAdaptation
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn black_point_compensation(self) -> bool {
|
||||
match self {
|
||||
RenderIntent::Perceptual => true,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
mod matrices {
|
||||
use crate::{cmm::cmm_primaries::Primaries, utils::ordered_float::F64};
|
||||
use {crate::cmm_primaries::Primaries, jay_utils::ordered_float::F64};
|
||||
|
||||
fn check(primaries: Primaries, expected: [[f64; 4]; 3]) {
|
||||
let (ltg, gtl) = primaries.matrices();
|
||||
|
|
@ -134,7 +134,7 @@ mod matrices {
|
|||
}
|
||||
|
||||
mod transforms {
|
||||
use crate::cmm::{
|
||||
use crate::{
|
||||
cmm_eotf::Eotf, cmm_luminance::Luminance, cmm_manager::ColorManager,
|
||||
cmm_primaries::Primaries, cmm_render_intent::RenderIntent,
|
||||
};
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
cmm::{cmm_eotf::Eotf, cmm_primaries::Primaries},
|
||||
gfx_api::AlphaMode,
|
||||
theme::Color,
|
||||
utils::ordered_float::F64,
|
||||
},
|
||||
crate::cmm_primaries::Primaries,
|
||||
jay_utils::ordered_float::F64,
|
||||
std::{
|
||||
fmt,
|
||||
fmt::{Debug, Formatter},
|
||||
|
|
@ -129,29 +125,6 @@ impl<T, U> Mul<[f64; 3]> for ColorMatrix<T, U> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, U> Mul<Color> for ColorMatrix<T, U> {
|
||||
type Output = Color;
|
||||
|
||||
fn mul(self, rhs: Color) -> Self::Output {
|
||||
let mut rgba = rhs.to_array(Eotf::Linear);
|
||||
let a = rgba[3];
|
||||
if a < 1.0 && a > 0.0 {
|
||||
for c in &mut rgba[..3] {
|
||||
*c /= a;
|
||||
}
|
||||
}
|
||||
let [r, g, b] = self * [rgba[0] as f64, rgba[1] as f64, rgba[2] as f64];
|
||||
Color::new(
|
||||
Eotf::Linear,
|
||||
AlphaMode::Straight,
|
||||
r as f32,
|
||||
g as f32,
|
||||
b as f32,
|
||||
a,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ColorMatrix<T, U> {
|
||||
pub const fn new(m: [[f64; 4]; 3]) -> Self {
|
||||
let m = [
|
||||
53
crates/cmm/src/lib.rs
Normal file
53
crates/cmm/src/lib.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
macro_rules! linear_ids {
|
||||
($ids:ident, $id:ident, $ty:ty $(,)?) => {
|
||||
#[derive(Debug)]
|
||||
pub struct $ids {
|
||||
next: jay_utils::numcell::NumCell<$ty>,
|
||||
}
|
||||
|
||||
impl Default for $ids {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: jay_utils::numcell::NumCell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $ids {
|
||||
pub fn next(&self) -> $id {
|
||||
$id(self.next.fetch_add(1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct $id($ty);
|
||||
|
||||
impl $id {
|
||||
#[allow(dead_code)]
|
||||
pub fn raw(&self) -> $ty {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn from_raw(id: $ty) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for $id {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod cmm_description;
|
||||
pub mod cmm_eotf;
|
||||
pub mod cmm_luminance;
|
||||
pub mod cmm_manager;
|
||||
pub mod cmm_primaries;
|
||||
pub mod cmm_render_intent;
|
||||
#[cfg(test)]
|
||||
mod cmm_tests;
|
||||
pub mod cmm_transform;
|
||||
24
crates/cpu-worker/Cargo.toml
Normal file
24
crates/cpu-worker/Cargo.toml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "jay-cpu-worker"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-async-engine = { path = "../async-engine" }
|
||||
jay-geometry = { path = "../geometry" }
|
||||
jay-io-uring = { path = "../io-uring" }
|
||||
jay-tracy = { path = "../tracy" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
log = { version = "0.4.20", features = ["std"] }
|
||||
parking_lot = "0.12.1"
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
|
||||
[dev-dependencies]
|
||||
jay-wheel = { path = "../wheel" }
|
||||
|
||||
[features]
|
||||
it = []
|
||||
tracy = ["jay-tracy/tracy", "jay-async-engine/tracy"]
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
cpu_worker::{AsyncCpuWork, CpuWork},
|
||||
rect::Rect,
|
||||
},
|
||||
crate::{AsyncCpuWork, CpuWork},
|
||||
jay_geometry::Rect,
|
||||
std::ptr,
|
||||
};
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ impl ImgCopyWork {
|
|||
|
||||
impl CpuWork for ImgCopyWork {
|
||||
fn run(&mut self) -> Option<Box<dyn AsyncCpuWork>> {
|
||||
zone!("ImgCopyWork");
|
||||
jay_tracy::zone!("ImgCopyWork");
|
||||
for rect in &self.rects {
|
||||
let mut offset = rect.y1() * self.stride + rect.x1() * self.bpp;
|
||||
if rect.width() == self.width {
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
cpu_worker::{AsyncCpuWork, CompletedWork, CpuWork, WorkCompletion},
|
||||
io_uring::{IoUring, IoUringError, IoUringTaskId},
|
||||
},
|
||||
crate::{AsyncCpuWork, CompletedWork, CpuWork, WorkCompletion},
|
||||
jay_async_engine::{AsyncEngine, SpawnedFuture},
|
||||
jay_io_uring::{IoUring, IoUringError, IoUringTaskId},
|
||||
std::{
|
||||
any::Any,
|
||||
ptr,
|
||||
|
|
@ -3,19 +3,18 @@ pub mod jobs;
|
|||
mod tests;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
io_uring::IoUring,
|
||||
utils::{
|
||||
buf::TypedBuf,
|
||||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
oserror::{OsError, OsErrorExt2},
|
||||
pipe::{Pipe, pipe},
|
||||
ptr_ext::MutPtrExt,
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
jay_async_engine::{AsyncEngine, SpawnedFuture},
|
||||
jay_io_uring::IoUring,
|
||||
jay_utils::{
|
||||
buf::TypedBuf,
|
||||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
numcell::NumCell,
|
||||
oserror::{OsError, OsErrorExt2},
|
||||
pipe::{Pipe, pipe},
|
||||
ptr_ext::MutPtrExt,
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
parking_lot::{Condvar, Mutex},
|
||||
std::{
|
||||
|
|
@ -138,7 +137,27 @@ struct CpuWorkerData {
|
|||
sync_wake_condvar: Arc<Condvar>,
|
||||
}
|
||||
|
||||
linear_ids!(CpuJobIds, CpuJobId, u64);
|
||||
#[derive(Debug)]
|
||||
struct CpuJobIds {
|
||||
next: NumCell<u64>,
|
||||
}
|
||||
|
||||
impl Default for CpuJobIds {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: NumCell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuJobIds {
|
||||
fn next(&self) -> CpuJobId {
|
||||
CpuJobId(self.next.fetch_add(1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
struct CpuJobId(u64);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CpuWorkerError {
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
cpu_worker::{AsyncCpuWork, CompletedWork, CpuJob, CpuWork, CpuWorker, WorkCompletion},
|
||||
io_uring::IoUring,
|
||||
utils::asyncevent::AsyncEvent,
|
||||
wheel::Wheel,
|
||||
},
|
||||
crate::{AsyncCpuWork, CompletedWork, CpuJob, CpuWork, CpuWorker, WorkCompletion},
|
||||
jay_async_engine::{AsyncEngine, SpawnedFuture},
|
||||
jay_io_uring::IoUring,
|
||||
jay_utils::asyncevent::AsyncEvent,
|
||||
jay_wheel::Wheel,
|
||||
std::{future::pending, rc::Rc, sync::Arc},
|
||||
uapi::{OwnedFd, c::EFD_CLOEXEC},
|
||||
};
|
||||
12
crates/criteria/Cargo.toml
Normal file
12
crates/criteria/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "jay-criteria"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
ahash = "0.8.7"
|
||||
linearize = { version = "0.1.3", features = ["derive"] }
|
||||
regex = "1.11.1"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, crit_upstream::CritUpstreamNode},
|
||||
},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{
|
||||
CritDownstream, CritDownstreamData, CritTarget, CritUpstreamData,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId, CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
||||
crit_graph::{
|
||||
CritTarget, CritUpstreamData,
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId, FixedRootMatcher, crit_leaf::CritLeafEvent,
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, queue::AsyncQueue},
|
||||
CritDestroyListener, CritMatcherId, FixedRootMatcher, crit_leaf::CritLeafEvent,
|
||||
crit_matchers::critm_constant::CritMatchConstant,
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, queue::AsyncQueue},
|
||||
std::{
|
||||
hash::Hash,
|
||||
rc::{Rc, Weak},
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritDestroyListener, CritMatcherId,
|
||||
crit_graph::{
|
||||
WeakCritTargetOwner,
|
||||
crit_downstream::CritDownstream,
|
||||
crit_target::{CritTarget, CritTargetOwner},
|
||||
},
|
||||
crit_per_target_data::CritPerTargetData,
|
||||
CritDestroyListener, CritMatcherId,
|
||||
crit_graph::{
|
||||
WeakCritTargetOwner,
|
||||
crit_downstream::CritDownstream,
|
||||
crit_target::{CritTarget, CritTargetOwner},
|
||||
},
|
||||
utils::copyhashmap::CopyHashMap,
|
||||
crit_per_target_data::CritPerTargetData,
|
||||
},
|
||||
jay_utils::copyhashmap::CopyHashMap,
|
||||
std::{
|
||||
cell::RefMut,
|
||||
mem,
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
criteria::{
|
||||
CritUpstreamNode,
|
||||
crit_graph::{CritDownstream, CritDownstreamData, CritMgr, CritTarget},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
utils::{cell_ext::CellExt, queue::AsyncQueue},
|
||||
CritUpstreamNode,
|
||||
crit_graph::{CritDownstream, CritDownstreamData, CritMgr, CritTarget},
|
||||
crit_per_target_data::{CritDestroyListenerBase, CritPerTargetData},
|
||||
},
|
||||
jay_utils::{cell_ext::CellExt, queue::AsyncQueue},
|
||||
std::{
|
||||
cell::Cell,
|
||||
rc::{Rc, Weak},
|
||||
|
|
@ -24,7 +22,7 @@ where
|
|||
events: Rc<AsyncQueue<CritLeafEvent<Target>>>,
|
||||
}
|
||||
|
||||
pub(in crate::criteria) struct NodeHolder<Target>
|
||||
pub struct NodeHolder<Target>
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
|
|
@ -77,7 +75,7 @@ impl<Target> CritLeafMatcher<Target>
|
|||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
pub(in crate::criteria) fn new(
|
||||
pub(crate) fn new(
|
||||
mgr: &Target::Mgr,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Target>>,
|
||||
on_match: impl Fn(Target::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
crate::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherIds, FixedRootMatcher,
|
||||
crit_graph::{
|
||||
CritFixedRootCriterion, CritFixedRootCriterionBase, CritMgr, CritRoot, CritRootFixed,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
crate::crit_graph::{CritMiddleCriterion, CritTarget, CritUpstreamNode},
|
||||
std::{marker::PhantomData, rc::Rc},
|
||||
};
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritLiteralOrRegex, RootMatcherMap,
|
||||
crit_graph::{CritRootCriterion, CritTarget},
|
||||
},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::criteria::{
|
||||
crate::{
|
||||
CritMatcherId,
|
||||
crit_graph::{CritTarget, CritTargetOwner, WeakCritTargetOwner},
|
||||
},
|
||||
|
|
@ -28,7 +28,7 @@ where
|
|||
data: T,
|
||||
}
|
||||
|
||||
pub(super) trait CritDestroyListenerBase<Target>: 'static
|
||||
pub trait CritDestroyListenerBase<Target>: 'static
|
||||
where
|
||||
Target: CritTarget,
|
||||
{
|
||||
131
crates/criteria/src/lib.rs
Normal file
131
crates/criteria/src/lib.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
pub mod crit_graph;
|
||||
pub mod crit_leaf;
|
||||
pub mod crit_matchers;
|
||||
pub mod crit_per_target_data;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
crit_graph::{CritMgr, CritMiddle, CritRoot, CritRootCriterion, CritRootFixed},
|
||||
crit_leaf::CritLeafMatcher,
|
||||
crit_matchers::{critm_any_or_all::CritMatchAnyOrAll, critm_exactly::CritMatchExactly},
|
||||
},
|
||||
jay_utils::{copyhashmap::CopyHashMap, numcell::NumCell},
|
||||
linearize::StaticMap,
|
||||
regex::Regex,
|
||||
std::rc::{Rc, Weak},
|
||||
};
|
||||
pub use {
|
||||
crit_graph::{CritTarget, CritUpstreamNode},
|
||||
crit_per_target_data::CritDestroyListener,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CritMatcherIds {
|
||||
next: NumCell<u64>,
|
||||
}
|
||||
|
||||
impl Default for CritMatcherIds {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: NumCell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CritMatcherIds {
|
||||
pub fn next(&self) -> CritMatcherId {
|
||||
CritMatcherId(self.next.fetch_add(1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct CritMatcherId(u64);
|
||||
|
||||
impl CritMatcherId {
|
||||
#[allow(clippy::allow_attributes, dead_code)]
|
||||
pub fn raw(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(clippy::allow_attributes, dead_code)]
|
||||
pub fn from_raw(id: u64) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CritMatcherId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub type RootMatcherMap<Target, T> = CopyHashMap<CritMatcherId, Weak<CritRoot<Target, T>>>;
|
||||
pub type FixedRootMatcher<Target, T> =
|
||||
StaticMap<bool, Rc<CritRoot<Target, CritRootFixed<Target, T>>>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CritLiteralOrRegex {
|
||||
Literal(String),
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
impl CritLiteralOrRegex {
|
||||
fn matches(&self, string: &str) -> bool {
|
||||
match self {
|
||||
CritLiteralOrRegex::Literal(p) => string == p,
|
||||
CritLiteralOrRegex::Regex(r) => r.is_match(string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CritMgrExt: CritMgr {
|
||||
fn list(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
all: bool,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if upstream.is_empty() {
|
||||
return self.match_constant()[all].clone();
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchAnyOrAll::new(upstream, all))
|
||||
}
|
||||
|
||||
fn exactly(
|
||||
&self,
|
||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
||||
num: usize,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
if num > upstream.len() {
|
||||
return self.match_constant()[false].clone();
|
||||
}
|
||||
if num == 0 {
|
||||
let upstream: Vec<_> = upstream.iter().map(|u| u.not(self)).collect();
|
||||
return self.list(&upstream, true);
|
||||
}
|
||||
CritMiddle::new(self, upstream, CritMatchExactly::new(upstream, num))
|
||||
}
|
||||
|
||||
fn leaf(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
on_match: impl Fn(<Self::Target as CritTarget>::LeafData) -> Box<dyn FnOnce()> + 'static,
|
||||
) -> Rc<CritLeafMatcher<Self::Target>> {
|
||||
CritLeafMatcher::new(self, upstream, on_match)
|
||||
}
|
||||
|
||||
fn not(
|
||||
&self,
|
||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
||||
upstream.not(self)
|
||||
}
|
||||
|
||||
fn root<T>(&self, criterion: T) -> Rc<dyn CritUpstreamNode<Self::Target>>
|
||||
where
|
||||
T: CritRootCriterion<Self::Target>,
|
||||
{
|
||||
CritRoot::new(self.roots(), self.id(), criterion)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CritMgrExt for T where T: CritMgr {}
|
||||
10
crates/damage/Cargo.toml
Normal file
10
crates/damage/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "jay-damage"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-geometry = { path = "../geometry" }
|
||||
jay-tree-types = { path = "../tree-types" }
|
||||
jay-units = { path = "../units" }
|
||||
116
crates/damage/src/lib.rs
Normal file
116
crates/damage/src/lib.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use {
|
||||
jay_geometry::Rect,
|
||||
jay_tree_types::Transform,
|
||||
jay_units::fixed::Fixed,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct DamageMatrix {
|
||||
transform: Transform,
|
||||
mx: f64,
|
||||
my: f64,
|
||||
dx: f64,
|
||||
dy: f64,
|
||||
smear: i32,
|
||||
}
|
||||
|
||||
impl Default for DamageMatrix {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
transform: Default::default(),
|
||||
mx: 1.0,
|
||||
my: 1.0,
|
||||
dx: 0.0,
|
||||
dy: 0.0,
|
||||
smear: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DamageMatrix {
|
||||
pub fn apply(&self, dx: i32, dy: i32, rect: Rect) -> Rect {
|
||||
let x1 = rect.x1() - self.smear;
|
||||
let x2 = rect.x2() + self.smear;
|
||||
let y1 = rect.y1() - self.smear;
|
||||
let y2 = rect.y2() + self.smear;
|
||||
let [x1, y1, x2, y2] = match self.transform {
|
||||
Transform::None => [x1, y1, x2, y2],
|
||||
Transform::Rotate90 => [-y2, x1, -y1, x2],
|
||||
Transform::Rotate180 => [-x2, -y2, -x1, -y1],
|
||||
Transform::Rotate270 => [y1, -x2, y2, -x1],
|
||||
Transform::Flip => [-x2, y1, -x1, y2],
|
||||
Transform::FlipRotate90 => [y1, x1, y2, x2],
|
||||
Transform::FlipRotate180 => [x1, -y2, x2, -y1],
|
||||
Transform::FlipRotate270 => [-y2, -x2, -y1, -x1],
|
||||
};
|
||||
let x1 = (x1 as f64 * self.mx + self.dx).floor() as i32 + dx;
|
||||
let y1 = (y1 as f64 * self.my + self.dy).floor() as i32 + dy;
|
||||
let x2 = (x2 as f64 * self.mx + self.dx).ceil() as i32 + dx;
|
||||
let y2 = (y2 as f64 * self.my + self.dy).ceil() as i32 + dy;
|
||||
Rect::new_saturating(x1, y1, x2, y2)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
transform: Transform,
|
||||
legacy_scale: i32,
|
||||
buffer_width: i32,
|
||||
buffer_height: i32,
|
||||
viewport: Option<[Fixed; 4]>,
|
||||
dst_width: i32,
|
||||
dst_height: i32,
|
||||
) -> DamageMatrix {
|
||||
let mut buffer_width = buffer_width as f64;
|
||||
let mut buffer_height = buffer_height as f64;
|
||||
let dst_width = dst_width as f64;
|
||||
let dst_height = dst_height as f64;
|
||||
|
||||
let mut mx = 1.0;
|
||||
let mut my = 1.0;
|
||||
if legacy_scale != 1 {
|
||||
let scale_inv = 1.0 / (legacy_scale as f64);
|
||||
mx = scale_inv;
|
||||
my = scale_inv;
|
||||
buffer_width *= scale_inv;
|
||||
buffer_height *= scale_inv;
|
||||
}
|
||||
let (mut buffer_width, mut buffer_height) =
|
||||
transform.maybe_swap((buffer_width, buffer_height));
|
||||
let (mut dx, mut dy) = match transform {
|
||||
Transform::None => (0.0, 0.0),
|
||||
Transform::Rotate90 => (buffer_width, 0.0),
|
||||
Transform::Rotate180 => (buffer_width, buffer_height),
|
||||
Transform::Rotate270 => (0.0, buffer_height),
|
||||
Transform::Flip => (buffer_width, 0.0),
|
||||
Transform::FlipRotate90 => (0.0, 0.0),
|
||||
Transform::FlipRotate180 => (0.0, buffer_height),
|
||||
Transform::FlipRotate270 => (buffer_width, buffer_height),
|
||||
};
|
||||
if let Some([x, y, w, h]) = viewport {
|
||||
dx -= x.to_f64();
|
||||
dy -= y.to_f64();
|
||||
buffer_width = w.to_f64();
|
||||
buffer_height = h.to_f64();
|
||||
}
|
||||
let mut smear = false;
|
||||
if dst_width != buffer_width {
|
||||
let scale = dst_width / buffer_width;
|
||||
mx *= scale;
|
||||
dx *= scale;
|
||||
smear |= dst_width > buffer_width;
|
||||
}
|
||||
if dst_height != buffer_height {
|
||||
let scale = dst_height / buffer_height;
|
||||
my *= scale;
|
||||
dy *= scale;
|
||||
smear |= dst_height > buffer_height;
|
||||
}
|
||||
DamageMatrix {
|
||||
transform,
|
||||
mx,
|
||||
my,
|
||||
dx,
|
||||
dy,
|
||||
smear: smear as _,
|
||||
}
|
||||
}
|
||||
}
|
||||
14
crates/dbus-core/Cargo.toml
Normal file
14
crates/dbus-core/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "jay-dbus-core"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-bufio = { path = "../bufio" }
|
||||
jay-io-uring = { path = "../io-uring" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
bstr = { version = "1.9.0", default-features = false, features = ["std"] }
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
|
|
@ -3,10 +3,8 @@ use {
|
|||
TY_ARRAY, TY_BOOLEAN, TY_BYTE, TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH,
|
||||
TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
|
||||
},
|
||||
crate::{
|
||||
dbus::{DbusError, DynamicType, Parser, types::Variant},
|
||||
utils::buf::DynamicBuf,
|
||||
},
|
||||
crate::{types::Variant, DbusError, DynamicType, Parser},
|
||||
jay_utils::buf::DynamicBuf,
|
||||
std::ops::Deref,
|
||||
};
|
||||
|
||||
|
|
@ -156,11 +154,8 @@ impl DynamicType {
|
|||
}
|
||||
let mut vals = vec![];
|
||||
{
|
||||
let mut parser = Parser {
|
||||
buf: &parser.buf[..parser.pos + len],
|
||||
pos: parser.pos,
|
||||
fds: parser.fds,
|
||||
};
|
||||
let mut parser =
|
||||
Parser::new_at(&parser.buf[..parser.pos + len], parser.pos, parser.fds);
|
||||
while !parser.eof() {
|
||||
vals.push(el.parse(&mut parser)?);
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
dbus::{DbusType, Formatter, types::Variant},
|
||||
utils::buf::DynamicBuf,
|
||||
},
|
||||
crate::{types::Variant, DbusType, Formatter},
|
||||
jay_utils::buf::DynamicBuf,
|
||||
std::rc::Rc,
|
||||
uapi::{OwnedFd, Packed},
|
||||
};
|
||||
232
crates/dbus-core/src/lib.rs
Normal file
232
crates/dbus-core/src/lib.rs
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
pub use {property::{Get, GetReply}, types::*};
|
||||
use {
|
||||
jay_bufio::BufIoError,
|
||||
jay_io_uring::IoUringError,
|
||||
jay_utils::{buf::DynamicBuf, oserror::OsError},
|
||||
std::{borrow::Cow, fmt::Display, rc::Rc},
|
||||
thiserror::Error,
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
mod dynamic_type;
|
||||
mod formatter;
|
||||
mod parser;
|
||||
pub mod property;
|
||||
pub mod types;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CallError {
|
||||
pub name: String,
|
||||
pub msg: Option<String>,
|
||||
}
|
||||
|
||||
impl Display for CallError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(msg) = &self.msg {
|
||||
write!(f, "{}: {}", self.name, msg)
|
||||
} else {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DbusError {
|
||||
#[error("Encountered an unknown type in a signature")]
|
||||
UnknownType,
|
||||
#[error("Function call reply does not contain a reply serial")]
|
||||
NoReplySerial,
|
||||
#[error("Signal message contains no interface or member or path")]
|
||||
MissingSignalHeaders,
|
||||
#[error("Method call message contains no interface or member or path")]
|
||||
MissingMethodCallHeaders,
|
||||
#[error("Error has no error name")]
|
||||
NoErrorName,
|
||||
#[error("The socket was killed")]
|
||||
Killed,
|
||||
#[error("{0}")]
|
||||
CallError(CallError),
|
||||
#[error("FD index is out of bounds")]
|
||||
OobFds,
|
||||
#[error("Variant has an invalid type")]
|
||||
InvalidVariantType,
|
||||
#[error("Could not create a socket")]
|
||||
Socket(#[source] OsError),
|
||||
#[error("Could not connect")]
|
||||
Connect(#[source] IoUringError),
|
||||
#[error("Could not write to the dbus socket")]
|
||||
WriteError(#[source] IoUringError),
|
||||
#[error("Could not read from the dbus socket")]
|
||||
ReadError(#[source] IoUringError),
|
||||
#[error("timeout")]
|
||||
IoUringError(#[source] Box<IoUringError>),
|
||||
#[error("Server did not send auth challenge")]
|
||||
NoChallenge,
|
||||
#[error("Server did not accept our authentication")]
|
||||
Auth,
|
||||
#[error("Array length is not a multiple of the element size")]
|
||||
PodArrayLength,
|
||||
#[error("Peer did not send enough fds")]
|
||||
TooFewFds,
|
||||
#[error("Variant signature is not a single type")]
|
||||
TrailingVariantSignature,
|
||||
#[error("Dict signature does not contain a terminating '}}'")]
|
||||
UnterminatedDict,
|
||||
#[error("Struct signature does not contain a terminating '}}'")]
|
||||
UnterminatedStruct,
|
||||
#[error("Dict signature contains trailing types")]
|
||||
DictTrailing,
|
||||
#[error("String does not contain valid UTF-8")]
|
||||
InvalidUtf8,
|
||||
#[error("Unexpected end of message")]
|
||||
UnexpectedEof,
|
||||
#[error("Boolean value was not 0 or 1")]
|
||||
InvalidBoolValue,
|
||||
#[error("Signature is empty")]
|
||||
EmptySignature,
|
||||
#[error("The session bus address is not set")]
|
||||
SessionBusAddressNotSet,
|
||||
#[error("Server does not support FD passing")]
|
||||
UnixFd,
|
||||
#[error("Server message has a different endianess than ourselves")]
|
||||
InvalidEndianess,
|
||||
#[error("Server speaks an unexpected protocol version")]
|
||||
InvalidProtocol,
|
||||
#[error("Signature contains an invalid type")]
|
||||
InvalidSignatureType,
|
||||
#[error("The signal already has a handler")]
|
||||
AlreadyHandled,
|
||||
#[error(transparent)]
|
||||
BufIoError(#[from] BufIoError),
|
||||
#[error(transparent)]
|
||||
DbusError(Rc<DbusError>),
|
||||
}
|
||||
|
||||
impl From<IoUringError> for DbusError {
|
||||
fn from(e: IoUringError) -> Self {
|
||||
DbusError::IoUringError(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
const TY_BYTE: u8 = b'y';
|
||||
const TY_BOOLEAN: u8 = b'b';
|
||||
const TY_INT16: u8 = b'n';
|
||||
const TY_UINT16: u8 = b'q';
|
||||
const TY_INT32: u8 = b'i';
|
||||
const TY_UINT32: u8 = b'u';
|
||||
const TY_INT64: u8 = b'x';
|
||||
const TY_UINT64: u8 = b't';
|
||||
const TY_DOUBLE: u8 = b'd';
|
||||
const TY_STRING: u8 = b's';
|
||||
const TY_OBJECT_PATH: u8 = b'o';
|
||||
const TY_SIGNATURE: u8 = b'g';
|
||||
const TY_ARRAY: u8 = b'a';
|
||||
const TY_VARIANT: u8 = b'v';
|
||||
const TY_UNIX_FD: u8 = b'h';
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DynamicType {
|
||||
U8,
|
||||
Bool,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F64,
|
||||
String,
|
||||
ObjectPath,
|
||||
Signature,
|
||||
Variant,
|
||||
Fd,
|
||||
Array(Box<DynamicType>),
|
||||
DictEntry(Box<DynamicType>, Box<DynamicType>),
|
||||
Struct(Vec<DynamicType>),
|
||||
}
|
||||
|
||||
pub struct Parser<'a> {
|
||||
pub(crate) buf: &'a [u8],
|
||||
pub(crate) pos: usize,
|
||||
pub(crate) fds: &'a [Rc<OwnedFd>],
|
||||
}
|
||||
|
||||
pub struct Formatter<'a> {
|
||||
fds: &'a mut Vec<Rc<OwnedFd>>,
|
||||
buf: &'a mut DynamicBuf,
|
||||
}
|
||||
|
||||
pub unsafe trait Message<'a>: Sized + 'a {
|
||||
const SIGNATURE: &'static str;
|
||||
const INTERFACE: &'static str;
|
||||
const MEMBER: &'static str;
|
||||
type Generic<'b>: Message<'b>;
|
||||
|
||||
fn marshal(&self, w: &mut Formatter);
|
||||
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||
fn num_fds(&self) -> u32;
|
||||
}
|
||||
|
||||
pub struct ErrorMessage<'a> {
|
||||
pub msg: Cow<'a, str>,
|
||||
}
|
||||
|
||||
unsafe impl<'a> Message<'a> for ErrorMessage<'a> {
|
||||
const SIGNATURE: &'static str = "s";
|
||||
const INTERFACE: &'static str = "";
|
||||
const MEMBER: &'static str = "";
|
||||
type Generic<'b> = ErrorMessage<'b>;
|
||||
|
||||
fn marshal(&self, w: &mut Formatter) {
|
||||
self.msg.marshal(w)
|
||||
}
|
||||
|
||||
fn unmarshal(p: &mut Parser<'a>) -> Result<Self, DbusError> {
|
||||
Ok(Self {
|
||||
msg: p.unmarshal()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn num_fds(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Property {
|
||||
const INTERFACE: &'static str;
|
||||
const PROPERTY: &'static str;
|
||||
type Type: DbusType<'static>;
|
||||
}
|
||||
|
||||
pub trait Signal<'a>: Message<'a> {}
|
||||
|
||||
pub trait MethodCall<'a>: Message<'a> {
|
||||
type Reply: Message<'static>;
|
||||
}
|
||||
|
||||
pub unsafe trait DbusType<'a>: Clone + 'a {
|
||||
const ALIGNMENT: usize;
|
||||
const IS_POD: bool;
|
||||
type Generic<'b>: DbusType<'b> + 'b;
|
||||
|
||||
fn consume_signature(s: &mut &[u8]) -> Result<(), DbusError>;
|
||||
#[allow(clippy::allow_attributes, dead_code)]
|
||||
fn write_signature(w: &mut Vec<u8>);
|
||||
fn marshal(&self, fmt: &mut Formatter);
|
||||
fn unmarshal(parser: &mut Parser<'a>) -> Result<Self, DbusError>;
|
||||
|
||||
fn num_fds(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use {
|
||||
super::{
|
||||
DbusError, DbusType, Formatter, Message, MethodCall, Parser, Property, Signal,
|
||||
types::{Bool, DictEntry, ObjectPath, Variant},
|
||||
},
|
||||
std::{borrow::Cow, rc::Rc},
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::dbus::{
|
||||
crate::{
|
||||
types::{Bool, ObjectPath, Signature, Variant, FALSE, TRUE},
|
||||
DbusError, DbusType, DynamicType, Parser,
|
||||
types::{Bool, FALSE, ObjectPath, Signature, TRUE, Variant},
|
||||
},
|
||||
bstr::ByteSlice,
|
||||
std::{borrow::Cow, rc::Rc},
|
||||
|
|
@ -10,7 +10,11 @@ use {
|
|||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(buf: &'a [u8], fds: &'a [Rc<OwnedFd>]) -> Self {
|
||||
Self { buf, pos: 0, fds }
|
||||
Self::new_at(buf, 0, fds)
|
||||
}
|
||||
|
||||
pub fn new_at(buf: &'a [u8], pos: usize, fds: &'a [Rc<OwnedFd>]) -> Self {
|
||||
Self { buf, pos, fds }
|
||||
}
|
||||
|
||||
pub fn eof(&self) -> bool {
|
||||
|
|
@ -107,11 +111,7 @@ impl<'a> Parser<'a> {
|
|||
self.pos += len;
|
||||
Ok(Cow::Borrowed(slice))
|
||||
} else {
|
||||
let mut parser = Parser {
|
||||
buf: &self.buf[..self.pos + len],
|
||||
pos: self.pos,
|
||||
fds: self.fds,
|
||||
};
|
||||
let mut parser = Parser::new_at(&self.buf[..self.pos + len], self.pos, self.fds);
|
||||
self.pos += len;
|
||||
let mut res = vec![];
|
||||
while !parser.eof() {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::dbus::{DbusError, DbusType, Formatter, Message, MethodCall, Parser},
|
||||
crate::{DbusError, DbusType, Formatter, Message, MethodCall, Parser},
|
||||
std::{borrow::Cow, marker::PhantomData},
|
||||
};
|
||||
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
dbus::{
|
||||
DbusError, DbusType, DynamicType, Formatter, Parser, TY_ARRAY, TY_BOOLEAN, TY_BYTE,
|
||||
TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING,
|
||||
TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
|
||||
},
|
||||
utils::buf::DynamicBuf,
|
||||
DbusError, DbusType, DynamicType, Formatter, Parser, TY_ARRAY, TY_BOOLEAN, TY_BYTE,
|
||||
TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING,
|
||||
TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
|
||||
},
|
||||
jay_utils::buf::DynamicBuf,
|
||||
std::{borrow::Cow, ops::Deref, rc::Rc},
|
||||
uapi::{OwnedFd, Packed, Pod},
|
||||
};
|
||||
|
|
@ -501,31 +499,6 @@ impl<'a> Variant<'a> {
|
|||
w.push(c);
|
||||
}
|
||||
|
||||
pub fn borrow<'b>(&'b self) -> Variant<'b> {
|
||||
match self {
|
||||
Variant::U8(v) => Variant::U8(*v),
|
||||
Variant::Bool(v) => Variant::Bool(*v),
|
||||
Variant::I16(v) => Variant::I16(*v),
|
||||
Variant::U16(v) => Variant::U16(*v),
|
||||
Variant::I32(v) => Variant::I32(*v),
|
||||
Variant::U32(v) => Variant::U32(*v),
|
||||
Variant::I64(v) => Variant::I64(*v),
|
||||
Variant::U64(v) => Variant::U64(*v),
|
||||
Variant::F64(v) => Variant::F64(*v),
|
||||
Variant::String(v) => Variant::String(v.deref().into()),
|
||||
Variant::ObjectPath(v) => Variant::ObjectPath(ObjectPath(v.0.deref().into())),
|
||||
Variant::Signature(v) => Variant::Signature(Signature(v.0.deref().into())),
|
||||
Variant::Variant(v) => Variant::Variant(Box::new(v.deref().borrow())),
|
||||
Variant::Fd(v) => Variant::Fd(v.clone()),
|
||||
Variant::Array(t, v) => {
|
||||
Variant::Array(t.clone(), v.iter().map(|v| v.borrow()).collect())
|
||||
}
|
||||
Variant::DictEntry(k, v) => {
|
||||
Variant::DictEntry(Box::new(k.deref().borrow()), Box::new(v.deref().borrow()))
|
||||
}
|
||||
Variant::Struct(v) => Variant::Struct(v.iter().map(|v| v.borrow()).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> DbusType<'a> for Variant<'a> {
|
||||
13
crates/drm-feedback/Cargo.toml
Normal file
13
crates/drm-feedback/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "jay-drm-feedback"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-video-types = { path = "../video-types" }
|
||||
|
||||
ahash = "0.8.7"
|
||||
byteorder = "1.5.0"
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
149
crates/drm-feedback/src/lib.rs
Normal file
149
crates/drm-feedback/src/lib.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
use {
|
||||
ahash::AHashMap,
|
||||
byteorder::{NativeEndian, WriteBytesExt},
|
||||
jay_video_types::Modifier,
|
||||
std::{io::Write, rc::Rc},
|
||||
thiserror::Error,
|
||||
uapi::{OwnedFd, c},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrmFeedbackIds {
|
||||
next: std::cell::Cell<u64>,
|
||||
}
|
||||
|
||||
impl Default for DrmFeedbackIds {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next: std::cell::Cell::new(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DrmFeedbackIds {
|
||||
pub fn next(&self) -> DrmFeedbackId {
|
||||
let id = self.next.get();
|
||||
self.next.set(id + 1);
|
||||
DrmFeedbackId(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct DrmFeedbackId(u64);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrmFeedbackShared {
|
||||
pub fd: Rc<OwnedFd>,
|
||||
pub size: usize,
|
||||
pub main_device: c::dev_t,
|
||||
pub indices: AHashMap<(u32, Modifier), u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrmFeedback {
|
||||
pub id: DrmFeedbackId,
|
||||
pub shared: Rc<DrmFeedbackShared>,
|
||||
pub tranches: Vec<DrmFeedbackTranche>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DrmFeedbackTranche {
|
||||
pub device: c::dev_t,
|
||||
pub indices: Vec<u16>,
|
||||
pub scanout: bool,
|
||||
}
|
||||
|
||||
impl DrmFeedback {
|
||||
pub fn new<C: DrmFeedbackContext + ?Sized>(
|
||||
ids: &DrmFeedbackIds,
|
||||
render_ctx: &C,
|
||||
) -> Result<Self, DrmFeedbackError> {
|
||||
let main_device = match render_ctx.main_device() {
|
||||
Some(dev) => dev,
|
||||
_ => return Err(DrmFeedbackError::NoDrmDevice),
|
||||
};
|
||||
let (data, index_map) = create_fd_data(render_ctx);
|
||||
let mut memfd =
|
||||
uapi::memfd_create("drm_feedback", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
||||
memfd.write_all(&data).unwrap();
|
||||
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
|
||||
uapi::fcntl_add_seals(
|
||||
memfd.raw(),
|
||||
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
||||
)
|
||||
.unwrap();
|
||||
Ok(Self {
|
||||
id: ids.next(),
|
||||
tranches: vec![DrmFeedbackTranche {
|
||||
device: main_device,
|
||||
indices: (0..index_map.len()).map(|v| v as u16).collect(),
|
||||
scanout: false,
|
||||
}],
|
||||
shared: Rc::new(DrmFeedbackShared {
|
||||
fd: Rc::new(memfd),
|
||||
size: data.len(),
|
||||
main_device,
|
||||
indices: index_map,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_scanout(
|
||||
&self,
|
||||
ids: &DrmFeedbackIds,
|
||||
devnum: c::dev_t,
|
||||
formats: &[(u32, Modifier)],
|
||||
) -> Result<Option<Self>, DrmFeedbackError> {
|
||||
let mut tranches = vec![];
|
||||
{
|
||||
let mut indices = vec![];
|
||||
for (format, modifier) in formats {
|
||||
if let Some(idx) = self.shared.indices.get(&(*format, *modifier)) {
|
||||
indices.push(*idx);
|
||||
}
|
||||
}
|
||||
if indices.len() > 0 {
|
||||
tranches.push(DrmFeedbackTranche {
|
||||
device: devnum,
|
||||
indices,
|
||||
scanout: true,
|
||||
});
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
tranches.extend(self.tranches.iter().cloned());
|
||||
Ok(Some(Self {
|
||||
id: ids.next(),
|
||||
shared: self.shared.clone(),
|
||||
tranches,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DrmFeedbackContext {
|
||||
fn main_device(&self) -> Option<c::dev_t>;
|
||||
fn for_each_read_format(&self, f: &mut dyn FnMut(u32, Modifier));
|
||||
}
|
||||
|
||||
fn create_fd_data<C: DrmFeedbackContext + ?Sized>(
|
||||
ctx: &C,
|
||||
) -> (Vec<u8>, AHashMap<(u32, Modifier), u16>) {
|
||||
let mut vec = vec![];
|
||||
let mut map = AHashMap::new();
|
||||
let mut pos = 0;
|
||||
ctx.for_each_read_format(&mut |format, modifier| {
|
||||
vec.write_u32::<NativeEndian>(format).unwrap();
|
||||
vec.write_u32::<NativeEndian>(0).unwrap();
|
||||
vec.write_u64::<NativeEndian>(modifier).unwrap();
|
||||
map.insert((format, modifier), pos);
|
||||
pos += 1;
|
||||
});
|
||||
(vec, map)
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DrmFeedbackError {
|
||||
#[error("Graphics API does not have a DRM device")]
|
||||
NoDrmDevice,
|
||||
}
|
||||
11
crates/edid/Cargo.toml
Normal file
11
crates/edid/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "jay-edid"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
description = "EDID parsing for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
bstr = { version = "1.9.0", default-features = false, features = ["std"] }
|
||||
thiserror = "2.0.11"
|
||||
|
|
@ -1,15 +1,48 @@
|
|||
use {
|
||||
crate::utils::{
|
||||
bitflags::BitflagsExt, clonecell::UnsafeCellCloneSafe, ptr_ext::PtrExt, stack::Stack,
|
||||
},
|
||||
bstr::{BString, ByteSlice},
|
||||
std::{
|
||||
cell::RefCell,
|
||||
fmt::{Debug, Formatter},
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
trait BitflagsExt {
|
||||
fn contains(self, other: Self) -> bool;
|
||||
}
|
||||
|
||||
impl BitflagsExt for u8 {
|
||||
fn contains(self, other: Self) -> bool {
|
||||
self & other == other
|
||||
}
|
||||
}
|
||||
|
||||
struct Stack<T>(RefCell<Vec<T>>);
|
||||
|
||||
impl<T> Default for Stack<T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stack<T> {
|
||||
fn push(&self, v: T) {
|
||||
self.0.borrow_mut().push(v);
|
||||
}
|
||||
|
||||
fn pop(&self) -> Option<T> {
|
||||
self.0.borrow_mut().pop()
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.0.borrow().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ColorBitDepth {
|
||||
Undefined,
|
||||
|
|
@ -30,7 +63,6 @@ pub enum DigitalVideoInterfaceStandard {
|
|||
HdmiB,
|
||||
MDDI,
|
||||
DisplayPort,
|
||||
#[expect(dead_code)]
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +82,6 @@ impl Debug for SignalLevelStandard {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub enum VideoInputDefinition {
|
||||
Analog {
|
||||
signal_level_standard: SignalLevelStandard,
|
||||
|
|
@ -87,7 +118,6 @@ pub struct ChromaticityCoordinates {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct EstablishedTimings {
|
||||
pub s_720x400_70: bool,
|
||||
pub s_720x400_88: bool,
|
||||
|
|
@ -118,7 +148,6 @@ pub enum AspectRatio {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct StandardTiming {
|
||||
pub x_resolution: u16,
|
||||
pub aspect_ratio: AspectRatio,
|
||||
|
|
@ -132,7 +161,6 @@ pub enum AnalogSyncType {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub enum SyncSignal {
|
||||
Analog {
|
||||
ty: AnalogSyncType,
|
||||
|
|
@ -184,7 +212,6 @@ impl Debug for StereoViewingSupport {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct DisplayRangeLimitsAndAdditionalTiming {
|
||||
pub vertical_field_rate_min: u16,
|
||||
pub vertical_field_rate_max: u16,
|
||||
|
|
@ -201,12 +228,10 @@ pub enum AspectRatioPreference {
|
|||
A16_10,
|
||||
A5_4,
|
||||
A15_9,
|
||||
#[expect(dead_code)]
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub enum ExtendedTimingInformation {
|
||||
DefaultGtf,
|
||||
NoTimingInformation,
|
||||
|
|
@ -240,7 +265,6 @@ pub enum ExtendedTimingInformation {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[expect(dead_code)]
|
||||
pub struct ColorPoint {
|
||||
pub white_point_index: u8,
|
||||
pub white_point_x: u16,
|
||||
|
|
@ -249,7 +273,6 @@ pub struct ColorPoint {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct EstablishedTimings3 {
|
||||
pub s640x350_85: bool,
|
||||
pub s640x400_85: bool,
|
||||
|
|
@ -298,7 +321,6 @@ pub struct EstablishedTimings3 {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct ColorManagementData {
|
||||
pub red_a3: u16,
|
||||
pub red_a2: u16,
|
||||
|
|
@ -325,7 +347,6 @@ pub enum CvtPreferredVerticalRate {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct Cvt3ByteCode {
|
||||
pub addressable_lines_per_field: u16,
|
||||
pub aspect_ration: CvtAspectRatio,
|
||||
|
|
@ -338,7 +359,6 @@ pub struct Cvt3ByteCode {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct DetailedTimingDescriptor {
|
||||
pub pixel_clock_khz: u32,
|
||||
pub horizontal_addressable_pixels: u16,
|
||||
|
|
@ -359,7 +379,6 @@ pub struct DetailedTimingDescriptor {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub enum Descriptor {
|
||||
Unknown(u8),
|
||||
DetailedTimingDescriptor(DetailedTimingDescriptor),
|
||||
|
|
@ -393,7 +412,6 @@ macro_rules! bail {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum EdidParseContext {
|
||||
#[expect(dead_code)]
|
||||
ReadingBytes(usize),
|
||||
BaseBlock,
|
||||
Descriptors,
|
||||
|
|
@ -410,8 +428,6 @@ pub enum EdidParseContext {
|
|||
VideoInputDefinition,
|
||||
}
|
||||
|
||||
unsafe impl UnsafeCellCloneSafe for EdidParseContext {}
|
||||
|
||||
struct EdidPushedContext {
|
||||
stack: Rc<Stack<(usize, EdidParseContext)>>,
|
||||
}
|
||||
|
|
@ -453,7 +469,7 @@ impl<'a> EdidParser<'a> {
|
|||
if self.data.len() - self.pos < N {
|
||||
bail!(self, EdidError::UnexpectedEof);
|
||||
}
|
||||
let v = unsafe { self.data[self.pos..].as_ptr().cast::<[u8; N]>().deref() };
|
||||
let v = self.data[self.pos..self.pos + N].try_into().unwrap();
|
||||
self.pos += N;
|
||||
Ok(v)
|
||||
}
|
||||
|
|
@ -1161,7 +1177,6 @@ pub enum DisplayColorType {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub enum FeatureSupport2 {
|
||||
Analog {
|
||||
display_color_type: DisplayColorType,
|
||||
|
|
@ -1174,7 +1189,6 @@ pub enum FeatureSupport2 {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct FeatureSupport {
|
||||
pub standby_supported: bool,
|
||||
pub suspend_supported: bool,
|
||||
|
|
@ -1186,7 +1200,6 @@ pub struct FeatureSupport {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct EdidBaseBlock {
|
||||
pub id_manufacturer_name: BString,
|
||||
pub id_product_code: u16,
|
||||
|
|
@ -1229,12 +1242,10 @@ pub enum CtaDataBlock {
|
|||
#[derive(Debug)]
|
||||
pub struct CtaAmdVendorDataBlock {
|
||||
pub minimum_refresh_hz: u8,
|
||||
#[expect(dead_code)]
|
||||
pub maximum_refresh_hz: u8,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct CtaColorimetryDataBlock {
|
||||
pub bt2020_rgb: bool,
|
||||
pub bt2020_ycc: bool,
|
||||
|
|
@ -1248,7 +1259,6 @@ pub struct CtaColorimetryDataBlock {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[expect(dead_code)]
|
||||
pub struct CtaStaticHdrMetadataDataBlock {
|
||||
pub traditional_gamma_sdr_luminance: bool,
|
||||
pub traditional_gamma_hdr_luminance: bool,
|
||||
14
crates/eventfd-cache/Cargo.toml
Normal file
14
crates/eventfd-cache/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "jay-eventfd-cache"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jay-async-engine = { path = "../async-engine" }
|
||||
jay-io-uring = { path = "../io-uring" }
|
||||
jay-utils = { path = "../utils" }
|
||||
|
||||
log = { version = "0.4.20", features = ["std"] }
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
io_uring::{IoUring, IoUringError},
|
||||
utils::{
|
||||
buf::Buf,
|
||||
errorfmt::ErrorFmt,
|
||||
oserror::{OsError, OsErrorExt, OsErrorExt2},
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
jay_async_engine::{AsyncEngine, SpawnedFuture},
|
||||
jay_io_uring::{IoUring, IoUringError},
|
||||
jay_utils::{
|
||||
buf::Buf,
|
||||
errorfmt::ErrorFmt,
|
||||
oserror::{OsError, OsErrorExt, OsErrorExt2},
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
std::{cell::Cell, future::poll_fn, pin::Pin, rc::Rc, slice, task::Poll},
|
||||
thiserror::Error,
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::AsyncEngine, eventfd_cache::EventfdCache, io_uring::IoUring, utils::array,
|
||||
},
|
||||
crate::EventfdCache,
|
||||
jay_async_engine::AsyncEngine,
|
||||
jay_io_uring::IoUring,
|
||||
jay_utils::array,
|
||||
std::{rc::Rc, slice},
|
||||
uapi::c,
|
||||
};
|
||||
13
crates/formats/Cargo.toml
Normal file
13
crates/formats/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "jay-formats"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
description = "Pixel format tables for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
ahash = "0.8.7"
|
||||
ash = { package = "jay-ash", version = "0.3.0" }
|
||||
clap = { version = "4.4.18", features = ["derive", "wrap_help"] }
|
||||
jay-config = { path = "../jay-config" }
|
||||
559
crates/formats/src/lib.rs
Normal file
559
crates/formats/src/lib.rs
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
use {
|
||||
ahash::AHashMap,
|
||||
ash::vk,
|
||||
clap::{ValueEnum, builder::PossibleValue},
|
||||
jay_config::video::Format as ConfigFormat,
|
||||
std::{
|
||||
fmt::{self, Debug, Write},
|
||||
sync::LazyLock,
|
||||
},
|
||||
};
|
||||
|
||||
pub type GLenum = u32;
|
||||
pub type GLint = i32;
|
||||
|
||||
const GL_RGBA: GLint = 0x1908;
|
||||
const GL_RGBA8: GLenum = 0x8058;
|
||||
const GL_BGRA_EXT: GLint = 0x80E1;
|
||||
const GL_UNSIGNED_BYTE: GLint = 0x1401;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FormatShmInfo {
|
||||
pub gl_format: GLint,
|
||||
pub gl_internal_format: GLenum,
|
||||
pub gl_type: GLint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Format {
|
||||
pub name: &'static str,
|
||||
pub vk_format: vk::Format,
|
||||
pub drm: u32,
|
||||
pub wl_id: Option<u32>,
|
||||
pub external_only_guess: bool,
|
||||
pub has_alpha: bool,
|
||||
pub opaque: Option<&'static Format>,
|
||||
pub shm_info: Option<FormatShmInfo>,
|
||||
pub config: ConfigFormat,
|
||||
pub bpp: u32,
|
||||
}
|
||||
|
||||
const fn default(config: ConfigFormat) -> Format {
|
||||
Format {
|
||||
name: "",
|
||||
vk_format: vk::Format::UNDEFINED,
|
||||
drm: 0,
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
shm_info: None,
|
||||
config,
|
||||
bpp: 4,
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Format {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.drm == other.drm
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Format {}
|
||||
|
||||
impl ValueEnum for &'static Format {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
ref_formats()
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(PossibleValue::new(self.name))
|
||||
}
|
||||
}
|
||||
|
||||
static FORMATS_MAP: LazyLock<AHashMap<u32, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.drm, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_REFS: LazyLock<Vec<&'static Format>> = LazyLock::new(|| FORMATS.iter().collect());
|
||||
|
||||
static FORMATS_NAMES: LazyLock<AHashMap<&'static str, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.name, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
static FORMATS_CONFIG: LazyLock<AHashMap<ConfigFormat, &'static Format>> = LazyLock::new(|| {
|
||||
let mut map = AHashMap::new();
|
||||
for format in FORMATS {
|
||||
assert!(map.insert(format.config, format).is_none());
|
||||
}
|
||||
map
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn formats_dont_panic() {
|
||||
formats();
|
||||
named_formats();
|
||||
config_formats();
|
||||
}
|
||||
|
||||
pub fn formats() -> &'static AHashMap<u32, &'static Format> {
|
||||
&FORMATS_MAP
|
||||
}
|
||||
|
||||
pub fn ref_formats() -> &'static [&'static Format] {
|
||||
&FORMATS_REFS
|
||||
}
|
||||
|
||||
pub fn named_formats() -> &'static AHashMap<&'static str, &'static Format> {
|
||||
&FORMATS_NAMES
|
||||
}
|
||||
|
||||
pub fn config_formats() -> &'static AHashMap<ConfigFormat, &'static Format> {
|
||||
&FORMATS_CONFIG
|
||||
}
|
||||
|
||||
const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 {
|
||||
(a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
|
||||
}
|
||||
|
||||
pub fn debug(fourcc: u32) -> impl Debug {
|
||||
fmt::from_fn(move |fmt| {
|
||||
fmt.write_char(fourcc as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 8) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 16) as u8 as char)?;
|
||||
fmt.write_char((fourcc >> 24) as u8 as char)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
const ARGB8888_ID: u32 = 0;
|
||||
const ARGB8888_DRM: u32 = fourcc_code('A', 'R', '2', '4');
|
||||
|
||||
const XRGB8888_ID: u32 = 1;
|
||||
const XRGB8888_DRM: u32 = fourcc_code('X', 'R', '2', '4');
|
||||
|
||||
pub fn map_wayland_format_id(id: u32) -> u32 {
|
||||
match id {
|
||||
ARGB8888_ID => ARGB8888_DRM,
|
||||
XRGB8888_ID => XRGB8888_DRM,
|
||||
_ => id,
|
||||
}
|
||||
}
|
||||
|
||||
pub static ARGB8888: &Format = &Format {
|
||||
name: "argb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: ARGB8888_DRM,
|
||||
wl_id: Some(ARGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB8888),
|
||||
config: ConfigFormat::ARGB8888,
|
||||
};
|
||||
|
||||
pub static XRGB8888: &Format = &Format {
|
||||
name: "xrgb8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_BGRA_EXT,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::B8G8R8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: XRGB8888_DRM,
|
||||
wl_id: Some(XRGB8888_ID),
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XRGB8888,
|
||||
};
|
||||
|
||||
static ABGR8888: &Format = &Format {
|
||||
name: "abgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR8888),
|
||||
config: ConfigFormat::ABGR8888,
|
||||
};
|
||||
|
||||
static XBGR8888: &Format = &Format {
|
||||
name: "xbgr8888",
|
||||
shm_info: Some(FormatShmInfo {
|
||||
gl_format: GL_RGBA,
|
||||
gl_internal_format: GL_RGBA8,
|
||||
gl_type: GL_UNSIGNED_BYTE,
|
||||
}),
|
||||
vk_format: vk::Format::R8G8B8A8_UNORM,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '2', '4'),
|
||||
wl_id: None,
|
||||
external_only_guess: false,
|
||||
has_alpha: false,
|
||||
opaque: None,
|
||||
config: ConfigFormat::XBGR8888,
|
||||
};
|
||||
|
||||
static R8: &Format = &Format {
|
||||
name: "r8",
|
||||
vk_format: vk::Format::R8_UNORM,
|
||||
bpp: 1,
|
||||
drm: fourcc_code('R', '8', ' ', ' '),
|
||||
..default(ConfigFormat::R8)
|
||||
};
|
||||
|
||||
static GR88: &Format = &Format {
|
||||
name: "gr88",
|
||||
vk_format: vk::Format::R8G8_UNORM,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('G', 'R', '8', '8'),
|
||||
..default(ConfigFormat::GR88)
|
||||
};
|
||||
|
||||
static RGB888: &Format = &Format {
|
||||
name: "rgb888",
|
||||
vk_format: vk::Format::B8G8R8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('R', 'G', '2', '4'),
|
||||
..default(ConfigFormat::RGB888)
|
||||
};
|
||||
|
||||
static BGR888: &Format = &Format {
|
||||
name: "bgr888",
|
||||
vk_format: vk::Format::R8G8B8_UNORM,
|
||||
bpp: 3,
|
||||
drm: fourcc_code('B', 'G', '2', '4'),
|
||||
..default(ConfigFormat::BGR888)
|
||||
};
|
||||
|
||||
static RGBA4444: &Format = &Format {
|
||||
name: "rgba4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX4444),
|
||||
..default(ConfigFormat::RGBA4444)
|
||||
};
|
||||
|
||||
static RGBX4444: &Format = &Format {
|
||||
name: "rgbx4444",
|
||||
vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '2'),
|
||||
..default(ConfigFormat::RGBX4444)
|
||||
};
|
||||
|
||||
static BGRA4444: &Format = &Format {
|
||||
name: "bgra4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '2'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX4444),
|
||||
..default(ConfigFormat::BGRA4444)
|
||||
};
|
||||
|
||||
static BGRX4444: &Format = &Format {
|
||||
name: "bgrx4444",
|
||||
vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '2'),
|
||||
..default(ConfigFormat::BGRX4444)
|
||||
};
|
||||
|
||||
static RGB565: &Format = &Format {
|
||||
name: "rgb565",
|
||||
vk_format: vk::Format::R5G6B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'G', '1', '6'),
|
||||
..default(ConfigFormat::RGB565)
|
||||
};
|
||||
|
||||
static BGR565: &Format = &Format {
|
||||
name: "bgr565",
|
||||
vk_format: vk::Format::B5G6R5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'G', '1', '6'),
|
||||
..default(ConfigFormat::BGR565)
|
||||
};
|
||||
|
||||
static RGBA5551: &Format = &Format {
|
||||
name: "rgba5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(RGBX5551),
|
||||
..default(ConfigFormat::RGBA5551)
|
||||
};
|
||||
|
||||
static RGBX5551: &Format = &Format {
|
||||
name: "rgbx5551",
|
||||
vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', 'X', '1', '5'),
|
||||
..default(ConfigFormat::RGBX5551)
|
||||
};
|
||||
|
||||
static BGRA5551: &Format = &Format {
|
||||
name: "bgra5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'A', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(BGRX5551),
|
||||
..default(ConfigFormat::BGRA5551)
|
||||
};
|
||||
|
||||
static BGRX5551: &Format = &Format {
|
||||
name: "bgrx5551",
|
||||
vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('B', 'X', '1', '5'),
|
||||
..default(ConfigFormat::BGRX5551)
|
||||
};
|
||||
|
||||
static ARGB1555: &Format = &Format {
|
||||
name: "argb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('A', 'R', '1', '5'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB1555),
|
||||
..default(ConfigFormat::ARGB1555)
|
||||
};
|
||||
|
||||
static XRGB1555: &Format = &Format {
|
||||
name: "xrgb1555",
|
||||
vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('X', 'R', '1', '5'),
|
||||
..default(ConfigFormat::XRGB1555)
|
||||
};
|
||||
|
||||
static ARGB2101010: &Format = &Format {
|
||||
name: "argb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'R', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XRGB2101010),
|
||||
..default(ConfigFormat::ARGB2101010)
|
||||
};
|
||||
|
||||
static XRGB2101010: &Format = &Format {
|
||||
name: "xrgb2101010",
|
||||
vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'R', '3', '0'),
|
||||
..default(ConfigFormat::XRGB2101010)
|
||||
};
|
||||
|
||||
static ABGR2101010: &Format = &Format {
|
||||
name: "abgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('A', 'B', '3', '0'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR2101010),
|
||||
..default(ConfigFormat::ABGR2101010)
|
||||
};
|
||||
|
||||
static XBGR2101010: &Format = &Format {
|
||||
name: "xbgr2101010",
|
||||
vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('X', 'B', '3', '0'),
|
||||
..default(ConfigFormat::XBGR2101010)
|
||||
};
|
||||
|
||||
static ABGR16161616: &Format = &Format {
|
||||
name: "abgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', '8'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616),
|
||||
..default(ConfigFormat::ABGR16161616)
|
||||
};
|
||||
|
||||
static XBGR16161616: &Format = &Format {
|
||||
name: "xbgr16161616",
|
||||
vk_format: vk::Format::R16G16B16A16_UNORM,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', '8'),
|
||||
..default(ConfigFormat::XBGR16161616)
|
||||
};
|
||||
|
||||
pub static ABGR16161616F: &Format = &Format {
|
||||
name: "abgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('A', 'B', '4', 'H'),
|
||||
has_alpha: true,
|
||||
opaque: Some(XBGR16161616F),
|
||||
..default(ConfigFormat::ABGR16161616F)
|
||||
};
|
||||
|
||||
static XBGR16161616F: &Format = &Format {
|
||||
name: "xbgr16161616f",
|
||||
vk_format: vk::Format::R16G16B16A16_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('X', 'B', '4', 'H'),
|
||||
..default(ConfigFormat::XBGR16161616F)
|
||||
};
|
||||
|
||||
static BGR161616: &Format = &Format {
|
||||
name: "bgr161616",
|
||||
vk_format: vk::Format::R16G16B16_UNORM,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', '4', '8'),
|
||||
..default(ConfigFormat::BGR161616)
|
||||
};
|
||||
|
||||
static R16F: &Format = &Format {
|
||||
name: "r16f",
|
||||
vk_format: vk::Format::R16_SFLOAT,
|
||||
bpp: 2,
|
||||
drm: fourcc_code('R', ' ', ' ', 'H'),
|
||||
..default(ConfigFormat::R16F)
|
||||
};
|
||||
|
||||
static GR1616F: &Format = &Format {
|
||||
name: "gr1616f",
|
||||
vk_format: vk::Format::R16G16_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('G', 'R', ' ', 'H'),
|
||||
..default(ConfigFormat::GR1616F)
|
||||
};
|
||||
|
||||
static BGR161616F: &Format = &Format {
|
||||
name: "bgr161616f",
|
||||
vk_format: vk::Format::R16G16B16_SFLOAT,
|
||||
bpp: 6,
|
||||
drm: fourcc_code('B', 'G', 'R', 'H'),
|
||||
..default(ConfigFormat::BGR161616F)
|
||||
};
|
||||
|
||||
static R32F: &Format = &Format {
|
||||
name: "r32f",
|
||||
vk_format: vk::Format::R32_SFLOAT,
|
||||
bpp: 4,
|
||||
drm: fourcc_code('R', ' ', ' ', 'F'),
|
||||
..default(ConfigFormat::R32F)
|
||||
};
|
||||
|
||||
static GR3232F: &Format = &Format {
|
||||
name: "gr3232f",
|
||||
vk_format: vk::Format::R32G32_SFLOAT,
|
||||
bpp: 8,
|
||||
drm: fourcc_code('G', 'R', ' ', 'F'),
|
||||
..default(ConfigFormat::GR3232F)
|
||||
};
|
||||
|
||||
static BGR323232F: &Format = &Format {
|
||||
name: "bgr323232f",
|
||||
vk_format: vk::Format::R32G32B32_SFLOAT,
|
||||
bpp: 12,
|
||||
drm: fourcc_code('B', 'G', 'R', 'F'),
|
||||
..default(ConfigFormat::BGR323232F)
|
||||
};
|
||||
|
||||
static ABGR32323232F: &Format = &Format {
|
||||
name: "abgr32323232f",
|
||||
vk_format: vk::Format::R32G32B32A32_SFLOAT,
|
||||
bpp: 16,
|
||||
drm: fourcc_code('A', 'B', '8', 'F'),
|
||||
has_alpha: true,
|
||||
..default(ConfigFormat::ABGR32323232F)
|
||||
};
|
||||
|
||||
pub static FORMATS: &[Format] = &[
|
||||
*ARGB8888,
|
||||
*XRGB8888,
|
||||
*ABGR8888,
|
||||
*XBGR8888,
|
||||
*R8,
|
||||
*GR88,
|
||||
*RGB888,
|
||||
*BGR888,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX4444,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGB565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR565,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*RGBX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRA5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGRX5551,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB1555,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ARGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XRGB2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR2101010,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*XBGR16161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R16F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR1616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR161616F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*R32F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*GR3232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*BGR323232F,
|
||||
#[cfg(target_endian = "little")]
|
||||
*ABGR32323232F,
|
||||
];
|
||||
11
crates/geometry/Cargo.toml
Normal file
11
crates/geometry/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "jay-geometry"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
description = "Geometry primitives for Jay"
|
||||
repository = "https://github.com/mahkoh/jay"
|
||||
|
||||
[dependencies]
|
||||
jay-algorithms = { path = "../algorithms" }
|
||||
smallvec = { version = "1.11.1", features = ["const_generics", "const_new", "union"] }
|
||||
|
|
@ -246,7 +246,6 @@ where
|
|||
dx * dx + dy * dy
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn contains_rect<U>(&self, rect: &Rect<U>) -> bool
|
||||
where
|
||||
U: Tag,
|
||||
|
|
@ -273,12 +272,10 @@ where
|
|||
self.raw.x1 == self.raw.x2 || self.raw.y1 == self.raw.y2
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn is_not_empty(&self) -> bool {
|
||||
!self.is_empty()
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn to_origin(&self) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
use {
|
||||
crate::{
|
||||
rect::{Rect, Region},
|
||||
utils::{
|
||||
array,
|
||||
ptr_ext::{MutPtrExt, PtrExt},
|
||||
},
|
||||
},
|
||||
crate::{Rect, Region},
|
||||
jay_algorithms::rect::{
|
||||
RectRaw, Tag,
|
||||
region::{
|
||||
|
|
@ -15,6 +9,7 @@ use {
|
|||
},
|
||||
smallvec::SmallVec,
|
||||
std::{
|
||||
array,
|
||||
borrow::Cow,
|
||||
cell::UnsafeCell,
|
||||
fmt::{Debug, Formatter},
|
||||
|
|
@ -176,7 +171,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), expect(dead_code))]
|
||||
pub fn extents(&self) -> Rect {
|
||||
self.extents
|
||||
}
|
||||
|
|
@ -274,7 +268,6 @@ impl RegionBuilder {
|
|||
self.base.clone()
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn clear(&mut self) {
|
||||
self.pending.clear();
|
||||
self.base = Region::empty();
|
||||
|
|
@ -321,26 +314,26 @@ impl DamageQueue {
|
|||
}
|
||||
|
||||
pub fn damage(&self, rects: &[Rect]) {
|
||||
let datas = unsafe { self.datas.get().deref_mut() };
|
||||
let datas = unsafe { &mut *self.datas.get() };
|
||||
for data in datas {
|
||||
data.extend(rects);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
let data = unsafe { &mut self.datas.get().deref_mut()[self.this] };
|
||||
let data = unsafe { &mut (&mut *self.datas.get())[self.this] };
|
||||
data.clear();
|
||||
}
|
||||
|
||||
pub fn clear_all(&self) {
|
||||
let datas = unsafe { self.datas.get().deref_mut() };
|
||||
let datas = unsafe { &mut *self.datas.get() };
|
||||
for data in datas {
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Region {
|
||||
let data = unsafe { &self.datas.get().deref()[self.this] };
|
||||
let data = unsafe { &(&*self.datas.get())[self.this] };
|
||||
Region::from_rects2(data)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::rect::{Rect, Region},
|
||||
crate::{Rect, Region},
|
||||
jay_algorithms::rect::{NoTag, RectRaw},
|
||||
};
|
||||
|
||||
8
crates/gfx-types/Cargo.toml
Normal file
8
crates/gfx-types/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "jay-gfx-types"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
uapi = "0.2.13"
|
||||
38
crates/gfx-types/src/lib.rs
Normal file
38
crates/gfx-types/src/lib.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use {
|
||||
std::{cell::Cell, error::Error, rc::Rc},
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
|
||||
pub enum AlphaMode {
|
||||
#[default]
|
||||
PremultipliedElectrical,
|
||||
PremultipliedOptical,
|
||||
Straight,
|
||||
}
|
||||
|
||||
pub trait ShmMemory {
|
||||
fn len(&self) -> usize;
|
||||
fn safe_access(&self) -> ShmMemoryBacking;
|
||||
fn access(&self, f: &mut dyn FnMut(&[Cell<u8>])) -> Result<(), Box<dyn Error + Sync + Send>>;
|
||||
}
|
||||
|
||||
pub enum ShmMemoryBacking {
|
||||
Ptr(*const [Cell<u8>]),
|
||||
Fd(Rc<OwnedFd>, usize),
|
||||
}
|
||||
|
||||
impl ShmMemory for Vec<Cell<u8>> {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn safe_access(&self) -> ShmMemoryBacking {
|
||||
ShmMemoryBacking::Ptr(&**self)
|
||||
}
|
||||
|
||||
fn access(&self, f: &mut dyn FnMut(&[Cell<u8>])) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
f(self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue