mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
519 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
604fcdb1db | ||
|
|
879243e370 | ||
|
|
989cffe70d | ||
|
|
3e08e3be4a | ||
|
|
91f4890ec2 | ||
|
|
74ce6c22a5 | ||
|
|
0b58bddf13 | ||
|
|
3d36ab9211 | ||
|
|
d786e07899 | ||
|
|
6d63871f05 | ||
|
|
19c5d22beb | ||
|
|
06275103f2 | ||
|
|
03e7966650 | ||
|
|
5529aae3e6 | ||
|
|
6e1c8748ff | ||
|
|
d8fb7adcf0 | ||
|
|
c2d9ae2142 | ||
|
|
6978509f64 | ||
|
|
2252854297 | ||
|
|
dde07b6840 | ||
|
|
406aa5f7f5 | ||
|
|
2ec4012559 | ||
|
|
d039ad8da3 | ||
|
|
3f0d338643 | ||
|
|
60d72724cd | ||
|
|
7cb3393e75 | ||
|
|
26c1476827 | ||
|
|
138210f01c | ||
|
|
845a7a581d | ||
|
|
108d94f798 | ||
|
|
aaf82ee332 | ||
|
|
d1c88e9497 | ||
|
|
3e88a79e6f | ||
|
|
b2d09cdee9 | ||
|
|
35eba5f2fe | ||
|
|
a91f96b391 | ||
|
|
6fee3623e4 | ||
|
|
7f6d66ea62 | ||
|
|
54374b6fe6 | ||
|
|
dd7f543189 | ||
|
|
d7ae9a866b | ||
|
|
462046ffdc | ||
|
|
bd566225ea | ||
|
|
b62c6878e1 | ||
|
|
fd069ad4f2 | ||
|
|
5e5842cb1a | ||
|
|
cdd2c7e006 | ||
|
|
905465b0fa | ||
|
|
102a6bd415 | ||
|
|
06aacb2a6f | ||
|
|
0166fd9eb7 | ||
|
|
423afc3fc9 | ||
|
|
122310a2de | ||
|
|
b799ffc6ae | ||
|
|
e95117b700 | ||
|
|
1a18e47efa | ||
|
|
bbd9a49bdf | ||
|
|
7bf5ff4c02 | ||
|
|
b0c886ec77 | ||
|
|
7431d840d0 | ||
|
|
bb1f8673b3 | ||
|
|
ad1b2f2819 | ||
|
|
812675ba34 | ||
|
|
7392b3313a | ||
|
|
07e92fb868 | ||
|
|
12316417b0 | ||
|
|
dd3c63f5e6 | ||
|
|
c8b7600adc | ||
|
|
51a78cb0ed | ||
| 1beb25a1c8 | |||
|
|
2f2c0dfcc6 | ||
|
|
47a90d6f1a | ||
|
|
db5e9ca04c | ||
|
|
efb17980a8 | ||
|
|
be5e266211 | ||
|
|
80c7e0f772 | ||
|
|
ccec4116b3 | ||
|
|
d2007d7dc1 | ||
|
|
a4eb2cff46 | ||
|
|
eff620770c | ||
|
|
f5dc6416f0 | ||
|
|
c14aa1d0b8 | ||
|
|
c39b3ce7a3 | ||
|
|
f4327f52cf | ||
|
|
6aa654b728 | ||
|
|
31b78a4f3a | ||
|
|
58c3680d96 | ||
|
|
48bd1831fe | ||
|
|
8c7041c4e8 | ||
|
|
aecb867098 | ||
|
|
bf40f396bf | ||
|
|
2498036e67 | ||
|
|
e76f8ac2b3 | ||
|
|
6d8bb66f98 | ||
|
|
f5e7caf599 | ||
|
|
98af337175 | ||
|
|
0c272a3842 | ||
|
|
071773cb27 | ||
|
|
ae85c31176 | ||
|
|
fa1feb447f | ||
|
|
a8144088df | ||
|
|
3a51a5c623 | ||
|
|
56d95c2ecb | ||
|
|
ec422ac389 | ||
|
|
7a1161438c | ||
|
|
4efec11721 | ||
|
|
8d1c6e42ac | ||
|
|
b1a9dab03e | ||
|
|
dd3d9be41e | ||
|
|
c8d94000a6 | ||
|
|
0ee0452af0 | ||
|
|
f5a0992686 | ||
|
|
7b6eec530c | ||
|
|
b482e9089b | ||
|
|
dc258b2237 | ||
|
|
4470683591 | ||
|
|
8430a1922d | ||
|
|
f024d1b8c8 | ||
|
|
e64de4d55f | ||
|
|
f3524de980 | ||
|
|
a5706e2fb9 | ||
|
|
1df2274f6c | ||
|
|
30c6efedf1 | ||
|
|
2ea0e386c4 | ||
|
|
a30c102163 | ||
|
|
bfcb4211f6 | ||
|
|
f10dd1da1c | ||
|
|
97f6946c8d | ||
|
|
74217a4d93 | ||
|
|
3665b53e29 | ||
|
|
9b97e2607d | ||
|
|
d421538b4a | ||
|
|
c6133f9912 | ||
|
|
6204fc3278 | ||
|
|
51d051497d | ||
|
|
8713ac72fb | ||
|
|
95b2771bfd | ||
|
|
da820070f4 | ||
|
|
b066fd6b5a | ||
|
|
8fb4e4dabb | ||
|
|
bb50c7a5a4 | ||
|
|
221b37355f | ||
|
|
37992cf3b8 | ||
|
|
6c78225160 | ||
|
|
83a5bdf5d5 | ||
|
|
afe427d149 | ||
|
|
a08acfcee0 | ||
|
|
af43d3b9e7 | ||
|
|
aaeffe9769 | ||
|
|
fae4c5097d | ||
|
|
170f7e0706 | ||
|
|
2d5492c737 | ||
|
|
536100488f | ||
|
|
62c86fb975 | ||
|
|
c2327248f8 | ||
|
|
c9f0dbc159 | ||
|
|
f04ef79f61 | ||
|
|
13a62a23a2 | ||
|
|
af34aaad53 | ||
|
|
2420bfef0b | ||
|
|
70add22e74 | ||
|
|
f36f856cdb | ||
|
|
aef4de2ced | ||
|
|
e57dd9c5ef | ||
|
|
d4e4c9f64b | ||
|
|
22db307e4c | ||
|
|
156d47c866 | ||
|
|
80f33cd350 | ||
|
|
7dd8fdf76c | ||
|
|
648aee65ad | ||
|
|
86976870bd | ||
|
|
bd8454d3bc | ||
|
|
e9450a9947 | ||
|
|
78aaaaf7b6 | ||
|
|
b9d3ee9a2c | ||
|
|
7bf669fb5c | ||
|
|
8dab5f838d | ||
|
|
3ad4374a54 | ||
|
|
ed2406621a | ||
|
|
f8c639f19a | ||
|
|
5fd43add1c | ||
|
|
4277d8cfdc | ||
|
|
867960d6f4 | ||
|
|
d7527778bb | ||
|
|
5dc73937ff | ||
|
|
7161bcfabc | ||
|
|
1e7baefe96 | ||
|
|
9c9bf2efee | ||
|
|
0bf0c55ad2 | ||
|
|
c450991c4b | ||
|
|
792bee9657 | ||
|
|
5563d23b81 | ||
|
|
709fc8fd8e | ||
|
|
9c51424f8d | ||
|
|
84fc6aaf5a | ||
|
|
582f487b22 | ||
|
|
5f65b1194c | ||
|
|
fa6cd856e3 | ||
|
|
95c85af87c | ||
|
|
dcf38e3ea9 | ||
|
|
ab4ed32c06 | ||
|
|
6d4737a7f6 | ||
|
|
0ab3c1d060 | ||
|
|
10b8880fc7 | ||
|
|
50537e2e6f | ||
|
|
e11012a024 | ||
|
|
7d076d0bc9 | ||
|
|
156201fe71 | ||
|
|
d8ad4809fc | ||
|
|
420b60f203 | ||
|
|
9dbf5b9f6b | ||
|
|
99da6ccc87 | ||
|
|
db2c907f93 | ||
|
|
221bc5f6aa | ||
|
|
128cd07e91 | ||
|
|
ba7ac3efe5 | ||
|
|
954dba3968 | ||
|
|
50edd3a42d | ||
|
|
31f9d6bb97 | ||
|
|
94cb8e2bc7 | ||
|
|
ca1f9f86e6 | ||
|
|
08c74f36a9 | ||
|
|
5175b6e94e | ||
|
|
e752e3ec06 | ||
|
|
a63e21d94c | ||
|
|
3c76b93272 | ||
|
|
3505079823 | ||
|
|
a9542b9565 | ||
|
|
602a00ec1f | ||
|
|
66dfb7f49b | ||
|
|
b13fe9b3a1 | ||
|
|
35ff09a754 | ||
|
|
90b5f0dde5 | ||
|
|
e83b06e732 | ||
|
|
c9d6339b60 | ||
|
|
1380a48b4d | ||
|
|
dc7dba8b1f | ||
|
|
edd8df76d8 | ||
|
|
16f607f008 | ||
|
|
fef4f3637a | ||
|
|
d305934ebe | ||
|
|
714a0264a6 | ||
|
|
a64e1a58b1 | ||
|
|
83c5b15194 | ||
|
|
a818251aec | ||
|
|
0d056a0315 | ||
|
|
639ca05d35 | ||
|
|
c1eb053f5e | ||
|
|
82223e451a | ||
|
|
211eb9d60e | ||
|
|
7d1f535e49 | ||
|
|
9b55737cf5 | ||
|
|
fa97f7f1f0 | ||
|
|
1ee3ed4310 | ||
|
|
1c2cb4c802 | ||
|
|
4f6dd01e5a | ||
|
|
980ac9e4c8 | ||
|
|
b25f98d583 | ||
|
|
f95270bb5e | ||
|
|
c3224d4160 | ||
|
|
e3596abc9a | ||
|
|
9ab87167b5 | ||
|
|
8f56f7ca43 | ||
|
|
b03b05d2b3 | ||
|
|
bcf8e467db | ||
|
|
061aa1bd15 | ||
|
|
6bb8bb1cb7 | ||
|
|
82f9cd5310 | ||
|
|
248e837cb3 | ||
|
|
c0881bdc01 | ||
|
|
08e14deeca | ||
|
|
855b3fd607 | ||
|
|
c24efad6df | ||
|
|
4e4155ccbe | ||
|
|
6712e774d4 | ||
|
|
dadcbf65e6 | ||
|
|
eb85831284 | ||
|
|
a231bf7f62 | ||
|
|
4a67628cb0 | ||
|
|
62ecec6d53 | ||
|
|
89000b7df0 | ||
|
|
d5d650f9f6 | ||
|
|
7963ba6a0d | ||
|
|
5eed5d622d | ||
|
|
38923826c3 | ||
|
|
fa4d8bbad7 | ||
|
|
6f6268988b | ||
|
|
b908d865b1 | ||
|
|
9fdffba170 | ||
|
|
cfcf06b8b0 | ||
|
|
24232e8e98 | ||
|
|
b4ce0d8b39 | ||
|
|
7cf8e80ffe | ||
|
|
1c604207c6 | ||
|
|
428279a319 | ||
|
|
90530d43fe | ||
|
|
be555a9a99 | ||
|
|
c6de47d415 | ||
|
|
bd3724aa26 | ||
|
|
648c64b7e4 | ||
|
|
41e2331843 | ||
|
|
776f2c4e4d | ||
|
|
b97106ddcb | ||
|
|
2b4f30dc1d | ||
|
|
546c5d000d | ||
|
|
71943b3b1e | ||
|
|
a7ebe7c026 | ||
|
|
c7acfe906b | ||
|
|
9649fbe443 | ||
|
|
631e5be0d7 | ||
|
|
be3d2b74cf | ||
|
|
c6dd5e3c2e | ||
|
|
2424b1ecdd | ||
|
|
e21899037a | ||
|
|
c0d4d7217b | ||
|
|
3e651b4642 | ||
|
|
9aca985865 | ||
|
|
b2c3c371fc | ||
|
|
0d6cc471e9 | ||
|
|
24597bb971 | ||
|
|
2ff95e5c97 | ||
|
|
f233d25e86 | ||
|
|
0b720ae5ea | ||
|
|
85e2b662f1 | ||
|
|
2c3053370c | ||
|
|
e9a6b3b85d | ||
|
|
ca29f43a54 | ||
|
|
8e36040e88 | ||
|
|
c3acef0dc0 | ||
|
|
f440c60128 | ||
|
|
0108506c77 | ||
|
|
66ddd62e42 | ||
|
|
b2bb111f03 | ||
|
|
1dd05437bf | ||
|
|
55f15d1abd | ||
|
|
70d3635985 | ||
|
|
014023c14f | ||
|
|
c0945b6613 | ||
|
|
4c4d74a564 | ||
|
|
4ec1defb3e | ||
|
|
baeecc8dbd | ||
|
|
9e71c88467 | ||
|
|
63fabecee2 | ||
|
|
3f314bc183 | ||
|
|
38fc4f2976 | ||
|
|
81fa6c4b96 | ||
|
|
cda6fdffac | ||
|
|
2c098a3e45 | ||
|
|
1f13bc72fe | ||
|
|
0d728f96b7 | ||
|
|
d6b47c3ab0 | ||
|
|
8bb6935374 | ||
|
|
c5d8f6d187 | ||
|
|
3fdbfb0be8 | ||
|
|
ea93dd5cc3 | ||
|
|
3ca4bc8c09 | ||
|
|
d835fa813f | ||
|
|
ebab992b44 | ||
|
|
c1ce983826 | ||
|
|
1edd5e224f | ||
|
|
0f255b46fc | ||
|
|
3df1528a8f | ||
|
|
1520be3c5c | ||
|
|
3bbfae73ae | ||
|
|
9351c78d70 | ||
|
|
cf43a447cb | ||
|
|
7717c92ed0 | ||
|
|
4c74a8843a | ||
|
|
e8e76dc295 | ||
|
|
6006023a37 | ||
|
|
e51ce333bc | ||
|
|
0ba1982488 | ||
|
|
da8f7a07ba | ||
|
|
0d467ef9aa | ||
|
|
527b77b445 | ||
|
|
c87ab6465d | ||
|
|
47fb00f66d | ||
|
|
ba0cc8eb05 | ||
|
|
7952658367 | ||
|
|
3b3ed21e61 | ||
|
|
402a862413 | ||
|
|
1e949402b0 | ||
|
|
785e340f01 | ||
|
|
186bdc8da4 | ||
|
|
514c4b4cce | ||
|
|
8d8d5f5e94 | ||
|
|
009515161b | ||
|
|
f1b8937345 | ||
|
|
b9f0b9c766 | ||
|
|
831e7fc7ee | ||
|
|
79e063035c | ||
|
|
6202580b7b | ||
|
|
502eb38d80 | ||
|
|
fbafd8ed94 | ||
|
|
9904f160af | ||
|
|
b8418b7b91 | ||
|
|
dd8f4913a4 | ||
|
|
6ada67da9b | ||
|
|
c9fe96102d | ||
|
|
95d25d833f | ||
|
|
7ce868bcf6 | ||
|
|
ab118042ea | ||
|
|
3da6fac1f2 | ||
|
|
d55c175777 | ||
|
|
a8d1e5273a | ||
|
|
56d69320c7 | ||
|
|
c752270be7 | ||
|
|
7debaced03 | ||
|
|
bf0cac12a3 | ||
|
|
04525e6f82 | ||
|
|
96ad414ec9 | ||
|
|
9f7ab85718 | ||
|
|
1a7981f7c9 | ||
|
|
234d31f138 | ||
|
|
beb9a9ad0a | ||
|
|
0db4df4c8e | ||
|
|
0d6284eb62 | ||
|
|
d7223eae02 | ||
|
|
3187479c07 | ||
|
|
fa2abbeefb | ||
|
|
a5aae69b2a | ||
|
|
52afedadea | ||
|
|
52dce29e06 | ||
|
|
5432108846 | ||
|
|
5f3b99bbed | ||
|
|
1e03719361 | ||
|
|
0bf642d246 | ||
|
|
d2a5dbe104 | ||
|
|
43554c1966 | ||
|
|
cf93d31736 | ||
|
|
bfcaa4bc44 | ||
|
|
eebaca8dbf | ||
|
|
62cc96b3a4 | ||
|
|
098cb9b7a3 | ||
|
|
8582b45c9e | ||
|
|
3d2f09bace | ||
|
|
b4f077a596 | ||
|
|
3048fb3fc6 | ||
|
|
5df2b34d2b | ||
|
|
ccd4703207 | ||
|
|
a0450d219f | ||
|
|
270e6f4ebb | ||
|
|
e88988e364 | ||
|
|
310a5eb61c | ||
|
|
08495d2596 | ||
|
|
3103ea3af9 | ||
|
|
ee21deb458 | ||
|
|
baaec88e2f | ||
|
|
4da4269d8f | ||
|
|
5c98d1a04a | ||
|
|
a1298580cc | ||
|
|
515275ee72 | ||
|
|
23202e192c | ||
|
|
2463a4723e | ||
|
|
291df10fe5 | ||
|
|
235c8e922a | ||
|
|
70c99460ca | ||
|
|
4f1104654f | ||
|
|
14e1987f50 | ||
|
|
3e1358fec9 | ||
|
|
147c5c37e3 | ||
|
|
78dfa4f06d | ||
|
|
c52e01e85f | ||
|
|
6c8eabcecd | ||
|
|
2c64f36e88 | ||
|
|
e6dbe4580e | ||
|
|
adf9d8b0be | ||
|
|
e209fe2d05 | ||
|
|
3cae2a2c01 | ||
|
|
6214144735 | ||
|
|
71cc47b859 | ||
|
|
08e779bd85 | ||
|
|
0a388a14f1 | ||
|
|
20997df416 | ||
|
|
df4a1d94e2 | ||
|
|
1c7e1bcc28 | ||
|
|
14446216f4 | ||
|
|
1133bc15ce | ||
|
|
66d96d244c | ||
|
|
823a64bf7d | ||
|
|
4b4ca11f6f | ||
|
|
8730ca9661 | ||
|
|
775817e278 | ||
|
|
738bbf01ee | ||
|
|
5f88635118 | ||
|
|
9e9636f675 | ||
|
|
850dd7a792 | ||
|
|
c7035da5e2 | ||
|
|
48f0902a36 | ||
|
|
edb867bc05 | ||
|
|
5552de65f8 | ||
|
|
3067e45c2e | ||
|
|
1ad42bea99 | ||
|
|
d2374b3e4e | ||
|
|
19ffbfe356 | ||
|
|
a1635fdb76 | ||
|
|
4481c6b243 | ||
|
|
6261bd9684 | ||
|
|
d400b4587a | ||
|
|
42df9414fb | ||
|
|
7e13dfdd4d | ||
|
|
ceb4fcedca | ||
|
|
f9199bb6d4 | ||
|
|
5083efe18b | ||
|
|
eb5312022a | ||
|
|
aa1163e640 | ||
|
|
de574ac098 | ||
|
|
42673a2821 | ||
|
|
cd2cf1bafb | ||
|
|
f16a3c1180 | ||
|
|
015bb8512e | ||
|
|
7550e483ae | ||
|
|
2a8a23c467 | ||
|
|
179ed7c296 | ||
|
|
22adc65586 | ||
|
|
e17916d413 | ||
|
|
d3b7e040af | ||
|
|
5ecbd23c1d | ||
|
|
b10516e1e8 |
323 changed files with 13577 additions and 3702 deletions
|
|
@ -20,8 +20,13 @@ packages:
|
|||
- xwayland-dev
|
||||
- libseat-dev
|
||||
- hwdata-dev
|
||||
# for docs
|
||||
- go
|
||||
- zip
|
||||
sources:
|
||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
artifacts:
|
||||
- public.zip
|
||||
tasks:
|
||||
- setup: |
|
||||
cd wlroots
|
||||
|
|
@ -37,3 +42,16 @@ tasks:
|
|||
- tinywl: |
|
||||
cd wlroots/tinywl
|
||||
make
|
||||
- docs: |
|
||||
go install 'codeberg.org/emersion/gyosu@latest'
|
||||
include_dir="$(echo /usr/local/include/wlroots-*)"
|
||||
~/go/bin/gyosu \
|
||||
-DWLR_USE_UNSTABLE \
|
||||
$(pkg-config --cflags-only-I $(basename "$include_dir")) \
|
||||
-Iwlroots/build/protocol/ \
|
||||
-fexported-symbols='wlr_*' -fexported-symbols='WLR_*' \
|
||||
-ffile-prefix-map="$include_dir/"= \
|
||||
-fsite-name=wlroots \
|
||||
-o public \
|
||||
"$include_dir/wlr/"
|
||||
zip -r ~/public.zip public/
|
||||
|
|
|
|||
|
|
@ -41,9 +41,10 @@ tasks:
|
|||
cd wlroots/build-gcc/tinywl
|
||||
sudo modprobe vkms
|
||||
udevadm settle
|
||||
card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
|
||||
export WLR_BACKENDS=drm
|
||||
export WLR_RENDERER=pixman
|
||||
export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
|
||||
export WLR_DRM_DEVICES="$card"
|
||||
export UBSAN_OPTIONS=halt_on_error=1
|
||||
sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
|
||||
sudo chmod ugo+rw "$card"
|
||||
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
|
||||
|
|
|
|||
|
|
@ -20,19 +20,18 @@ packages:
|
|||
- x11/xcb-util-errors
|
||||
- x11/xcb-util-renderutil
|
||||
- x11/xcb-util-wm
|
||||
- x11-servers/xwayland-devel
|
||||
- x11-servers/xwayland
|
||||
- sysutils/libdisplay-info
|
||||
- sysutils/seatd
|
||||
- gmake
|
||||
- hwdata
|
||||
sources:
|
||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
tasks:
|
||||
- wlroots: |
|
||||
cd wlroots
|
||||
meson setup build --fatal-meson-warnings -Dauto_features=enabled
|
||||
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
|
||||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
- tinywl: |
|
||||
cd wlroots/tinywl
|
||||
gmake
|
||||
make
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
/subprojects/
|
||||
/subprojects/*
|
||||
!/subprojects/*.wrap
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
|
||||
alpine:
|
||||
extends: .dalligi
|
||||
pages: true
|
||||
archlinux:
|
||||
extends: .dalligi
|
||||
freebsd:
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -1 +1,2 @@
|
|||
Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
|
||||
Kirill Primak <vyivel@eclair.cafe> <vyivel@posteo.net>
|
||||
|
|
|
|||
|
|
@ -213,6 +213,27 @@ reinitialized to be used again.
|
|||
it, and free the memory. Such functions should always be able to accept a NULL
|
||||
pointer.
|
||||
|
||||
If the object has signals, the destructor function must assert that their
|
||||
listener lists are empty.
|
||||
|
||||
```c
|
||||
void wlr_thing_init(struct wlr_thing *thing) {
|
||||
*thing = (struct wlr_thing){
|
||||
// ...
|
||||
};
|
||||
|
||||
wl_signal_init(&thing->events.destroy);
|
||||
wl_signal_init(&thing->events.foo);
|
||||
}
|
||||
|
||||
void wlr_thing_finish(struct wlr_thing *thing) {
|
||||
wl_signal_emit_mutable(&thing->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&thing->events.destroy.listener_list));
|
||||
assert(wl_list_empty(&thing->events.foo.listener_list));
|
||||
}
|
||||
```
|
||||
|
||||
### Error Codes
|
||||
|
||||
For functions not returning a value, they should return a (stdbool.h) bool to
|
||||
|
|
@ -237,6 +258,13 @@ used and `#undef` them after.
|
|||
* Document the contents and container of a `struct wl_list` with a
|
||||
`// content.link` and `// container.list` comment.
|
||||
|
||||
### Private fields
|
||||
|
||||
Wrap private fields of public structures with `struct { … } WLR_PRIVATE`. This
|
||||
ensures that compositor authors don't use them by accident. Within wlroots
|
||||
`WLR_PRIVATE` is expanded to nothing, so private fields are accessed in the same
|
||||
way as public ones.
|
||||
|
||||
### Safety
|
||||
|
||||
* Avoid string manipulation functions which don't take the size of the
|
||||
|
|
@ -325,12 +353,14 @@ struct wlr_compositor {
|
|||
struct wl_global *global;
|
||||
…
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal new_surface;
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -12,9 +11,6 @@
|
|||
#include <wlr/config.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/multi.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "util/env.h"
|
||||
#include "util/time.h"
|
||||
|
|
@ -50,6 +46,10 @@ void wlr_backend_init(struct wlr_backend *backend,
|
|||
|
||||
void wlr_backend_finish(struct wlr_backend *backend) {
|
||||
wl_signal_emit_mutable(&backend->events.destroy, backend);
|
||||
|
||||
assert(wl_list_empty(&backend->events.destroy.listener_list));
|
||||
assert(wl_list_empty(&backend->events.new_input.listener_list));
|
||||
assert(wl_list_empty(&backend->events.new_output.listener_list));
|
||||
}
|
||||
|
||||
bool wlr_backend_start(struct wlr_backend *backend) {
|
||||
|
|
@ -121,14 +121,6 @@ int wlr_backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
return backend->impl->get_drm_fd(backend);
|
||||
}
|
||||
|
||||
uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
|
||||
if (!backend->impl->get_buffer_caps) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backend->impl->get_buffer_caps(backend);
|
||||
}
|
||||
|
||||
static size_t parse_outputs_env(const char *name) {
|
||||
const char *outputs_str = getenv(name);
|
||||
if (outputs_str == NULL) {
|
||||
|
|
@ -493,5 +485,10 @@ bool wlr_backend_commit(struct wlr_backend *backend,
|
|||
output_apply_commit(state->output, &state->base);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < states_len; i++) {
|
||||
const struct wlr_backend_output_state *state = &states[i];
|
||||
output_send_commit_event(state->output, &state->base);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#include <drm_fourcc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/color.h"
|
||||
|
||||
static char *atomic_commit_flags_str(uint32_t flags) {
|
||||
const char *const l[] = {
|
||||
|
|
@ -152,18 +155,20 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
|
|||
|
||||
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
|
||||
int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
|
||||
if (!pixman_region32_not_empty(damage)) {
|
||||
*blob_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
pixman_region32_t clipped;
|
||||
pixman_region32_init(&clipped);
|
||||
pixman_region32_intersect_rect(&clipped, damage, 0, 0, width, height);
|
||||
|
||||
int rects_len;
|
||||
const pixman_box32_t *rects = pixman_region32_rectangles(&clipped, &rects_len);
|
||||
int ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
|
||||
|
||||
int ret;
|
||||
if (rects_len > 0) {
|
||||
ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
|
||||
} else {
|
||||
ret = 0;
|
||||
*blob_id = 0;
|
||||
}
|
||||
pixman_region32_fini(&clipped);
|
||||
if (ret != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
|
||||
|
|
@ -173,6 +178,85 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return 2;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
abort(); // unsupported
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
abort(); // unsupported
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static uint16_t convert_cta861_color_coord(double v) {
|
||||
if (v < 0) {
|
||||
v = 0;
|
||||
}
|
||||
if (v > 1) {
|
||||
v = 1;
|
||||
}
|
||||
return (uint16_t)round(v * 50000);
|
||||
}
|
||||
|
||||
static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm,
|
||||
const struct wlr_output_image_description *img_desc, uint32_t *blob_id) {
|
||||
if (img_desc == NULL) {
|
||||
*blob_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct hdr_output_metadata metadata = {
|
||||
.metadata_type = 0,
|
||||
.hdmi_metadata_type1 = {
|
||||
.eotf = convert_cta861_eotf(img_desc->transfer_function),
|
||||
.metadata_type = 0,
|
||||
.display_primaries = {
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.y),
|
||||
},
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.y),
|
||||
},
|
||||
{
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.y),
|
||||
},
|
||||
},
|
||||
.white_point = {
|
||||
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.x),
|
||||
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.y),
|
||||
},
|
||||
.max_display_mastering_luminance = img_desc->mastering_luminance.max,
|
||||
.min_display_mastering_luminance = img_desc->mastering_luminance.min * 0.0001,
|
||||
.max_cll = img_desc->max_cll,
|
||||
.max_fall = img_desc->max_fall,
|
||||
},
|
||||
};
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t convert_primaries_to_colorspace(uint32_t primaries) {
|
||||
switch (primaries) {
|
||||
case 0:
|
||||
return 0; // Default
|
||||
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
|
||||
return 9; // BT2020_RGB
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static uint64_t max_bpc_for_format(uint32_t format) {
|
||||
switch (format) {
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
|
|
@ -247,19 +331,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
}
|
||||
|
||||
uint32_t gamma_lut = crtc->gamma_lut;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
||||
// Fallback to legacy gamma interface when gamma properties are not
|
||||
// available (can happen on older Intel GPUs that support gamma but not
|
||||
// degamma).
|
||||
if (crtc->props.gamma_lut == 0) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc,
|
||||
state->base->gamma_lut_size,
|
||||
state->base->gamma_lut)) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
|
||||
state->base->gamma_lut, &gamma_lut)) {
|
||||
if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -272,6 +362,15 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips);
|
||||
}
|
||||
|
||||
int in_fence_fd = -1;
|
||||
if (state->wait_timeline != NULL) {
|
||||
in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->wait_timeline,
|
||||
state->wait_point);
|
||||
if (in_fence_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool prev_vrr_enabled =
|
||||
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
|
||||
bool vrr_enabled = prev_vrr_enabled;
|
||||
|
|
@ -282,10 +381,25 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
vrr_enabled = state->base->adaptive_sync_enabled;
|
||||
}
|
||||
|
||||
uint32_t colorspace = conn->colorspace;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
colorspace = convert_primaries_to_colorspace(
|
||||
state->base->image_description ? state->base->image_description->primaries : 0);
|
||||
}
|
||||
|
||||
uint32_t hdr_output_metadata = conn->hdr_output_metadata;
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
!create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state->mode_id = mode_id;
|
||||
state->gamma_lut = gamma_lut;
|
||||
state->fb_damage_clips = fb_damage_clips;
|
||||
state->primary_in_fence_fd = in_fence_fd;
|
||||
state->vrr_enabled = vrr_enabled;
|
||||
state->colorspace = colorspace;
|
||||
state->hdr_output_metadata = hdr_output_metadata;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -300,11 +414,23 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
crtc->own_mode_id = true;
|
||||
commit_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
conn->output.adaptive_sync_status = state->vrr_enabled ?
|
||||
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
||||
|
||||
destroy_blob(drm, state->fb_damage_clips);
|
||||
if (state->primary_in_fence_fd >= 0) {
|
||||
close(state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->out_fence_fd >= 0) {
|
||||
// TODO: error handling
|
||||
wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
|
||||
state->base->signal_point, state->out_fence_fd);
|
||||
close(state->out_fence_fd);
|
||||
}
|
||||
|
||||
conn->colorspace = state->colorspace;
|
||||
}
|
||||
|
||||
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
|
||||
|
|
@ -314,8 +440,15 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
|||
|
||||
rollback_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
destroy_blob(drm, state->fb_damage_clips);
|
||||
if (state->primary_in_fence_fd >= 0) {
|
||||
close(state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->out_fence_fd >= 0) {
|
||||
close(state->out_fence_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
||||
|
|
@ -327,7 +460,8 @@ static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
|||
|
||||
static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id,
|
||||
int32_t x, int32_t y) {
|
||||
const struct wlr_box *dst_box,
|
||||
const struct wlr_fbox *src_box) {
|
||||
uint32_t id = plane->id;
|
||||
const struct wlr_drm_plane_props *props = &plane->props;
|
||||
|
||||
|
|
@ -337,28 +471,50 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t width = fb->wlr_buf->width;
|
||||
uint32_t height = fb->wlr_buf->height;
|
||||
|
||||
// The src_* properties are in 16.16 fixed point
|
||||
atomic_add(atom, id, props->src_x, 0);
|
||||
atomic_add(atom, id, props->src_y, 0);
|
||||
atomic_add(atom, id, props->src_w, (uint64_t)width << 16);
|
||||
atomic_add(atom, id, props->src_h, (uint64_t)height << 16);
|
||||
atomic_add(atom, id, props->crtc_w, width);
|
||||
atomic_add(atom, id, props->crtc_h, height);
|
||||
atomic_add(atom, id, props->src_x, src_box->x * (1 << 16));
|
||||
atomic_add(atom, id, props->src_y, src_box->y * (1 << 16));
|
||||
atomic_add(atom, id, props->src_w, src_box->width * (1 << 16));
|
||||
atomic_add(atom, id, props->src_h, src_box->height * (1 << 16));
|
||||
atomic_add(atom, id, props->fb_id, fb->id);
|
||||
atomic_add(atom, id, props->crtc_id, crtc_id);
|
||||
atomic_add(atom, id, props->crtc_x, (uint64_t)x);
|
||||
atomic_add(atom, id, props->crtc_y, (uint64_t)y);
|
||||
atomic_add(atom, id, props->crtc_x, dst_box->x);
|
||||
atomic_add(atom, id, props->crtc_y, dst_box->y);
|
||||
atomic_add(atom, id, props->crtc_w, dst_box->width);
|
||||
atomic_add(atom, id, props->crtc_h, dst_box->height);
|
||||
}
|
||||
|
||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane* plane) {
|
||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
|
||||
return plane->props.hotspot_x && plane->props.hotspot_y;
|
||||
}
|
||||
|
||||
static void set_plane_in_fence_fd(struct atomic *atom,
|
||||
struct wlr_drm_plane *plane, int sync_file_fd) {
|
||||
if (!plane->props.in_fence_fd) {
|
||||
wlr_log(WLR_ERROR, "Plane %"PRIu32 " is missing the IN_FENCE_FD property",
|
||||
plane->id);
|
||||
atom->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
|
||||
}
|
||||
|
||||
static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
|
||||
int *fd_ptr) {
|
||||
if (!crtc->props.out_fence_ptr) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
|
||||
crtc->id);
|
||||
atom->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
|
||||
}
|
||||
|
||||
static void atomic_connector_add(struct atomic *atom,
|
||||
const struct wlr_drm_connector_state *state, bool modeset) {
|
||||
struct wlr_drm_connector_state *state, bool modeset) {
|
||||
struct wlr_drm_connector *conn = state->connector;
|
||||
struct wlr_drm_backend *drm = conn->backend;
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
|
@ -376,6 +532,12 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
|
||||
}
|
||||
if (conn->props.colorspace != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
|
||||
}
|
||||
if (conn->props.hdr_output_metadata != 0) {
|
||||
atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata);
|
||||
}
|
||||
atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
|
||||
atomic_add(atom, crtc->id, crtc->props.active, active);
|
||||
if (active) {
|
||||
|
|
@ -385,16 +547,33 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (crtc->props.vrr_enabled != 0) {
|
||||
atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
|
||||
}
|
||||
|
||||
set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
|
||||
0, 0);
|
||||
&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
|
||||
if (crtc->primary->props.fb_damage_clips != 0) {
|
||||
atomic_add(atom, crtc->primary->id,
|
||||
crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
|
||||
}
|
||||
if (state->primary_in_fence_fd >= 0) {
|
||||
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
|
||||
}
|
||||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
struct wlr_fbox cursor_src = {
|
||||
.width = state->cursor_fb->wlr_buf->width,
|
||||
.height = state->cursor_fb->wlr_buf->height,
|
||||
};
|
||||
struct wlr_box cursor_dst = {
|
||||
.x = conn->cursor_x,
|
||||
.y = conn->cursor_y,
|
||||
.width = state->cursor_fb->wlr_buf->width,
|
||||
.height = state->cursor_fb->wlr_buf->height,
|
||||
};
|
||||
set_plane_props(atom, drm, crtc->cursor, state->cursor_fb,
|
||||
crtc->id, conn->cursor_x, conn->cursor_y);
|
||||
crtc->id, &cursor_dst, &cursor_src);
|
||||
if (supports_cursor_hotspots(crtc->cursor)) {
|
||||
atomic_add(atom, crtc->cursor->id,
|
||||
crtc->cursor->props.hotspot_x, conn->cursor_hotspot_x);
|
||||
|
|
@ -437,7 +616,7 @@ static bool atomic_device_commit(struct wlr_drm_backend *drm,
|
|||
if (state->modeset) {
|
||||
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
}
|
||||
if (!test_only && state->nonblock) {
|
||||
if (state->nonblock) {
|
||||
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
||||
}
|
||||
|
||||
|
|
@ -456,33 +635,6 @@ out:
|
|||
return ok;
|
||||
}
|
||||
|
||||
bool drm_atomic_reset(struct wlr_drm_backend *drm) {
|
||||
struct atomic atom;
|
||||
atomic_begin(&atom);
|
||||
|
||||
for (size_t i = 0; i < drm->num_crtcs; i++) {
|
||||
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
|
||||
atomic_add(&atom, crtc->id, crtc->props.mode_id, 0);
|
||||
atomic_add(&atom, crtc->id, crtc->props.active, 0);
|
||||
}
|
||||
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->connectors, link) {
|
||||
atomic_add(&atom, conn->id, conn->props.crtc_id, 0);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < drm->num_planes; i++) {
|
||||
plane_disable(&atom, &drm->planes[i]);
|
||||
}
|
||||
|
||||
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
bool ok = atomic_commit(&atom, drm, NULL, NULL, flags);
|
||||
atomic_finish(&atom);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
const struct wlr_drm_interface atomic_iface = {
|
||||
.commit = atomic_device_commit,
|
||||
.reset = drm_atomic_reset,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/backend/session.h>
|
||||
|
|
@ -13,6 +11,7 @@
|
|||
#include <xf86drm.h>
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "render/drm_format_set.h"
|
||||
|
||||
struct wlr_drm_backend *get_drm_backend_from_backend(
|
||||
struct wlr_backend *wlr_backend) {
|
||||
|
|
@ -53,7 +52,8 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
wl_list_remove(&drm->dev_change.link);
|
||||
wl_list_remove(&drm->dev_remove.link);
|
||||
|
||||
if (drm->parent) {
|
||||
if (drm->mgpu_renderer.wlr_rend) {
|
||||
wlr_drm_format_set_finish(&drm->mgpu_formats);
|
||||
finish_drm_renderer(&drm->mgpu_renderer);
|
||||
}
|
||||
|
||||
|
|
@ -75,10 +75,6 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
return drm->fd;
|
||||
}
|
||||
|
||||
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
|
||||
return WLR_BUFFER_CAP_DMABUF;
|
||||
}
|
||||
|
||||
static bool backend_test(struct wlr_backend *backend,
|
||||
const struct wlr_backend_output_state *states, size_t states_len) {
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
|
||||
|
|
@ -95,7 +91,6 @@ static const struct wlr_backend_impl backend_impl = {
|
|||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = backend_get_buffer_caps,
|
||||
.test = backend_test,
|
||||
.commit = backend_commit,
|
||||
};
|
||||
|
|
@ -117,11 +112,18 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
|
|||
wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused");
|
||||
|
||||
if (!session->active) {
|
||||
// Disconnect any active connectors so that the client will modeset and
|
||||
// rerender when the session is activated again.
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->connectors, link) {
|
||||
if (conn->status == DRM_MODE_CONNECTED) {
|
||||
wlr_output_destroy(&conn->output);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
scan_drm_connectors(drm, NULL);
|
||||
restore_drm_device(drm);
|
||||
}
|
||||
|
||||
static void handle_dev_change(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -165,6 +167,44 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) {
|
|||
backend_destroy(&drm->backend);
|
||||
}
|
||||
|
||||
static void sanitize_mgpu_modifiers(struct wlr_drm_format_set *set) {
|
||||
for (size_t idx = 0; idx < set->len; idx++) {
|
||||
// Implicit modifiers are not well-defined across devices, so strip
|
||||
// them from all formats in multi-gpu scenarios.
|
||||
struct wlr_drm_format *fmt = &set->formats[idx];
|
||||
wlr_drm_format_set_remove(set, fmt->format, DRM_FORMAT_MOD_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
static bool init_mgpu_renderer(struct wlr_drm_backend *drm) {
|
||||
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
|
||||
wlr_log(WLR_INFO, "Failed to initialize mgpu blit renderer"
|
||||
", falling back to scanning out from primary GPU");
|
||||
|
||||
for (uint32_t plane_idx = 0; plane_idx < drm->num_planes; plane_idx++) {
|
||||
struct wlr_drm_plane *plane = &drm->planes[plane_idx];
|
||||
sanitize_mgpu_modifiers(&plane->formats);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// We'll perform a multi-GPU copy for all submitted buffers, we need
|
||||
// to be able to texture from them
|
||||
struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
|
||||
const struct wlr_drm_format_set *texture_formats =
|
||||
wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
|
||||
if (texture_formats == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_drm_format_set_copy(&drm->mgpu_formats, texture_formats);
|
||||
sanitize_mgpu_modifiers(&drm->mgpu_formats);
|
||||
drm->backend.features.timeline = drm->backend.features.timeline &&
|
||||
drm->mgpu_renderer.wlr_rend->features.timeline;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
||||
struct wlr_device *dev, struct wlr_backend *parent) {
|
||||
assert(session && dev);
|
||||
|
|
@ -192,6 +232,8 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
|||
}
|
||||
wlr_backend_init(&drm->backend, &backend_impl);
|
||||
|
||||
drm->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF;
|
||||
|
||||
drm->session = session;
|
||||
wl_list_init(&drm->fbs);
|
||||
wl_list_init(&drm->connectors);
|
||||
|
|
@ -234,34 +276,8 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
|||
goto error_event;
|
||||
}
|
||||
|
||||
if (drm->parent) {
|
||||
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to initialize renderer");
|
||||
goto error_resources;
|
||||
}
|
||||
|
||||
// We'll perform a multi-GPU copy for all submitted buffers, we need
|
||||
// to be able to texture from them
|
||||
struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
|
||||
const struct wlr_drm_format_set *texture_formats =
|
||||
wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
|
||||
if (texture_formats == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
|
||||
goto error_mgpu_renderer;
|
||||
}
|
||||
|
||||
// Forbid implicit modifiers, because their meaning changes from one
|
||||
// GPU to another.
|
||||
for (size_t i = 0; i < texture_formats->len; i++) {
|
||||
const struct wlr_drm_format *fmt = &texture_formats->formats[i];
|
||||
for (size_t j = 0; j < fmt->len; j++) {
|
||||
uint64_t mod = fmt->modifiers[j];
|
||||
if (mod == DRM_FORMAT_MOD_INVALID) {
|
||||
continue;
|
||||
}
|
||||
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
|
||||
}
|
||||
}
|
||||
if (drm->parent && !init_mgpu_renderer(drm)) {
|
||||
goto error_mgpu_renderer;
|
||||
}
|
||||
|
||||
drm->session_destroy.notify = handle_session_destroy;
|
||||
|
|
@ -271,7 +287,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
|||
|
||||
error_mgpu_renderer:
|
||||
finish_drm_renderer(&drm->mgpu_renderer);
|
||||
error_resources:
|
||||
finish_drm_resources(drm);
|
||||
error_event:
|
||||
wl_list_remove(&drm->session_active.link);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <drm_mode.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -14,6 +13,7 @@
|
|||
#include <wayland-util.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
|
@ -24,9 +24,7 @@
|
|||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/pixel_format.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "render/color.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "util/env.h"
|
||||
#include "config.h"
|
||||
|
|
@ -40,9 +38,12 @@ static const uint32_t COMMIT_OUTPUT_STATE =
|
|||
WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_ENABLED |
|
||||
WLR_OUTPUT_STATE_GAMMA_LUT |
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
|
||||
WLR_OUTPUT_STATE_LAYERS;
|
||||
WLR_OUTPUT_STATE_LAYERS |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
|
||||
|
||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
|
||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
|
||||
|
|
@ -121,6 +122,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
|
|||
drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
|
||||
} else {
|
||||
drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
|
||||
drm->backend.features.timeline = drmGetCap(drm->fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap) == 0 && cap == 1;
|
||||
}
|
||||
|
||||
if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
|
||||
|
|
@ -170,7 +172,7 @@ static bool init_plane(struct wlr_drm_backend *drm,
|
|||
}
|
||||
|
||||
p->type = type;
|
||||
p->id = drm_plane->plane_id;
|
||||
p->id = id;
|
||||
p->props = props;
|
||||
p->initial_crtc_id = drm_plane->crtc_id;
|
||||
|
||||
|
|
@ -396,6 +398,7 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
|
|||
struct wlr_drm_plane *plane = &drm->planes[i];
|
||||
drm_plane_finish_surface(plane);
|
||||
wlr_drm_format_set_finish(&plane->formats);
|
||||
free(plane->cursor_sizes);
|
||||
}
|
||||
|
||||
free(drm->planes);
|
||||
|
|
@ -553,6 +556,7 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
|||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
||||
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
||||
crtc->primary->viewport = state->primary_viewport;
|
||||
if (crtc->cursor != NULL) {
|
||||
drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
|
||||
}
|
||||
|
|
@ -576,6 +580,16 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
|||
|
||||
conn->cursor_enabled = false;
|
||||
conn->crtc = NULL;
|
||||
|
||||
// Legacy uAPI doesn't support requesting page-flip events when
|
||||
// turning off a CRTC
|
||||
if (page_flip != NULL && conn->backend->iface == &legacy_iface) {
|
||||
drm_page_flip_pop(page_flip, crtc->id);
|
||||
conn->pending_page_flip = NULL;
|
||||
if (page_flip->connectors_len == 0) {
|
||||
drm_page_flip_destroy(page_flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -607,6 +621,7 @@ static bool drm_commit(struct wlr_drm_backend *drm,
|
|||
if (page_flip == NULL) {
|
||||
return false;
|
||||
}
|
||||
page_flip->async = (flags & DRM_MODE_PAGE_FLIP_ASYNC);
|
||||
}
|
||||
|
||||
bool ok = drm->iface->commit(drm, state, page_flip, flags, test_only);
|
||||
|
|
@ -630,6 +645,8 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
|||
.connector = conn,
|
||||
.base = base,
|
||||
.active = output_pending_enabled(&conn->output, base),
|
||||
.primary_in_fence_fd = -1,
|
||||
.out_fence_fd = -1,
|
||||
};
|
||||
|
||||
struct wlr_output_mode *mode = conn->output.current_mode;
|
||||
|
|
@ -639,7 +656,7 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
|||
|
||||
if (base->committed & WLR_OUTPUT_STATE_MODE) {
|
||||
switch (base->mode_type) {
|
||||
case WLR_OUTPUT_STATE_MODE_FIXED:;
|
||||
case WLR_OUTPUT_STATE_MODE_FIXED:
|
||||
mode = base->mode;
|
||||
break;
|
||||
case WLR_OUTPUT_STATE_MODE_CUSTOM:
|
||||
|
|
@ -666,8 +683,10 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
|||
struct wlr_drm_plane *primary = conn->crtc->primary;
|
||||
if (primary->queued_fb != NULL) {
|
||||
state->primary_fb = drm_fb_lock(primary->queued_fb);
|
||||
state->primary_viewport = primary->viewport;
|
||||
} else if (primary->current_fb != NULL) {
|
||||
state->primary_fb = drm_fb_lock(primary->current_fb);
|
||||
state->primary_viewport = primary->viewport;
|
||||
}
|
||||
|
||||
if (conn->cursor_enabled) {
|
||||
|
|
@ -687,6 +706,7 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
|||
static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
|
||||
drm_fb_clear(&state->primary_fb);
|
||||
drm_fb_clear(&state->cursor_fb);
|
||||
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
||||
}
|
||||
|
||||
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
|
||||
|
|
@ -701,8 +721,16 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
|
|||
struct wlr_drm_plane *plane = crtc->primary;
|
||||
struct wlr_buffer *source_buf = state->base->buffer;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
|
||||
uint64_t wait_point = 0;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
wait_timeline = state->base->wait_timeline;
|
||||
wait_point = state->base->wait_point;
|
||||
}
|
||||
assert(state->wait_timeline == NULL);
|
||||
|
||||
struct wlr_buffer *local_buf;
|
||||
if (drm->parent) {
|
||||
if (drm->mgpu_renderer.wlr_rend) {
|
||||
struct wlr_drm_format format = {0};
|
||||
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to pick primary plane format");
|
||||
|
|
@ -717,12 +745,23 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
|
|||
return false;
|
||||
}
|
||||
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf);
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf,
|
||||
wait_timeline, wait_point);
|
||||
if (local_buf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plane->mgpu_surf.timeline != NULL) {
|
||||
state->wait_timeline = wlr_drm_syncobj_timeline_ref(plane->mgpu_surf.timeline);
|
||||
state->wait_point = plane->mgpu_surf.point;
|
||||
}
|
||||
} else {
|
||||
local_buf = wlr_buffer_lock(source_buf);
|
||||
|
||||
if (wait_timeline != NULL) {
|
||||
state->wait_timeline = wlr_drm_syncobj_timeline_ref(wait_timeline);
|
||||
state->wait_point = wait_point;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
|
||||
|
|
@ -734,6 +773,9 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
|
|||
return false;
|
||||
}
|
||||
|
||||
output_state_get_buffer_src_box(state->base, &state->primary_viewport.src_box);
|
||||
output_state_get_buffer_dst_box(state->base, &state->primary_viewport.dst_box);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -742,7 +784,7 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
|
|||
struct wlr_drm_backend *drm = conn->backend;
|
||||
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
if (!crtc || drm->parent) {
|
||||
if (!crtc || drm->mgpu_renderer.wlr_rend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -784,13 +826,12 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
|
||||
if (output->current_mode == NULL &&
|
||||
!(state->committed & WLR_OUTPUT_STATE_MODE)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Can't enable an output without a mode");
|
||||
return false;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled &&
|
||||
output->width == 0 && output->height == 0 &&
|
||||
!(state->committed & WLR_OUTPUT_STATE_MODE)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Can't enable an output without a mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
|
||||
|
|
@ -801,7 +842,36 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
|||
return false;
|
||||
}
|
||||
|
||||
if (test_only && conn->backend->parent) {
|
||||
if ((state->committed & WLR_OUTPUT_STATE_BUFFER) && conn->backend->mgpu_renderer.wlr_rend) {
|
||||
struct wlr_dmabuf_attributes dmabuf;
|
||||
if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG, "Buffer is not a DMA-BUF");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wlr_drm_format_set_has(&conn->backend->mgpu_formats, dmabuf.format, dmabuf.modifier)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Buffer format 0x%"PRIX32" with modifier 0x%"PRIX64" cannot be "
|
||||
"imported into multi-GPU renderer",
|
||||
dmabuf.format, dmabuf.modifier);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL &&
|
||||
state->color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Only 3x1D LUT color transforms are supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
conn->backend->iface != &atomic_iface) {
|
||||
wlr_log(WLR_DEBUG, "Image descriptions are only supported by the atomic interface");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
|
||||
// If we're running as a secondary GPU, we can't perform an atomic
|
||||
// commit without blitting a buffer.
|
||||
return true;
|
||||
|
|
@ -871,7 +941,7 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (test_only && conn->backend->parent) {
|
||||
if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
|
||||
// If we're running as a secondary GPU, we can't perform an atomic
|
||||
// commit without blitting a buffer.
|
||||
ok = true;
|
||||
|
|
@ -1068,7 +1138,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
|||
}
|
||||
|
||||
struct wlr_buffer *local_buf;
|
||||
if (drm->parent) {
|
||||
if (drm->mgpu_renderer.wlr_rend) {
|
||||
struct wlr_drm_format format = {0};
|
||||
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
|
||||
|
|
@ -1082,7 +1152,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
|||
return false;
|
||||
}
|
||||
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer, NULL, 0);
|
||||
if (local_buf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1102,7 +1172,6 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
|||
conn->cursor_height = buffer->height;
|
||||
}
|
||||
|
||||
wlr_output_update_needs_frame(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1132,7 +1201,6 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
|
|||
conn->cursor_x = box.x;
|
||||
conn->cursor_y = box.y;
|
||||
|
||||
wlr_output_update_needs_frame(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1155,6 +1223,8 @@ static void dealloc_crtc(struct wlr_drm_connector *conn);
|
|||
static void drm_connector_destroy_output(struct wlr_output *output) {
|
||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
||||
|
||||
wlr_output_finish(output);
|
||||
|
||||
dealloc_crtc(conn);
|
||||
|
||||
conn->status = DRM_MODE_DISCONNECTED;
|
||||
|
|
@ -1182,7 +1252,7 @@ static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
|
|||
if (!plane) {
|
||||
return NULL;
|
||||
}
|
||||
if (conn->backend->parent) {
|
||||
if (conn->backend->mgpu_renderer.wlr_rend) {
|
||||
return &conn->backend->mgpu_formats;
|
||||
}
|
||||
return &plane->formats;
|
||||
|
|
@ -1211,7 +1281,7 @@ static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
|
|||
if (!drm_connector_alloc_crtc(conn)) {
|
||||
return NULL;
|
||||
}
|
||||
if (conn->backend->parent) {
|
||||
if (conn->backend->mgpu_renderer.wlr_rend) {
|
||||
return &conn->backend->mgpu_formats;
|
||||
}
|
||||
return &conn->crtc->primary->formats;
|
||||
|
|
@ -1348,7 +1418,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm,
|
|||
++i;
|
||||
}
|
||||
|
||||
match_obj(num_connectors, connector_constraints,
|
||||
match_connectors_with_crtcs(num_connectors, connector_constraints,
|
||||
drm->num_crtcs, previous_match, new_match);
|
||||
|
||||
// Converts our crtc=>connector result into a connector=>crtc one.
|
||||
|
|
@ -1476,14 +1546,14 @@ static struct wlr_drm_connector *create_drm_connector(struct wlr_drm_backend *dr
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char *conn_name =
|
||||
const char *conn_type_name =
|
||||
drmModeGetConnectorTypeName(drm_conn->connector_type);
|
||||
if (conn_name == NULL) {
|
||||
conn_name = "Unknown";
|
||||
if (conn_type_name == NULL) {
|
||||
conn_type_name = "Unknown";
|
||||
}
|
||||
|
||||
snprintf(wlr_conn->name, sizeof(wlr_conn->name),
|
||||
"%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
|
||||
"%s-%"PRIu32, conn_type_name, drm_conn->connector_type_id);
|
||||
|
||||
wlr_conn->possible_crtcs =
|
||||
drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
|
||||
|
|
@ -1554,6 +1624,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
|
||||
wlr_log(WLR_INFO, "Detected modes:");
|
||||
|
||||
bool found_current_mode = false;
|
||||
for (int i = 0; i < drm_conn->count_modes; ++i) {
|
||||
if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
continue;
|
||||
|
|
@ -1572,14 +1643,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
if (current_modeinfo != NULL && memcmp(&mode->drm_mode,
|
||||
current_modeinfo, sizeof(*current_modeinfo)) == 0) {
|
||||
wlr_output_state_set_mode(&state, &mode->wlr_mode);
|
||||
|
||||
uint64_t mode_id = 0;
|
||||
get_drm_prop(drm->fd, wlr_conn->crtc->id,
|
||||
wlr_conn->crtc->props.mode_id, &mode_id);
|
||||
|
||||
wlr_conn->crtc->own_mode_id = false;
|
||||
wlr_conn->crtc->mode_id = mode_id;
|
||||
wlr_conn->refresh = calculate_refresh_rate(current_modeinfo);
|
||||
found_current_mode = true;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO, " %"PRId32"x%"PRId32" @ %.3f Hz %s",
|
||||
|
|
@ -1590,6 +1654,23 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
wl_list_insert(modes.prev, &mode->wlr_mode.link);
|
||||
}
|
||||
|
||||
if (current_modeinfo != NULL) {
|
||||
int32_t refresh = calculate_refresh_rate(current_modeinfo);
|
||||
|
||||
if (!found_current_mode) {
|
||||
wlr_output_state_set_custom_mode(&state,
|
||||
current_modeinfo->hdisplay, current_modeinfo->vdisplay, refresh);
|
||||
}
|
||||
|
||||
uint64_t mode_id = 0;
|
||||
get_drm_prop(drm->fd, wlr_conn->crtc->id,
|
||||
wlr_conn->crtc->props.mode_id, &mode_id);
|
||||
|
||||
wlr_conn->crtc->own_mode_id = false;
|
||||
wlr_conn->crtc->mode_id = mode_id;
|
||||
wlr_conn->refresh = refresh;
|
||||
}
|
||||
|
||||
free(current_modeinfo);
|
||||
|
||||
wlr_output_init(output, &drm->backend, &output_impl, drm->session->event_loop, &state);
|
||||
|
|
@ -1636,7 +1717,11 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
|||
size_t edid_len = 0;
|
||||
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
||||
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
||||
parse_edid(wlr_conn, edid_len, edid);
|
||||
if (edid_len > 0) {
|
||||
parse_edid(wlr_conn, edid_len, edid);
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "Connector has no EDID");
|
||||
}
|
||||
free(edid);
|
||||
|
||||
char *subconnector = NULL;
|
||||
|
|
@ -1702,6 +1787,10 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
|
|||
}
|
||||
}
|
||||
|
||||
if (wlr_conn && wlr_conn->lease) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the hotplug event contains a connector ID, ignore any other
|
||||
// connector.
|
||||
if (event != NULL && event->connector_id != 0 &&
|
||||
|
|
@ -1779,8 +1868,6 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
|
|||
destroy_drm_connector(conn);
|
||||
}
|
||||
|
||||
realloc_crtcs(drm, NULL);
|
||||
|
||||
for (size_t i = 0; i < new_outputs_len; ++i) {
|
||||
struct wlr_drm_connector *conn = new_outputs[i];
|
||||
|
||||
|
|
@ -1820,108 +1907,6 @@ void scan_drm_leases(struct wlr_drm_backend *drm) {
|
|||
drmFree(list);
|
||||
}
|
||||
|
||||
static void build_current_connector_state(struct wlr_output_state *state,
|
||||
struct wlr_drm_connector *conn) {
|
||||
bool enabled = conn->status != DRM_MODE_DISCONNECTED && conn->output.enabled;
|
||||
|
||||
wlr_output_state_init(state);
|
||||
wlr_output_state_set_enabled(state, enabled);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->output.current_mode != NULL) {
|
||||
wlr_output_state_set_mode(state, conn->output.current_mode);
|
||||
} else {
|
||||
wlr_output_state_set_custom_mode(state,
|
||||
conn->output.width, conn->output.height, conn->output.refresh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we need to perform a full reset after a VT switch.
|
||||
*
|
||||
* If any connector or plane has a different CRTC, we need to perform a full
|
||||
* reset to restore our mapping. We couldn't avoid a full reset even if we
|
||||
* used a single KMS atomic commit to apply our state: the kernel rejects
|
||||
* commits which migrate a plane from one CRTC to another without going through
|
||||
* an intermediate state where the plane is disabled.
|
||||
*/
|
||||
static bool skip_reset_for_restore(struct wlr_drm_backend *drm) {
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->connectors, link) {
|
||||
drmModeConnector *drm_conn = drmModeGetConnectorCurrent(drm->fd, conn->id);
|
||||
if (drm_conn == NULL) {
|
||||
return false;
|
||||
}
|
||||
struct wlr_drm_crtc *crtc = connector_get_current_crtc(conn, drm_conn);
|
||||
drmModeFreeConnector(drm_conn);
|
||||
|
||||
if (crtc != NULL && conn->crtc != crtc) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < drm->num_planes; i++) {
|
||||
struct wlr_drm_plane *plane = &drm->planes[i];
|
||||
|
||||
drmModePlane *drm_plane = drmModeGetPlane(drm->fd, plane->id);
|
||||
if (drm_plane == NULL) {
|
||||
return false;
|
||||
}
|
||||
uint32_t crtc_id = drm_plane->crtc_id;
|
||||
drmModeFreePlane(drm_plane);
|
||||
|
||||
struct wlr_drm_crtc *crtc = NULL;
|
||||
for (size_t i = 0; i < drm->num_crtcs; i++) {
|
||||
if (drm->crtcs[i].id == crtc_id) {
|
||||
crtc = &drm->crtcs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (crtc == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
switch (plane->type) {
|
||||
case DRM_PLANE_TYPE_PRIMARY:
|
||||
ok = crtc->primary == plane;
|
||||
break;
|
||||
case DRM_PLANE_TYPE_CURSOR:
|
||||
ok = crtc->cursor == plane;
|
||||
break;
|
||||
}
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void restore_drm_device(struct wlr_drm_backend *drm) {
|
||||
// The previous DRM master leaves KMS in an undefined state. We need
|
||||
// to restore our own state, but be careful to avoid invalid
|
||||
// configurations. The connector/CRTC mapping may have changed, so
|
||||
// first disable all CRTCs, then light up the ones we were using
|
||||
// before the VT switch.
|
||||
// TODO: better use the atomic API to improve restoration after a VT switch
|
||||
if (!skip_reset_for_restore(drm) && !drm->iface->reset(drm)) {
|
||||
wlr_log(WLR_ERROR, "Failed to reset state after VT switch");
|
||||
}
|
||||
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->connectors, link) {
|
||||
struct wlr_output_state state;
|
||||
build_current_connector_state(&state, conn);
|
||||
if (!drm_connector_commit_state(conn, &state, false)) {
|
||||
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch");
|
||||
}
|
||||
wlr_output_state_finish(&state);
|
||||
}
|
||||
}
|
||||
|
||||
bool commit_drm_device(struct wlr_drm_backend *drm,
|
||||
const struct wlr_backend_output_state *output_states, size_t output_states_len,
|
||||
bool test_only) {
|
||||
|
|
@ -1970,7 +1955,7 @@ bool commit_drm_device(struct wlr_drm_backend *drm,
|
|||
modeset |= output_state->base.allow_reconfiguration;
|
||||
}
|
||||
|
||||
if (test_only && drm->parent) {
|
||||
if (test_only && drm->mgpu_renderer.wlr_rend) {
|
||||
// If we're running as a secondary GPU, we can't perform an atomic
|
||||
// commit without blitting a buffer.
|
||||
ok = true;
|
||||
|
|
@ -2008,6 +1993,12 @@ static void handle_page_flip(int fd, unsigned seq,
|
|||
if (conn != NULL) {
|
||||
conn->pending_page_flip = NULL;
|
||||
}
|
||||
|
||||
uint32_t present_flags = WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
|
||||
if (!page_flip->async) {
|
||||
present_flags |= WLR_OUTPUT_PRESENT_VSYNC;
|
||||
}
|
||||
|
||||
if (page_flip->connectors_len == 0) {
|
||||
drm_page_flip_destroy(page_flip);
|
||||
}
|
||||
|
|
@ -2038,26 +2029,23 @@ static void handle_page_flip(int fd, unsigned seq,
|
|||
drm_fb_move(&layer->current_fb, &layer->queued_fb);
|
||||
}
|
||||
|
||||
uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
|
||||
WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
|
||||
/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
|
||||
* data between the GPUs, even if we were using the direct scanout
|
||||
* interface.
|
||||
*/
|
||||
if (!drm->parent) {
|
||||
if (!drm->mgpu_renderer.wlr_rend) {
|
||||
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
||||
}
|
||||
|
||||
struct timespec present_time = {
|
||||
.tv_sec = tv_sec,
|
||||
.tv_nsec = tv_usec * 1000,
|
||||
};
|
||||
struct wlr_output_event_present present_event = {
|
||||
/* The DRM backend guarantees that the presentation event will be for
|
||||
* the last submitted frame. */
|
||||
.commit_seq = conn->output.commit_seq,
|
||||
.presented = drm->session->active,
|
||||
.when = &present_time,
|
||||
.when = {
|
||||
.tv_sec = tv_sec,
|
||||
.tv_nsec = tv_usec * 1000,
|
||||
},
|
||||
.seq = seq,
|
||||
.refresh = mhz_to_nsec(conn->refresh),
|
||||
.flags = present_flags,
|
||||
|
|
@ -2191,6 +2179,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
|
|||
get_drm_connector_from_output(outputs[i]);
|
||||
conn->lease = lease;
|
||||
conn->crtc->lease = lease;
|
||||
disconnect_drm_connector(conn);
|
||||
}
|
||||
|
||||
return lease;
|
||||
|
|
@ -2213,6 +2202,8 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
|
|||
|
||||
wl_signal_emit_mutable(&lease->events.destroy, NULL);
|
||||
|
||||
assert(wl_list_empty(&lease->events.destroy.listener_list));
|
||||
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->connectors, link) {
|
||||
if (conn->lease == lease) {
|
||||
|
|
@ -2227,4 +2218,5 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
|
|||
}
|
||||
|
||||
free(lease);
|
||||
scan_drm_connectors(drm, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/color.h"
|
||||
#include "types/wlr_output.h"
|
||||
|
||||
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
|
||||
struct wlr_drm_fb *fb2) {
|
||||
|
|
@ -39,20 +41,41 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
|
|||
struct wlr_drm_connector *conn = state->connector;
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_BUFFER) && !modeset) {
|
||||
struct wlr_drm_fb *pending_fb = state->primary_fb;
|
||||
|
||||
struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
|
||||
if (!prev_fb) {
|
||||
prev_fb = crtc->primary->current_fb;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
// If the size doesn't match, reject buffer (scaling is not supported)
|
||||
int pending_width, pending_height;
|
||||
output_pending_resolution(&state->connector->output, state->base,
|
||||
&pending_width, &pending_height);
|
||||
if (state->base->buffer->width != pending_width ||
|
||||
state->base->buffer->height != pending_height) {
|
||||
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
|
||||
return false;
|
||||
}
|
||||
// Source crop is also not supported
|
||||
struct wlr_fbox src_box;
|
||||
output_state_get_buffer_src_box(state->base, &src_box);
|
||||
if (src_box.x != 0.0 || src_box.y != 0.0 ||
|
||||
src_box.width != (double)state->base->buffer->width ||
|
||||
src_box.height != (double)state->base->buffer->height) {
|
||||
wlr_log(WLR_DEBUG, "Source crop not supported in DRM-legacy output");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Legacy is only guaranteed to be able to display a FB if it's been
|
||||
* allocated the same way as the previous one. */
|
||||
if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Cannot change scan-out buffer parameters with legacy KMS API");
|
||||
return false;
|
||||
if (!modeset) {
|
||||
struct wlr_drm_fb *pending_fb = state->primary_fb;
|
||||
|
||||
struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
|
||||
if (!prev_fb) {
|
||||
prev_fb = crtc->primary->current_fb;
|
||||
}
|
||||
|
||||
/* Legacy is only guaranteed to be able to display a FB if it's been
|
||||
* allocated the same way as the previous one. */
|
||||
if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Cannot change scan-out buffer parameters with legacy KMS API");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,9 +125,17 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc,
|
||||
state->base->gamma_lut_size, state->base->gamma_lut)) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +159,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
state->base->adaptive_sync_enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
|
||||
if (cursor != NULL && state->active && drm_connector_is_cursor_visible(conn)) {
|
||||
struct wlr_drm_fb *cursor_fb = state->cursor_fb;
|
||||
if (cursor_fb == NULL) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to acquire cursor FB");
|
||||
|
|
@ -170,7 +201,9 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
// Legacy uAPI doesn't support requesting page-flip events when
|
||||
// turning off a CRTC
|
||||
if (state->active && (flags & DRM_MODE_PAGE_FLIP_EVENT)) {
|
||||
if (drmModePageFlip(drm->fd, crtc->id, fb_id, flags, page_flip)) {
|
||||
wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
|
||||
return false;
|
||||
|
|
@ -248,20 +281,6 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool legacy_reset(struct wlr_drm_backend *drm) {
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < drm->num_crtcs; i++) {
|
||||
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
|
||||
if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32,
|
||||
crtc->id);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
const struct wlr_drm_interface legacy_iface = {
|
||||
.commit = legacy_commit,
|
||||
.reset = legacy_reset,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
#include "config.h"
|
||||
#include "types/wlr_output.h"
|
||||
|
||||
static void log_handler(enum liftoff_log_priority priority, const char *fmt, va_list args) {
|
||||
enum wlr_log_importance importance = WLR_SILENT;
|
||||
|
|
@ -149,25 +151,23 @@ static bool add_prop(drmModeAtomicReq *req, uint32_t obj,
|
|||
}
|
||||
|
||||
static bool set_plane_props(struct wlr_drm_plane *plane,
|
||||
struct liftoff_layer *layer, struct wlr_drm_fb *fb, int32_t x, int32_t y, uint64_t zpos) {
|
||||
struct liftoff_layer *layer, struct wlr_drm_fb *fb, uint64_t zpos,
|
||||
const struct wlr_box *dst_box, const struct wlr_fbox *src_box) {
|
||||
if (fb == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t width = fb->wlr_buf->width;
|
||||
uint32_t height = fb->wlr_buf->height;
|
||||
|
||||
// The SRC_* properties are in 16.16 fixed point
|
||||
// The src_* properties are in 16.16 fixed point
|
||||
return liftoff_layer_set_property(layer, "zpos", zpos) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_X", 0) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_Y", 0) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_W", (uint64_t)width << 16) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_H", (uint64_t)height << 16) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_X", (uint64_t)x) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_Y", (uint64_t)y) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_W", width) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_H", height) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_X", src_box->x * (1 << 16)) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_Y", src_box->y * (1 << 16)) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_W", src_box->width * (1 << 16)) == 0 &&
|
||||
liftoff_layer_set_property(layer, "SRC_H", src_box->height * (1 << 16)) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_X", dst_box->x) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_Y", dst_box->y) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_W", dst_box->width) == 0 &&
|
||||
liftoff_layer_set_property(layer, "CRTC_H", dst_box->height) == 0 &&
|
||||
liftoff_layer_set_property(layer, "FB_ID", fb->id) == 0;
|
||||
}
|
||||
|
||||
|
|
@ -331,14 +331,32 @@ static bool add_connector(drmModeAtomicReq *req,
|
|||
if (crtc->props.vrr_enabled != 0) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
|
||||
}
|
||||
ok = ok &&
|
||||
set_plane_props(crtc->primary, crtc->primary->liftoff_layer, state->primary_fb, 0, 0, 0) &&
|
||||
set_plane_props(crtc->primary, crtc->liftoff_composition_layer, state->primary_fb, 0, 0, 0);
|
||||
|
||||
ok = ok && set_plane_props(crtc->primary,
|
||||
crtc->primary->liftoff_layer, state->primary_fb, 0,
|
||||
&state->primary_viewport.dst_box,
|
||||
&state->primary_viewport.src_box);
|
||||
ok = ok && set_plane_props(crtc->primary,
|
||||
crtc->liftoff_composition_layer, state->primary_fb, 0,
|
||||
&state->primary_viewport.dst_box,
|
||||
&state->primary_viewport.src_box);
|
||||
|
||||
liftoff_layer_set_property(crtc->primary->liftoff_layer,
|
||||
"FB_DAMAGE_CLIPS", state->fb_damage_clips);
|
||||
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
||||
"FB_DAMAGE_CLIPS", state->fb_damage_clips);
|
||||
|
||||
if (state->primary_in_fence_fd >= 0) {
|
||||
liftoff_layer_set_property(crtc->primary->liftoff_layer,
|
||||
"IN_FENCE_FD", state->primary_in_fence_fd);
|
||||
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
||||
"IN_FENCE_FD", state->primary_in_fence_fd);
|
||||
}
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.out_fence_ptr,
|
||||
(uintptr_t)&state->out_fence_fd);
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||
const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
|
||||
|
|
@ -349,9 +367,19 @@ static bool add_connector(drmModeAtomicReq *req,
|
|||
|
||||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
struct wlr_fbox cursor_src = {
|
||||
.width = state->cursor_fb->wlr_buf->width,
|
||||
.height = state->cursor_fb->wlr_buf->height,
|
||||
};
|
||||
struct wlr_box cursor_dst = {
|
||||
.x = conn->cursor_x,
|
||||
.y = conn->cursor_y,
|
||||
.width = state->cursor_fb->wlr_buf->width,
|
||||
.height = state->cursor_fb->wlr_buf->height,
|
||||
};
|
||||
ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
|
||||
state->cursor_fb, conn->cursor_x, conn->cursor_y,
|
||||
wl_list_length(&crtc->layers) + 1);
|
||||
state->cursor_fb, wl_list_length(&crtc->layers) + 1,
|
||||
&cursor_dst, &cursor_src);
|
||||
} else {
|
||||
ok = ok && disable_plane(crtc->cursor);
|
||||
}
|
||||
|
|
@ -397,7 +425,7 @@ static bool commit(struct wlr_drm_backend *drm,
|
|||
if (state->modeset) {
|
||||
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
}
|
||||
if (!test_only && state->nonblock) {
|
||||
if (state->nonblock) {
|
||||
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
||||
}
|
||||
|
||||
|
|
@ -479,5 +507,4 @@ const struct wlr_drm_interface liftoff_iface = {
|
|||
.init = init,
|
||||
.finish = finish,
|
||||
.commit = commit,
|
||||
.reset = drm_atomic_reset,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ hwdata = dependency(
|
|||
|
||||
libdisplay_info = dependency(
|
||||
'libdisplay-info',
|
||||
version: '>=0.2.0',
|
||||
required: 'drm' in backends,
|
||||
fallback: 'libdisplay-info',
|
||||
not_found_message: 'Required for the DRM backend.',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
|
@ -21,8 +22,10 @@ struct prop_info {
|
|||
static const struct prop_info connector_info[] = {
|
||||
#define INDEX(name) (offsetof(struct wlr_drm_connector_props, name) / sizeof(uint32_t))
|
||||
{ "CRTC_ID", INDEX(crtc_id) },
|
||||
{ "Colorspace", INDEX(colorspace) },
|
||||
{ "DPMS", INDEX(dpms) },
|
||||
{ "EDID", INDEX(edid) },
|
||||
{ "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) },
|
||||
{ "PATH", INDEX(path) },
|
||||
{ "content type", INDEX(content_type) },
|
||||
{ "link-status", INDEX(link_status) },
|
||||
|
|
@ -40,6 +43,7 @@ static const struct prop_info crtc_info[] = {
|
|||
{ "GAMMA_LUT", INDEX(gamma_lut) },
|
||||
{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
|
||||
{ "MODE_ID", INDEX(mode_id) },
|
||||
{ "OUT_FENCE_PTR", INDEX(out_fence_ptr) },
|
||||
{ "VRR_ENABLED", INDEX(vrr_enabled) },
|
||||
#undef INDEX
|
||||
};
|
||||
|
|
@ -55,6 +59,7 @@ static const struct prop_info plane_info[] = {
|
|||
{ "FB_ID", INDEX(fb_id) },
|
||||
{ "HOTSPOT_X", INDEX(hotspot_x) },
|
||||
{ "HOTSPOT_Y", INDEX(hotspot_y) },
|
||||
{ "IN_FENCE_FD", INDEX(in_fence_fd) },
|
||||
{ "IN_FORMATS", INDEX(in_formats) },
|
||||
{ "SIZE_HINTS", INDEX(size_hints) },
|
||||
{ "SRC_H", INDEX(src_h) },
|
||||
|
|
@ -77,14 +82,14 @@ static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result
|
|||
const struct prop_info *info, size_t info_len) {
|
||||
drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type);
|
||||
if (!props) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to get DRM object properties");
|
||||
wlr_log_errno(WLR_ERROR, "Failed to get DRM object %" PRIu32 " properties", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < props->count_props; ++i) {
|
||||
drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]);
|
||||
if (!prop) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to get DRM object property");
|
||||
wlr_log_errno(WLR_ERROR, "Failed to get property %" PRIu32 " of DRM object %" PRIu32, props->props[i], id);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,35 @@
|
|||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/renderer.h"
|
||||
#include "backend/backend.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
#include "render/pixel_format.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
|
||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_renderer *renderer) {
|
||||
wlr_log(WLR_DEBUG, "Creating multi-GPU renderer");
|
||||
renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
|
||||
if (!renderer->wlr_rend) {
|
||||
wlr_log(WLR_ERROR, "Failed to create renderer");
|
||||
return false;
|
||||
}
|
||||
if (wlr_renderer_get_texture_formats(renderer->wlr_rend, WLR_BUFFER_CAP_DMABUF) == NULL) {
|
||||
wlr_log(WLR_ERROR, "Renderer did not support importing DMA-BUFs");
|
||||
wlr_renderer_destroy(renderer->wlr_rend);
|
||||
renderer->wlr_rend = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t backend_caps = backend_get_buffer_caps(&drm->backend);
|
||||
renderer->allocator = allocator_autocreate_with_drm_fd(backend_caps,
|
||||
renderer->wlr_rend, drm->fd);
|
||||
renderer->allocator = wlr_allocator_autocreate(&drm->backend, renderer->wlr_rend);
|
||||
if (renderer->allocator == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create allocator");
|
||||
wlr_renderer_destroy(renderer->wlr_rend);
|
||||
renderer->wlr_rend = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +50,7 @@ void finish_drm_surface(struct wlr_drm_surface *surf) {
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_drm_syncobj_timeline_unref(surf->timeline);
|
||||
wlr_swapchain_destroy(surf->swapchain);
|
||||
|
||||
*surf = (struct wlr_drm_surface){0};
|
||||
|
|
@ -68,13 +73,24 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
|
|||
return false;
|
||||
}
|
||||
|
||||
int drm_fd = wlr_renderer_get_drm_fd(renderer->wlr_rend);
|
||||
if (renderer->wlr_rend->features.timeline && drm_fd >= 0) {
|
||||
surf->timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
||||
if (surf->timeline == NULL) {
|
||||
finish_drm_surface(surf);
|
||||
wlr_log(WLR_ERROR, "Failed to create DRM syncobj timeline");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
surf->renderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
||||
struct wlr_buffer *buffer) {
|
||||
struct wlr_buffer *buffer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
|
||||
|
||||
if (surf->swapchain->width != buffer->width ||
|
||||
|
|
@ -89,13 +105,18 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
|
||||
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain);
|
||||
if (!dst) {
|
||||
wlr_log(WLR_ERROR, "Failed to acquire multi-GPU swapchain buffer");
|
||||
goto error_tex;
|
||||
}
|
||||
|
||||
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, NULL);
|
||||
surf->point++;
|
||||
const struct wlr_buffer_pass_options pass_options = {
|
||||
.signal_timeline = surf->timeline,
|
||||
.signal_point = surf->point,
|
||||
};
|
||||
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, &pass_options);
|
||||
if (pass == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to begin render pass with multi-GPU destination buffer");
|
||||
goto error_dst;
|
||||
|
|
@ -104,6 +125,8 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
|
||||
.texture = tex,
|
||||
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
|
||||
.wait_timeline = wait_timeline,
|
||||
.wait_point = wait_point,
|
||||
});
|
||||
if (!wlr_render_pass_submit(pass)) {
|
||||
wlr_log(WLR_ERROR, "Failed to submit multi-GPU render pass");
|
||||
|
|
|
|||
|
|
@ -83,6 +83,17 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data)
|
|||
output->model = di_info_get_model(info);
|
||||
output->serial = di_info_get_serial(info);
|
||||
|
||||
const struct di_supported_signal_colorimetry *colorimetry = di_info_get_supported_signal_colorimetry(info);
|
||||
bool has_bt2020 = colorimetry->bt2020_cycc || colorimetry->bt2020_ycc || colorimetry->bt2020_rgb;
|
||||
if (conn->props.colorspace != 0 && has_bt2020) {
|
||||
output->supported_primaries |= WLR_COLOR_NAMED_PRIMARIES_BT2020;
|
||||
}
|
||||
|
||||
const struct di_hdr_static_metadata *hdr_static_metadata = di_info_get_hdr_static_metadata(info);
|
||||
if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) {
|
||||
output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
}
|
||||
|
||||
di_info_destroy(info);
|
||||
}
|
||||
|
||||
|
|
@ -112,9 +123,9 @@ static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
|
|||
* passing 12 arguments to a function.
|
||||
*/
|
||||
struct match_state {
|
||||
const size_t num_objs;
|
||||
const uint32_t *restrict objs;
|
||||
const size_t num_res;
|
||||
const size_t num_conns;
|
||||
const uint32_t *restrict conns;
|
||||
const size_t num_crtcs;
|
||||
size_t score;
|
||||
size_t replaced;
|
||||
uint32_t *restrict res;
|
||||
|
|
@ -123,27 +134,31 @@ struct match_state {
|
|||
bool exit_early;
|
||||
};
|
||||
|
||||
/*
|
||||
* skips: The number of SKIP elements encountered so far.
|
||||
* score: The number of resources we've matched so far.
|
||||
/**
|
||||
* Step to process a CRTC.
|
||||
*
|
||||
* This is a naive implementation of maximum bipartite matching.
|
||||
*
|
||||
* score: The number of connectors we've matched so far.
|
||||
* replaced: The number of changes from the original solution.
|
||||
* i: The index of the current element.
|
||||
* crtc_index: The index of the current CRTC.
|
||||
*
|
||||
* This tries to match a solution as close to st->orig as it can.
|
||||
*
|
||||
* Returns whether we've set a new best element with this solution.
|
||||
*/
|
||||
static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_t replaced, size_t i) {
|
||||
static bool match_connectors_with_crtcs_(struct match_state *st,
|
||||
size_t score, size_t replaced, size_t crtc_index) {
|
||||
// Finished
|
||||
if (i >= st->num_res) {
|
||||
if (crtc_index >= st->num_crtcs) {
|
||||
if (score > st->score ||
|
||||
(score == st->score && replaced < st->replaced)) {
|
||||
st->score = score;
|
||||
st->replaced = replaced;
|
||||
memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_res);
|
||||
memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_crtcs);
|
||||
|
||||
st->exit_early = (st->score == st->num_res - skips
|
||||
|| st->score == st->num_objs)
|
||||
st->exit_early = (st->score == st->num_crtcs
|
||||
|| st->score == st->num_conns)
|
||||
&& st->replaced == 0;
|
||||
|
||||
return true;
|
||||
|
|
@ -152,27 +167,16 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
|
|||
}
|
||||
}
|
||||
|
||||
if (st->orig[i] == SKIP) {
|
||||
st->res[i] = SKIP;
|
||||
return match_obj_(st, skips + 1, score, replaced, i + 1);
|
||||
}
|
||||
|
||||
bool has_best = false;
|
||||
|
||||
/*
|
||||
* Attempt to use the current solution first, to try and avoid
|
||||
* recalculating everything
|
||||
*/
|
||||
if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) {
|
||||
st->res[i] = st->orig[i];
|
||||
size_t obj_score = st->objs[st->res[i]] != 0 ? 1 : 0;
|
||||
if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
|
||||
has_best = true;
|
||||
}
|
||||
}
|
||||
if (st->orig[i] == UNMATCHED) {
|
||||
st->res[i] = UNMATCHED;
|
||||
if (match_obj_(st, skips, score, replaced, i + 1)) {
|
||||
if (st->orig[crtc_index] != UNMATCHED && !is_taken(crtc_index, st->res, st->orig[crtc_index])) {
|
||||
st->res[crtc_index] = st->orig[crtc_index];
|
||||
size_t crtc_score = st->conns[st->res[crtc_index]] != 0 ? 1 : 0;
|
||||
if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
|
||||
has_best = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -180,29 +184,29 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
|
|||
return true;
|
||||
}
|
||||
|
||||
if (st->orig[i] != UNMATCHED) {
|
||||
if (st->orig[crtc_index] != UNMATCHED) {
|
||||
++replaced;
|
||||
}
|
||||
|
||||
for (size_t candidate = 0; candidate < st->num_objs; ++candidate) {
|
||||
for (size_t candidate = 0; candidate < st->num_conns; ++candidate) {
|
||||
// We tried this earlier
|
||||
if (candidate == st->orig[i]) {
|
||||
if (candidate == st->orig[crtc_index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not compatible
|
||||
if (!(st->objs[candidate] & (1 << i))) {
|
||||
if (!(st->conns[candidate] & (1 << crtc_index))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Already taken
|
||||
if (is_taken(i, st->res, candidate)) {
|
||||
if (is_taken(crtc_index, st->res, candidate)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
st->res[i] = candidate;
|
||||
size_t obj_score = st->objs[candidate] != 0 ? 1 : 0;
|
||||
if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
|
||||
st->res[crtc_index] = candidate;
|
||||
size_t crtc_score = st->conns[candidate] != 0 ? 1 : 0;
|
||||
if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
|
||||
has_best = true;
|
||||
}
|
||||
|
||||
|
|
@ -211,37 +215,37 @@ static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_
|
|||
}
|
||||
}
|
||||
|
||||
if (has_best) {
|
||||
return true;
|
||||
// Maybe this CRTC can't be matched
|
||||
st->res[crtc_index] = UNMATCHED;
|
||||
if (match_connectors_with_crtcs_(st, score, replaced, crtc_index + 1)) {
|
||||
has_best = true;
|
||||
}
|
||||
|
||||
// Maybe this resource can't be matched
|
||||
st->res[i] = UNMATCHED;
|
||||
return match_obj_(st, skips, score, replaced, i + 1);
|
||||
return has_best;
|
||||
}
|
||||
|
||||
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
|
||||
size_t num_res, const uint32_t res[static restrict num_res],
|
||||
uint32_t out[static restrict num_res]) {
|
||||
uint32_t solution[num_res];
|
||||
for (size_t i = 0; i < num_res; ++i) {
|
||||
void match_connectors_with_crtcs(size_t num_conns,
|
||||
const uint32_t conns[static restrict num_conns],
|
||||
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
|
||||
uint32_t new_crtcs[static restrict num_crtcs]) {
|
||||
uint32_t solution[num_crtcs];
|
||||
for (size_t i = 0; i < num_crtcs; ++i) {
|
||||
solution[i] = UNMATCHED;
|
||||
}
|
||||
|
||||
struct match_state st = {
|
||||
.num_objs = num_objs,
|
||||
.num_res = num_res,
|
||||
.num_conns = num_conns,
|
||||
.num_crtcs = num_crtcs,
|
||||
.score = 0,
|
||||
.replaced = SIZE_MAX,
|
||||
.objs = objs,
|
||||
.conns = conns,
|
||||
.res = solution,
|
||||
.best = out,
|
||||
.orig = res,
|
||||
.best = new_crtcs,
|
||||
.orig = prev_crtcs,
|
||||
.exit_early = false,
|
||||
};
|
||||
|
||||
match_obj_(&st, 0, 0, 0, 0);
|
||||
return st.score;
|
||||
match_connectors_with_crtcs_(&st, 0, 0, 0);
|
||||
}
|
||||
|
||||
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
|
||||
|
|
|
|||
|
|
@ -45,16 +45,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
free(backend);
|
||||
}
|
||||
|
||||
static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) {
|
||||
return WLR_BUFFER_CAP_DATA_PTR
|
||||
| WLR_BUFFER_CAP_DMABUF
|
||||
| WLR_BUFFER_CAP_SHM;
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_buffer_caps = get_buffer_caps,
|
||||
};
|
||||
|
||||
static void handle_event_loop_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -74,12 +67,17 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop) {
|
|||
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
|
||||
backend->backend.buffer_caps =
|
||||
WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
|
||||
|
||||
backend->event_loop = loop;
|
||||
wl_list_init(&backend->outputs);
|
||||
|
||||
backend->event_loop_destroy.notify = handle_event_loop_destroy;
|
||||
wl_event_loop_add_destroy_listener(loop, &backend->event_loop_destroy);
|
||||
|
||||
backend->backend.features.timeline = true;
|
||||
|
||||
return &backend->backend;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,9 +79,20 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool output_set_cursor(struct wlr_output *wlr_output,
|
||||
struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool output_move_cursor(struct wlr_output *wlr_output, int x, int y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void output_destroy(struct wlr_output *wlr_output) {
|
||||
struct wlr_headless_output *output =
|
||||
headless_output_from_output(wlr_output);
|
||||
struct wlr_headless_output *output = headless_output_from_output(wlr_output);
|
||||
|
||||
wlr_output_finish(wlr_output);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
wl_event_source_remove(output->frame_timer);
|
||||
free(output);
|
||||
|
|
@ -89,7 +100,10 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
|
||||
static const struct wlr_output_impl output_impl = {
|
||||
.destroy = output_destroy,
|
||||
.test = output_test,
|
||||
.commit = output_commit,
|
||||
.set_cursor = output_set_cursor,
|
||||
.move_cursor = output_move_cursor,
|
||||
};
|
||||
|
||||
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
|
||||
|
|
|
|||
|
|
@ -61,25 +61,15 @@ void handle_pointer_button(struct libinput_event *event,
|
|||
.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
|
||||
.button = libinput_event_pointer_get_button(pevent),
|
||||
};
|
||||
// Ignore events which aren't a seat-wide state change. For instance, if
|
||||
// the same button is pressed twice on the same seat, ignore the second
|
||||
// press.
|
||||
uint32_t seat_count = libinput_event_pointer_get_seat_button_count(pevent);
|
||||
switch (libinput_event_pointer_get_button_state(pevent)) {
|
||||
case LIBINPUT_BUTTON_STATE_PRESSED:
|
||||
wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED;
|
||||
if (seat_count != 1) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case LIBINPUT_BUTTON_STATE_RELEASED:
|
||||
wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED;
|
||||
if (seat_count != 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
wl_signal_emit_mutable(&pointer->events.button, &wlr_event);
|
||||
wlr_pointer_notify_button(pointer, &wlr_event);
|
||||
wl_signal_emit_mutable(&pointer->events.frame, pointer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
|
|||
struct udev_device *udev = libinput_device_get_udev_device(handle);
|
||||
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
udev_device_unref(udev);
|
||||
|
||||
int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
|
||||
for (int i = 0; i < groups; ++i) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/interfaces/wlr_tablet_tool.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/libinput.h"
|
||||
#include "config.h"
|
||||
|
||||
struct tablet_tool {
|
||||
struct wlr_tablet_tool wlr_tool;
|
||||
|
|
@ -36,6 +37,7 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) {
|
|||
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
|
||||
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
udev_device_unref(udev);
|
||||
|
||||
wl_list_init(&dev->tablet_tools);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/multi.h"
|
||||
|
||||
struct subbackend_state {
|
||||
|
|
@ -52,6 +51,9 @@ static void multi_backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
|
||||
wlr_backend_finish(wlr_backend);
|
||||
|
||||
assert(wl_list_empty(&backend->events.backend_add.listener_list));
|
||||
assert(wl_list_empty(&backend->events.backend_remove.listener_list));
|
||||
|
||||
// Some backends may depend on other backends, ie. destroying a backend may
|
||||
// also destroy other backends
|
||||
while (!wl_list_empty(&backend->backends)) {
|
||||
|
|
@ -76,28 +78,6 @@ static int multi_backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t multi_backend_get_buffer_caps(struct wlr_backend *backend) {
|
||||
struct wlr_multi_backend *multi = multi_backend_from_backend(backend);
|
||||
|
||||
if (wl_list_empty(&multi->backends)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t caps = WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF
|
||||
| WLR_BUFFER_CAP_SHM;
|
||||
|
||||
struct subbackend_state *sub;
|
||||
wl_list_for_each(sub, &multi->backends, link) {
|
||||
uint32_t backend_caps = backend_get_buffer_caps(sub->backend);
|
||||
if (backend_caps != 0) {
|
||||
// only count backend capable of presenting a buffer
|
||||
caps = caps & backend_caps;
|
||||
}
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static int compare_output_state_backend(const void *data_a, const void *data_b) {
|
||||
const struct wlr_backend_output_state *a = data_a;
|
||||
const struct wlr_backend_output_state *b = data_b;
|
||||
|
|
@ -126,22 +106,24 @@ static bool commit(struct wlr_backend *backend,
|
|||
qsort(by_backend, states_len, sizeof(by_backend[0]), compare_output_state_backend);
|
||||
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < states_len; i++) {
|
||||
for (size_t i = 0; i < states_len;) {
|
||||
struct wlr_backend *sub = by_backend[i].output->backend;
|
||||
|
||||
size_t j = i;
|
||||
while (j < states_len && by_backend[j].output->backend == sub) {
|
||||
j++;
|
||||
size_t len = 1;
|
||||
while (i + len < states_len &&
|
||||
by_backend[i + len].output->backend == sub) {
|
||||
len++;
|
||||
}
|
||||
|
||||
if (test_only) {
|
||||
ok = wlr_backend_test(sub, &by_backend[i], j - i);
|
||||
ok = wlr_backend_test(sub, &by_backend[i], len);
|
||||
} else {
|
||||
ok = wlr_backend_commit(sub, &by_backend[i], j - i);
|
||||
ok = wlr_backend_commit(sub, &by_backend[i], len);
|
||||
}
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
i += len;
|
||||
}
|
||||
|
||||
free(by_backend);
|
||||
|
|
@ -162,7 +144,6 @@ static const struct wlr_backend_impl backend_impl = {
|
|||
.start = multi_backend_start,
|
||||
.destroy = multi_backend_destroy,
|
||||
.get_drm_fd = multi_backend_get_drm_fd,
|
||||
.get_buffer_caps = multi_backend_get_buffer_caps,
|
||||
.test = multi_backend_test,
|
||||
.commit = multi_backend_commit,
|
||||
};
|
||||
|
|
@ -225,6 +206,33 @@ static struct subbackend_state *multi_backend_get_subbackend(struct wlr_multi_ba
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void multi_backend_refresh_features(struct wlr_multi_backend *multi) {
|
||||
multi->backend.buffer_caps = 0;
|
||||
multi->backend.features.timeline = true;
|
||||
|
||||
bool has_buffer_cap = false;
|
||||
uint32_t buffer_caps_intersection =
|
||||
WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
|
||||
struct subbackend_state *sub = NULL;
|
||||
wl_list_for_each(sub, &multi->backends, link) {
|
||||
// Only take into account backends capable of presenting a buffer
|
||||
if (sub->backend->buffer_caps != 0) {
|
||||
has_buffer_cap = true;
|
||||
buffer_caps_intersection &= sub->backend->buffer_caps;
|
||||
}
|
||||
|
||||
// timeline is only applicable to backends that support DMABUFs
|
||||
if (sub->backend->buffer_caps & WLR_BUFFER_CAP_DMABUF) {
|
||||
multi->backend.features.timeline = multi->backend.features.timeline &&
|
||||
sub->backend->features.timeline;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_buffer_cap) {
|
||||
multi->backend.buffer_caps = buffer_caps_intersection;
|
||||
}
|
||||
}
|
||||
|
||||
bool wlr_multi_backend_add(struct wlr_backend *_multi,
|
||||
struct wlr_backend *backend) {
|
||||
assert(_multi && backend);
|
||||
|
|
@ -256,6 +264,7 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi,
|
|||
wl_signal_add(&backend->events.new_output, &sub->new_output);
|
||||
sub->new_output.notify = new_output_reemit;
|
||||
|
||||
multi_backend_refresh_features(multi);
|
||||
wl_signal_emit_mutable(&multi->events.backend_add, backend);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -270,6 +279,7 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi,
|
|||
if (sub) {
|
||||
wl_signal_emit_mutable(&multi->events.backend_remove, backend);
|
||||
subbackend_state_destroy(sub);
|
||||
multi_backend_refresh_features(multi);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,32 +191,40 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
|||
goto out;
|
||||
}
|
||||
|
||||
dev_t devnum = udev_device_get_devnum(udev_dev);
|
||||
if (strcmp(action, "add") == 0) {
|
||||
struct wlr_device *dev;
|
||||
wl_list_for_each(dev, &session->devices, link) {
|
||||
if (dev->dev == devnum) {
|
||||
wlr_log(WLR_DEBUG, "Skipping duplicate device %s", sysname);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
|
||||
struct wlr_session_add_event event = {
|
||||
.path = devnode,
|
||||
};
|
||||
wl_signal_emit_mutable(&session->events.add_drm_card, &event);
|
||||
} else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
|
||||
dev_t devnum = udev_device_get_devnum(udev_dev);
|
||||
} else if (strcmp(action, "change") == 0) {
|
||||
struct wlr_device *dev;
|
||||
wl_list_for_each(dev, &session->devices, link) {
|
||||
if (dev->dev != devnum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(action, "change") == 0) {
|
||||
if (dev->dev == devnum) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
|
||||
struct wlr_device_change_event event = {0};
|
||||
read_udev_change_event(&event, udev_dev);
|
||||
wl_signal_emit_mutable(&dev->events.change, &event);
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
struct wlr_device *dev;
|
||||
wl_list_for_each(dev, &session->devices, link) {
|
||||
if (dev->dev == devnum) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
|
||||
wl_signal_emit_mutable(&dev->events.remove, NULL);
|
||||
} else {
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,6 +303,11 @@ void wlr_session_destroy(struct wlr_session *session) {
|
|||
}
|
||||
|
||||
wl_signal_emit_mutable(&session->events.destroy, session);
|
||||
|
||||
assert(wl_list_empty(&session->events.active.listener_list));
|
||||
assert(wl_list_empty(&session->events.add_drm_card.listener_list));
|
||||
assert(wl_list_empty(&session->events.destroy.listener_list));
|
||||
|
||||
wl_list_remove(&session->event_loop_destroy.link);
|
||||
|
||||
wl_event_source_remove(session->udev_event);
|
||||
|
|
@ -352,6 +365,13 @@ void wlr_session_close_file(struct wlr_session *session,
|
|||
if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
|
||||
}
|
||||
|
||||
assert(wl_list_empty(&dev->events.change.listener_list));
|
||||
// TODO: assert that the "remove" listener list is empty as well. Listeners
|
||||
// will typically call wlr_session_close_file() in response, and
|
||||
// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
|
||||
// these two.
|
||||
|
||||
close(dev->fd);
|
||||
wl_list_remove(&dev->link);
|
||||
free(dev);
|
||||
|
|
@ -499,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
bool is_boot_vga = false;
|
||||
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
||||
if (!dev) {
|
||||
|
|
@ -516,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
continue;
|
||||
}
|
||||
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
bool is_primary = false;
|
||||
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
|
||||
if (boot_display && strcmp(boot_display, "1") == 0) {
|
||||
is_primary = true;
|
||||
} else {
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_boot_vga = true;
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_primary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -537,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
udev_device_unref(dev);
|
||||
|
||||
ret[i] = wlr_dev;
|
||||
if (is_boot_vga) {
|
||||
if (is_primary) {
|
||||
struct wlr_device *tmp = ret[0];
|
||||
ret[0] = ret[i];
|
||||
ret[i] = tmp;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "drm-client-protocol.h"
|
||||
#include "linux-dmabuf-v1-client-protocol.h"
|
||||
#include "linux-drm-syncobj-v1-client-protocol.h"
|
||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
#include "xdg-activation-v1-client-protocol.h"
|
||||
|
|
@ -54,14 +55,6 @@ struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *wlr_backe
|
|||
static int dispatch_events(int fd, uint32_t mask, void *data) {
|
||||
struct wlr_wl_backend *wl = data;
|
||||
|
||||
if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
||||
}
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
count = wl_display_dispatch(wl->remote_display);
|
||||
|
|
@ -74,6 +67,18 @@ static int dispatch_events(int fd, uint32_t mask, void *data) {
|
|||
wl_display_flush(wl->remote_display);
|
||||
}
|
||||
|
||||
// Make sure we've consumed all data before disconnecting due to hangup,
|
||||
// so that we process any wl_display.error events
|
||||
if (!(mask & WL_EVENT_READABLE) && (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR))) {
|
||||
if (mask & WL_EVENT_ERROR) {
|
||||
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "Disconnected from remote Wayland display");
|
||||
}
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
|
||||
wlr_backend_destroy(&wl->backend);
|
||||
|
|
@ -178,7 +183,9 @@ static void linux_dmabuf_feedback_v1_handle_main_device(void *data,
|
|||
"falling back to primary node", name);
|
||||
}
|
||||
|
||||
feedback_data->backend->drm_render_name = strdup(name);
|
||||
struct wlr_wl_backend *wl = feedback_data->backend;
|
||||
assert(wl->drm_render_name == NULL);
|
||||
wl->drm_render_name = strdup(name);
|
||||
|
||||
drmFreeDevice(&device);
|
||||
}
|
||||
|
|
@ -305,6 +312,7 @@ static char *get_render_name(const char *name) {
|
|||
static void legacy_drm_handle_device(void *data, struct wl_drm *drm,
|
||||
const char *name) {
|
||||
struct wlr_wl_backend *wl = data;
|
||||
assert(wl->drm_render_name == NULL);
|
||||
wl->drm_render_name = get_render_name(name);
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +416,9 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(iface, wp_viewporter_interface.name) == 0) {
|
||||
wl->viewporter = wl_registry_bind(registry, name,
|
||||
&wp_viewporter_interface, 1);
|
||||
} else if (strcmp(iface, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) {
|
||||
wl->drm_syncobj_manager_v1 = wl_registry_bind(registry, name,
|
||||
&wp_linux_drm_syncobj_manager_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -481,6 +492,11 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
destroy_wl_buffer(buffer);
|
||||
}
|
||||
|
||||
struct wlr_wl_drm_syncobj_timeline *timeline, *tmp_timeline;
|
||||
wl_list_for_each_safe(timeline, tmp_timeline, &wl->drm_syncobj_timelines, link) {
|
||||
destroy_wl_drm_syncobj_timeline(timeline);
|
||||
}
|
||||
|
||||
wlr_backend_finish(backend);
|
||||
|
||||
wl_list_remove(&wl->event_loop_destroy.link);
|
||||
|
|
@ -515,6 +531,9 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
if (wl->zwp_linux_dmabuf_v1) {
|
||||
zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1);
|
||||
}
|
||||
if (wl->drm_syncobj_manager_v1) {
|
||||
wp_linux_drm_syncobj_manager_v1_destroy(wl->drm_syncobj_manager_v1);
|
||||
}
|
||||
if (wl->legacy_drm != NULL) {
|
||||
wl_drm_destroy(wl->legacy_drm);
|
||||
}
|
||||
|
|
@ -540,6 +559,7 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
wl_compositor_destroy(wl->compositor);
|
||||
wl_registry_destroy(wl->registry);
|
||||
wl_display_flush(wl->remote_display);
|
||||
wl_event_queue_destroy(wl->busy_loop_queue);
|
||||
if (wl->own_remote_display) {
|
||||
wl_display_disconnect(wl->remote_display);
|
||||
}
|
||||
|
|
@ -551,17 +571,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
return wl->drm_fd;
|
||||
}
|
||||
|
||||
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
|
||||
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
||||
return (wl->zwp_linux_dmabuf_v1 ? WLR_BUFFER_CAP_DMABUF : 0)
|
||||
| (wl->shm ? WLR_BUFFER_CAP_SHM : 0);
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = get_buffer_caps,
|
||||
};
|
||||
|
||||
bool wlr_backend_is_wl(struct wlr_backend *b) {
|
||||
|
|
@ -589,6 +602,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
|
|||
wl_list_init(&wl->outputs);
|
||||
wl_list_init(&wl->seats);
|
||||
wl_list_init(&wl->buffers);
|
||||
wl_list_init(&wl->drm_syncobj_timelines);
|
||||
|
||||
if (remote_display != NULL) {
|
||||
wl->remote_display = remote_display;
|
||||
|
|
@ -601,10 +615,16 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
|
|||
wl->own_remote_display = true;
|
||||
}
|
||||
|
||||
wl->busy_loop_queue = wl_display_create_queue(wl->remote_display);
|
||||
if (wl->busy_loop_queue == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Could not create a Wayland event queue");
|
||||
goto error_display;
|
||||
}
|
||||
|
||||
wl->registry = wl_display_get_registry(wl->remote_display);
|
||||
if (!wl->registry) {
|
||||
wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
|
||||
goto error_display;
|
||||
goto error_queue;
|
||||
}
|
||||
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
||||
|
||||
|
|
@ -621,6 +641,10 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
|
|||
goto error_registry;
|
||||
}
|
||||
|
||||
wl->backend.features.timeline = wl->drm_syncobj_manager_v1 != NULL;
|
||||
|
||||
wl_display_roundtrip(wl->remote_display); // process initial event bursts
|
||||
|
||||
struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback_v1 = NULL;
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 feedback_data = { .backend = wl };
|
||||
if (wl->zwp_linux_dmabuf_v1 != NULL &&
|
||||
|
|
@ -638,18 +662,27 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
|
|||
if (wl->legacy_drm != NULL) {
|
||||
wl_drm_destroy(wl->legacy_drm);
|
||||
wl->legacy_drm = NULL;
|
||||
|
||||
free(wl->drm_render_name);
|
||||
wl->drm_render_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats
|
||||
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf feedback events
|
||||
|
||||
if (feedback_data.format_table != NULL) {
|
||||
munmap(feedback_data.format_table, feedback_data.format_table_size);
|
||||
}
|
||||
|
||||
if (feedback_data.format_table != NULL) {
|
||||
munmap(feedback_data.format_table, feedback_data.format_table_size);
|
||||
}
|
||||
if (linux_dmabuf_feedback_v1 != NULL) {
|
||||
zwp_linux_dmabuf_feedback_v1_destroy(linux_dmabuf_feedback_v1);
|
||||
}
|
||||
|
||||
if (wl->zwp_linux_dmabuf_v1) {
|
||||
wl->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
|
||||
}
|
||||
if (wl->shm) {
|
||||
wl->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
|
||||
}
|
||||
|
||||
int fd = wl_display_get_fd(wl->remote_display);
|
||||
wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
||||
dispatch_events, wl);
|
||||
|
|
@ -693,6 +726,8 @@ error_registry:
|
|||
xdg_wm_base_destroy(wl->xdg_wm_base);
|
||||
}
|
||||
wl_registry_destroy(wl->registry);
|
||||
error_queue:
|
||||
wl_event_queue_destroy(wl->busy_loop_queue);
|
||||
error_display:
|
||||
if (wl->own_remote_display) {
|
||||
wl_display_disconnect(wl->remote_display);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
wayland_client = dependency('wayland-client',
|
||||
fallback: 'wayland',
|
||||
default_options: wayland_project_options,
|
||||
kwargs: wayland_kwargs,
|
||||
)
|
||||
wlr_deps += wayland_client
|
||||
|
||||
|
|
@ -15,6 +14,7 @@ wlr_files += files(
|
|||
client_protos = [
|
||||
'drm',
|
||||
'linux-dmabuf-v1',
|
||||
'linux-drm-syncobj-v1',
|
||||
'pointer-gestures-unstable-v1',
|
||||
'presentation-time',
|
||||
'relative-pointer-unstable-v1',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_output_layer.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
#include "types/wlr_output.h"
|
||||
|
||||
#include "linux-dmabuf-v1-client-protocol.h"
|
||||
#include "linux-drm-syncobj-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "xdg-activation-v1-client-protocol.h"
|
||||
|
|
@ -31,7 +33,9 @@ static const uint32_t SUPPORTED_OUTPUT_STATE =
|
|||
WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_ENABLED |
|
||||
WLR_OUTPUT_STATE_MODE |
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE;
|
||||
|
||||
static size_t last_output_num = 0;
|
||||
|
||||
|
|
@ -94,14 +98,13 @@ static void presentation_feedback_handle_presented(void *data,
|
|||
uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) {
|
||||
struct wlr_wl_presentation_feedback *feedback = data;
|
||||
|
||||
struct timespec t = {
|
||||
.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
|
||||
.tv_nsec = tv_nsec,
|
||||
};
|
||||
struct wlr_output_event_present event = {
|
||||
.commit_seq = feedback->commit_seq,
|
||||
.presented = true,
|
||||
.when = &t,
|
||||
.when = {
|
||||
.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
|
||||
.tv_nsec = tv_nsec,
|
||||
},
|
||||
.seq = ((uint64_t)seq_hi << 32) | seq_lo,
|
||||
.refresh = refresh_ns,
|
||||
.flags = flags,
|
||||
|
|
@ -131,6 +134,11 @@ static const struct wp_presentation_feedback_listener
|
|||
.discarded = presentation_feedback_handle_discarded,
|
||||
};
|
||||
|
||||
static void buffer_remove_drm_syncobj_waiter(struct wlr_wl_buffer *buffer) {
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&buffer->drm_syncobj_waiter);
|
||||
buffer->has_drm_syncobj_waiter = false;
|
||||
}
|
||||
|
||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
||||
if (buffer == NULL) {
|
||||
return;
|
||||
|
|
@ -138,22 +146,42 @@ void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
|
|||
wl_list_remove(&buffer->buffer_destroy.link);
|
||||
wl_list_remove(&buffer->link);
|
||||
wl_buffer_destroy(buffer->wl_buffer);
|
||||
if (buffer->has_drm_syncobj_waiter) {
|
||||
buffer_remove_drm_syncobj_waiter(buffer);
|
||||
}
|
||||
if (!buffer->released) {
|
||||
wlr_buffer_unlock(buffer->buffer);
|
||||
}
|
||||
wlr_drm_syncobj_timeline_unref(buffer->fallback_signal_timeline);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void buffer_release(struct wlr_wl_buffer *buffer) {
|
||||
if (buffer->released) {
|
||||
return;
|
||||
}
|
||||
buffer->released = true;
|
||||
wlr_buffer_unlock(buffer->buffer); // might free buffer
|
||||
}
|
||||
|
||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
|
||||
struct wlr_wl_buffer *buffer = data;
|
||||
buffer->released = true;
|
||||
wlr_buffer_unlock(buffer->buffer); // might free buffer
|
||||
if (buffer->has_drm_syncobj_waiter) {
|
||||
return;
|
||||
}
|
||||
buffer_release(buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
.release = buffer_handle_release,
|
||||
};
|
||||
|
||||
static void buffer_handle_drm_syncobj_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
|
||||
struct wlr_wl_buffer *buffer = wl_container_of(waiter, buffer, drm_syncobj_waiter);
|
||||
buffer_remove_drm_syncobj_waiter(buffer);
|
||||
buffer_release(buffer);
|
||||
}
|
||||
|
||||
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_wl_buffer *buffer =
|
||||
|
|
@ -176,6 +204,30 @@ static bool test_buffer(struct wlr_wl_backend *wl,
|
|||
}
|
||||
}
|
||||
|
||||
struct dmabuf_listener_data {
|
||||
struct wl_buffer *wl_buffer;
|
||||
bool done;
|
||||
};
|
||||
|
||||
static void dmabuf_handle_created(void *data_, struct zwp_linux_buffer_params_v1 *params,
|
||||
struct wl_buffer *buffer) {
|
||||
struct dmabuf_listener_data *data = data_;
|
||||
data->wl_buffer = buffer;
|
||||
data->done = true;
|
||||
wlr_log(WLR_DEBUG, "DMA-BUF imported into parent Wayland compositor");
|
||||
}
|
||||
|
||||
static void dmabuf_handle_failed(void *data_, struct zwp_linux_buffer_params_v1 *params) {
|
||||
struct dmabuf_listener_data *data = data_;
|
||||
data->done = true;
|
||||
wlr_log(WLR_ERROR, "Failed to import DMA-BUF into parent Wayland compositor");
|
||||
}
|
||||
|
||||
static const struct zwp_linux_buffer_params_v1_listener dmabuf_listener = {
|
||||
.created = dmabuf_handle_created,
|
||||
.failed = dmabuf_handle_failed,
|
||||
};
|
||||
|
||||
static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
|
||||
struct wlr_dmabuf_attributes *dmabuf) {
|
||||
uint32_t modifier_hi = dmabuf->modifier >> 32;
|
||||
|
|
@ -187,18 +239,35 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
|
|||
dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
|
||||
}
|
||||
|
||||
struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
|
||||
params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
|
||||
struct dmabuf_listener_data data = {0};
|
||||
zwp_linux_buffer_params_v1_add_listener(params, &dmabuf_listener, &data);
|
||||
zwp_linux_buffer_params_v1_create(params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
|
||||
|
||||
struct wl_event_queue *display_queue =
|
||||
wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
|
||||
wl_proxy_set_queue((struct wl_proxy *)params, wl->busy_loop_queue);
|
||||
|
||||
while (!data.done) {
|
||||
if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) < 0) {
|
||||
wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct wl_buffer *buffer = data.wl_buffer;
|
||||
if (buffer != NULL) {
|
||||
wl_proxy_set_queue((struct wl_proxy *)buffer, display_queue);
|
||||
}
|
||||
|
||||
zwp_linux_buffer_params_v1_destroy(params);
|
||||
// TODO: handle create() errors
|
||||
return wl_buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
|
||||
struct wlr_shm_attributes *shm) {
|
||||
enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
|
||||
uint32_t size = shm->stride * shm->height;
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size);
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, shm->offset + size);
|
||||
if (pool == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -262,6 +331,58 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
|
|||
return create_wl_buffer(wl, wlr_buffer);
|
||||
}
|
||||
|
||||
void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline) {
|
||||
wp_linux_drm_syncobj_timeline_v1_destroy(timeline->wl);
|
||||
wlr_addon_finish(&timeline->addon);
|
||||
wl_list_remove(&timeline->link);
|
||||
free(timeline);
|
||||
}
|
||||
|
||||
static void drm_syncobj_timeline_addon_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
|
||||
destroy_wl_drm_syncobj_timeline(timeline);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface drm_syncobj_timeline_addon_impl = {
|
||||
.name = "wlr_wl_drm_syncobj_timeline",
|
||||
.destroy = drm_syncobj_timeline_addon_destroy,
|
||||
};
|
||||
|
||||
static struct wlr_wl_drm_syncobj_timeline *get_or_create_drm_syncobj_timeline(
|
||||
struct wlr_wl_backend *wl, struct wlr_drm_syncobj_timeline *wlr_timeline) {
|
||||
struct wlr_addon *addon =
|
||||
wlr_addon_find(&wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
|
||||
if (addon != NULL) {
|
||||
struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
|
||||
return timeline;
|
||||
}
|
||||
|
||||
struct wlr_wl_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
|
||||
if (timeline == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timeline->base = wlr_timeline;
|
||||
|
||||
int fd = wlr_drm_syncobj_timeline_export(wlr_timeline);
|
||||
if (fd < 0) {
|
||||
free(timeline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timeline->wl = wp_linux_drm_syncobj_manager_v1_import_timeline(wl->drm_syncobj_manager_v1, fd);
|
||||
close(fd);
|
||||
if (timeline->wl == NULL) {
|
||||
free(timeline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_addon_init(&timeline->addon, &wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
|
||||
wl_list_insert(&wl->drm_syncobj_timelines, &timeline->link);
|
||||
|
||||
return timeline;
|
||||
}
|
||||
|
||||
static bool update_title(struct wlr_wl_output *output, const char *title) {
|
||||
struct wlr_output *wlr_output = &output->wlr_output;
|
||||
|
||||
|
|
@ -301,6 +422,28 @@ static bool output_test(struct wlr_output *wlr_output,
|
|||
struct wlr_wl_output *output =
|
||||
get_wl_output_from_output(wlr_output);
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
// If the size doesn't match, reject buffer (scaling is not currently
|
||||
// supported but could be implemented with viewporter)
|
||||
int pending_width, pending_height;
|
||||
output_pending_resolution(wlr_output, state,
|
||||
&pending_width, &pending_height);
|
||||
if (state->buffer->width != pending_width ||
|
||||
state->buffer->height != pending_height) {
|
||||
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
|
||||
return false;
|
||||
}
|
||||
// Source crop is also not currently supported
|
||||
struct wlr_fbox src_box;
|
||||
output_state_get_buffer_src_box(state, &src_box);
|
||||
if (src_box.x != 0.0 || src_box.y != 0.0 ||
|
||||
src_box.width != (double)state->buffer->width ||
|
||||
src_box.height != (double)state->buffer->height) {
|
||||
wlr_log(WLR_DEBUG, "Source crop not supported in wayland output");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
|
||||
if (unsupported != 0) {
|
||||
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
|
||||
|
|
@ -334,6 +477,21 @@ static bool output_test(struct wlr_output *wlr_output,
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) &&
|
||||
!(state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE)) {
|
||||
wlr_log(WLR_DEBUG, "Signal timeline requires a wait timeline");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) ||
|
||||
(state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) {
|
||||
struct wlr_dmabuf_attributes dmabuf;
|
||||
if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
|
||||
wlr_log(WLR_DEBUG, "Wait/signal timelines require DMA-BUFs");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
// If we can't use a sub-surface for a layer, then we can't use a
|
||||
// sub-surface for any layer underneath
|
||||
|
|
@ -565,15 +723,15 @@ static const struct wl_callback_listener unmap_callback_listener = {
|
|||
.done = unmap_callback_handle_done,
|
||||
};
|
||||
|
||||
static bool output_commit(struct wlr_output *wlr_output,
|
||||
const struct wlr_output_state *state) {
|
||||
struct wlr_wl_output *output =
|
||||
get_wl_output_from_output(wlr_output);
|
||||
static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) {
|
||||
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
|
||||
|
||||
if (!output_test(wlr_output, state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_wl_backend *wl = output->backend;
|
||||
|
||||
bool pending_enabled = output_pending_enabled(wlr_output, state);
|
||||
|
||||
if (wlr_output->enabled && !pending_enabled) {
|
||||
|
|
@ -598,15 +756,28 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
wl_surface_commit(output->surface);
|
||||
output->initialized = true;
|
||||
|
||||
wl_display_flush(output->backend->remote_display);
|
||||
struct wl_event_queue *display_queue =
|
||||
wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
|
||||
wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, wl->busy_loop_queue);
|
||||
wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, wl->busy_loop_queue);
|
||||
|
||||
wl_display_flush(wl->remote_display);
|
||||
while (!output->configured) {
|
||||
if (wl_display_dispatch(output->backend->remote_display) == -1) {
|
||||
wlr_log(WLR_ERROR, "wl_display_dispatch() failed");
|
||||
return false;
|
||||
if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) == -1) {
|
||||
wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, display_queue);
|
||||
wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, display_queue);
|
||||
|
||||
if (!output->configured) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_wl_buffer *buffer = NULL;
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
const pixman_region32_t *damage = NULL;
|
||||
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||
|
|
@ -614,8 +785,7 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
}
|
||||
|
||||
struct wlr_buffer *wlr_buffer = state->buffer;
|
||||
struct wlr_wl_buffer *buffer =
|
||||
get_or_create_wl_buffer(output->backend, wlr_buffer);
|
||||
buffer = get_or_create_wl_buffer(wl, wlr_buffer);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -624,6 +794,63 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
damage_surface(output->surface, damage);
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
struct wlr_wl_drm_syncobj_timeline *wait_timeline =
|
||||
get_or_create_drm_syncobj_timeline(wl, state->wait_timeline);
|
||||
|
||||
struct wlr_wl_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
if (state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
signal_timeline = get_or_create_drm_syncobj_timeline(wl, state->signal_timeline);
|
||||
signal_point = state->signal_point;
|
||||
} else {
|
||||
if (buffer->fallback_signal_timeline == NULL) {
|
||||
buffer->fallback_signal_timeline =
|
||||
wlr_drm_syncobj_timeline_create(wl->drm_fd);
|
||||
if (buffer->fallback_signal_timeline == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
signal_timeline =
|
||||
get_or_create_drm_syncobj_timeline(wl, buffer->fallback_signal_timeline);
|
||||
signal_point = ++buffer->fallback_signal_point;
|
||||
}
|
||||
|
||||
if (wait_timeline == NULL || signal_timeline == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (output->drm_syncobj_surface_v1 == NULL) {
|
||||
output->drm_syncobj_surface_v1 = wp_linux_drm_syncobj_manager_v1_get_surface(
|
||||
wl->drm_syncobj_manager_v1, output->surface);
|
||||
if (output->drm_syncobj_surface_v1 == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t wait_point_hi = state->wait_point >> 32;
|
||||
uint32_t wait_point_lo = state->wait_point & UINT32_MAX;
|
||||
uint32_t signal_point_hi = signal_point >> 32;
|
||||
uint32_t signal_point_lo = signal_point & UINT32_MAX;
|
||||
|
||||
wp_linux_drm_syncobj_surface_v1_set_acquire_point(output->drm_syncobj_surface_v1,
|
||||
wait_timeline->wl, wait_point_hi, wait_point_lo);
|
||||
wp_linux_drm_syncobj_surface_v1_set_release_point(output->drm_syncobj_surface_v1,
|
||||
signal_timeline->wl, signal_point_hi, signal_point_lo);
|
||||
|
||||
if (!wlr_drm_syncobj_timeline_waiter_init(&buffer->drm_syncobj_waiter,
|
||||
signal_timeline->base, signal_point, 0, wl->event_loop,
|
||||
buffer_handle_drm_syncobj_ready)) {
|
||||
return false;
|
||||
}
|
||||
buffer->has_drm_syncobj_waiter = true;
|
||||
} else {
|
||||
if (output->drm_syncobj_surface_v1 != NULL) {
|
||||
wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
|
||||
output->drm_syncobj_surface_v1 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
|
||||
!commit_layers(output, state->layers, state->layers_len)) {
|
||||
return false;
|
||||
|
|
@ -637,9 +864,8 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
||||
|
||||
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||
if (output->backend->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||
output->surface);
|
||||
if (wl->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(wl->presentation, output->surface);
|
||||
}
|
||||
|
||||
if (output->has_configure_serial) {
|
||||
|
|
@ -672,7 +898,7 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
}
|
||||
}
|
||||
|
||||
wl_display_flush(output->backend->remote_display);
|
||||
wl_display_flush(wl->remote_display);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -728,6 +954,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_output_finish(wlr_output);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
if (output->cursor.surface) {
|
||||
|
|
@ -748,6 +976,9 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
wl_callback_destroy(output->unmap_callback);
|
||||
}
|
||||
|
||||
if (output->drm_syncobj_surface_v1) {
|
||||
wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
|
||||
}
|
||||
if (output->zxdg_toplevel_decoration_v1) {
|
||||
zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
|
||||
}
|
||||
|
|
@ -824,6 +1055,12 @@ static void xdg_surface_handle_configure(void *data,
|
|||
output->has_configure_serial = true;
|
||||
output->configure_serial = serial;
|
||||
|
||||
if (!output->wlr_output.enabled) {
|
||||
// We're waiting for a configure event after an initial commit to enable
|
||||
// the output. Do not notify the compositor about the requested state.
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
wlr_output_state_set_custom_mode(&state, req_width, req_height, 0);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
|||
.state = state,
|
||||
.time_msec = time,
|
||||
};
|
||||
wl_signal_emit_mutable(&pointer->wlr_pointer.events.button, &event);
|
||||
wlr_pointer_notify_button(&pointer->wlr_pointer, &event);
|
||||
}
|
||||
|
||||
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
||||
|
|
|
|||
|
|
@ -27,12 +27,14 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
|
|||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
|
||||
struct wlr_keyboard *keyboard = data;
|
||||
|
||||
int64_t time_msec = get_current_time_msec();
|
||||
|
||||
uint32_t *keycode_ptr;
|
||||
wl_array_for_each(keycode_ptr, keys) {
|
||||
struct wlr_keyboard_key_event event = {
|
||||
.keycode = *keycode_ptr,
|
||||
.state = WL_KEYBOARD_KEY_STATE_PRESSED,
|
||||
.time_msec = get_current_time_msec(),
|
||||
.time_msec = time_msec,
|
||||
.update_state = false,
|
||||
};
|
||||
wlr_keyboard_notify_key(keyboard, &event);
|
||||
|
|
@ -43,18 +45,12 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
|||
uint32_t serial, struct wl_surface *surface) {
|
||||
struct wlr_keyboard *keyboard = data;
|
||||
|
||||
size_t num_keycodes = keyboard->num_keycodes;
|
||||
uint32_t pressed[num_keycodes + 1];
|
||||
memcpy(pressed, keyboard->keycodes,
|
||||
num_keycodes * sizeof(uint32_t));
|
||||
|
||||
for (size_t i = 0; i < num_keycodes; ++i) {
|
||||
uint32_t keycode = pressed[i];
|
||||
|
||||
int64_t time_msec = get_current_time_msec();
|
||||
while (keyboard->num_keycodes > 0) {
|
||||
struct wlr_keyboard_key_event event = {
|
||||
.keycode = keycode,
|
||||
.keycode = keyboard->keycodes[keyboard->num_keycodes - 1],
|
||||
.state = WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
.time_msec = get_current_time_msec(),
|
||||
.time_msec = time_msec,
|
||||
.update_state = false,
|
||||
};
|
||||
wlr_keyboard_notify_key(keyboard, &event);
|
||||
|
|
|
|||
|
|
@ -212,17 +212,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
return x11->drm_fd;
|
||||
}
|
||||
|
||||
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
|
||||
struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend);
|
||||
return (x11->have_dri3 ? WLR_BUFFER_CAP_DMABUF : 0)
|
||||
| (x11->have_shm ? WLR_BUFFER_CAP_SHM : 0);
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = get_buffer_caps,
|
||||
};
|
||||
|
||||
bool wlr_backend_is_x11(struct wlr_backend *backend) {
|
||||
|
|
@ -409,7 +402,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
|
|||
wl_list_init(&x11->outputs);
|
||||
|
||||
x11->xcb = xcb_connect(x11_display, NULL);
|
||||
if (!x11->xcb || xcb_connection_has_error(x11->xcb)) {
|
||||
if (xcb_connection_has_error(x11->xcb)) {
|
||||
wlr_log(WLR_ERROR, "Failed to open xcb connection");
|
||||
goto error_x11;
|
||||
}
|
||||
|
|
@ -512,7 +505,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
|
|||
xcb_present_query_version(x11->xcb, 1, 2);
|
||||
xcb_present_query_version_reply_t *present_reply =
|
||||
xcb_present_query_version_reply(x11->xcb, present_cookie, NULL);
|
||||
if (!present_reply || present_reply->major_version < 1) {
|
||||
if (!present_reply) {
|
||||
wlr_log(WLR_ERROR, "Failed to query Present version");
|
||||
goto error_display;
|
||||
} else if (present_reply->major_version < 1) {
|
||||
wlr_log(WLR_ERROR, "X11 does not support required Present version "
|
||||
"(has %"PRIu32".%"PRIu32", want 1.0)",
|
||||
present_reply->major_version, present_reply->minor_version);
|
||||
|
|
@ -533,7 +529,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
|
|||
xcb_xfixes_query_version(x11->xcb, 4, 0);
|
||||
xcb_xfixes_query_version_reply_t *fixes_reply =
|
||||
xcb_xfixes_query_version_reply(x11->xcb, fixes_cookie, NULL);
|
||||
if (!fixes_reply || fixes_reply->major_version < 4) {
|
||||
if (!fixes_reply) {
|
||||
wlr_log(WLR_ERROR, "Failed to query Xfixes version");
|
||||
goto error_display;
|
||||
} else if (fixes_reply->major_version < 4) {
|
||||
wlr_log(WLR_ERROR, "X11 does not support required Xfixes version "
|
||||
"(has %"PRIu32".%"PRIu32", want 4.0)",
|
||||
fixes_reply->major_version, fixes_reply->minor_version);
|
||||
|
|
@ -555,7 +554,10 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
|
|||
xcb_input_xi_query_version(x11->xcb, 2, 0);
|
||||
xcb_input_xi_query_version_reply_t *xi_reply =
|
||||
xcb_input_xi_query_version_reply(x11->xcb, xi_cookie, NULL);
|
||||
if (!xi_reply || xi_reply->major_version < 2) {
|
||||
if (!xi_reply) {
|
||||
wlr_log(WLR_ERROR, "Failed to query Xinput version");
|
||||
goto error_display;
|
||||
} else if (xi_reply->major_version < 2) {
|
||||
wlr_log(WLR_ERROR, "X11 does not support required Xinput version "
|
||||
"(has %"PRIu32".%"PRIu32", want 2.0)",
|
||||
xi_reply->major_version, xi_reply->minor_version);
|
||||
|
|
@ -564,6 +566,13 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
|
|||
}
|
||||
free(xi_reply);
|
||||
|
||||
if (x11->have_dri3) {
|
||||
x11->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
|
||||
}
|
||||
if (x11->have_shm) {
|
||||
x11->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
|
||||
}
|
||||
|
||||
int fd = xcb_get_file_descriptor(x11->xcb);
|
||||
uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
|
||||
x11->event_source = wl_event_loop_add_fd(loop, fd, events, x11_event, x11);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ static void send_button_event(struct wlr_x11_output *output, uint32_t key,
|
|||
.button = key,
|
||||
.state = st,
|
||||
};
|
||||
wl_signal_emit_mutable(&output->pointer.events.button, &ev);
|
||||
wlr_pointer_notify_button(&output->pointer, &ev);
|
||||
wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
|
|||
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
|
||||
struct wlr_x11_backend *x11 = output->x11;
|
||||
|
||||
wlr_output_finish(wlr_output);
|
||||
|
||||
pixman_region32_fini(&output->exposed);
|
||||
|
||||
wlr_pointer_finish(&output->pointer);
|
||||
|
|
@ -129,6 +131,27 @@ static bool output_test(struct wlr_output *wlr_output,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
// If the size doesn't match, reject buffer (scaling is not supported)
|
||||
int pending_width, pending_height;
|
||||
output_pending_resolution(wlr_output, state,
|
||||
&pending_width, &pending_height);
|
||||
if (state->buffer->width != pending_width ||
|
||||
state->buffer->height != pending_height) {
|
||||
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
|
||||
return false;
|
||||
}
|
||||
// Source crop is not supported
|
||||
struct wlr_fbox src_box;
|
||||
output_state_get_buffer_src_box(state, &src_box);
|
||||
if (src_box.x != 0.0 || src_box.y != 0.0 ||
|
||||
src_box.width != (double)state->buffer->width ||
|
||||
src_box.height != (double)state->buffer->height) {
|
||||
wlr_log(WLR_DEBUG, "Source crop not supported in X11 output");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All we can do to influence adaptive sync on the X11 backend is set the
|
||||
// _VARIABLE_REFRESH window property like mesa automatically does. We don't
|
||||
// have any control beyond that, so we set the state to enabled on creating
|
||||
|
|
@ -747,9 +770,6 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
|
|||
|
||||
output->last_msc = complete_notify->msc;
|
||||
|
||||
struct timespec t;
|
||||
timespec_from_nsec(&t, complete_notify->ust * 1000);
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
|
||||
flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
||||
|
|
@ -760,10 +780,10 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
|
|||
.output = &output->wlr_output,
|
||||
.commit_seq = complete_notify->serial,
|
||||
.presented = presented,
|
||||
.when = &t,
|
||||
.seq = complete_notify->msc,
|
||||
.flags = flags,
|
||||
};
|
||||
timespec_from_nsec(&present_event.when, complete_notify->ust * 1000);
|
||||
wlr_output_send_present(&output->wlr_output, &present_event);
|
||||
|
||||
wlr_output_send_frame(&output->wlr_output);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ wlroots reads these environment variables
|
|||
renderers: gles2, pixman, vulkan)
|
||||
* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
|
||||
hardware-accelerated renderers.
|
||||
* *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization
|
||||
support in renderers.
|
||||
* *WLR_RENDERER_FORCE_SOFTWARE*: set to 1 to force software rendering for GLES2
|
||||
and Vulkan
|
||||
* *WLR_EGL_NO_MODIFIERS*: set to 1 to disable format modifiers in EGL, this can
|
||||
be used to understand and work around driver bugs.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ struct cairo_buffer {
|
|||
|
||||
static void cairo_buffer_destroy(struct wlr_buffer *wlr_buffer) {
|
||||
struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
wlr_buffer_finish(wlr_buffer);
|
||||
cairo_surface_destroy(buffer->surface);
|
||||
free(buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,258 +0,0 @@
|
|||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_fullscreen_shell_v1.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/transform.h>
|
||||
|
||||
/**
|
||||
* A minimal fullscreen-shell server. It only supports rendering.
|
||||
*/
|
||||
|
||||
struct fullscreen_server {
|
||||
struct wl_display *wl_display;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
|
||||
struct wlr_fullscreen_shell_v1 *fullscreen_shell;
|
||||
struct wl_listener present_surface;
|
||||
|
||||
struct wlr_output_layout *output_layout;
|
||||
struct wl_list outputs;
|
||||
struct wl_listener new_output;
|
||||
};
|
||||
|
||||
struct fullscreen_output {
|
||||
struct wl_list link;
|
||||
struct fullscreen_server *server;
|
||||
struct wlr_output *wlr_output;
|
||||
struct wlr_surface *surface;
|
||||
struct wl_listener surface_destroy;
|
||||
|
||||
struct wl_listener frame;
|
||||
};
|
||||
|
||||
struct render_data {
|
||||
struct wlr_output *output;
|
||||
struct wlr_render_pass *render_pass;
|
||||
struct timespec *when;
|
||||
};
|
||||
|
||||
static void render_surface(struct wlr_surface *surface,
|
||||
int sx, int sy, void *data) {
|
||||
struct render_data *rdata = data;
|
||||
struct wlr_output *output = rdata->output;
|
||||
|
||||
struct wlr_texture *texture = wlr_surface_get_texture(surface);
|
||||
if (texture == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_box box = {
|
||||
.x = sx * output->scale,
|
||||
.y = sy * output->scale,
|
||||
.width = surface->current.width * output->scale,
|
||||
.height = surface->current.height * output->scale,
|
||||
};
|
||||
|
||||
enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform);
|
||||
transform = wlr_output_transform_compose(transform, output->transform);
|
||||
|
||||
wlr_render_pass_add_texture(rdata->render_pass, &(struct wlr_render_texture_options){
|
||||
.texture = texture,
|
||||
.dst_box = box,
|
||||
.transform = transform,
|
||||
});
|
||||
|
||||
wlr_surface_send_frame_done(surface, rdata->when);
|
||||
}
|
||||
|
||||
static void output_handle_frame(struct wl_listener *listener, void *data) {
|
||||
struct fullscreen_output *output =
|
||||
wl_container_of(listener, output, frame);
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
int width, height;
|
||||
wlr_output_effective_resolution(output->wlr_output, &width, &height);
|
||||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &state, NULL,
|
||||
NULL);
|
||||
if (pass == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.color = { 0.3, 0.3, 0.3, 1.0 },
|
||||
.box = { .width = width, .height = height },
|
||||
});
|
||||
|
||||
if (output->surface != NULL) {
|
||||
struct render_data rdata = {
|
||||
.output = output->wlr_output,
|
||||
.render_pass = pass,
|
||||
.when = &now,
|
||||
};
|
||||
wlr_surface_for_each_surface(output->surface, render_surface, &rdata);
|
||||
}
|
||||
|
||||
wlr_render_pass_submit(pass);
|
||||
wlr_output_commit_state(output->wlr_output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
}
|
||||
|
||||
static void output_set_surface(struct fullscreen_output *output,
|
||||
struct wlr_surface *surface);
|
||||
|
||||
static void output_handle_surface_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct fullscreen_output *output =
|
||||
wl_container_of(listener, output, surface_destroy);
|
||||
output_set_surface(output, NULL);
|
||||
}
|
||||
|
||||
static void output_set_surface(struct fullscreen_output *output,
|
||||
struct wlr_surface *surface) {
|
||||
if (output->surface == surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->surface != NULL) {
|
||||
wl_list_remove(&output->surface_destroy.link);
|
||||
output->surface = NULL;
|
||||
}
|
||||
|
||||
if (surface != NULL) {
|
||||
output->surface_destroy.notify = output_handle_surface_destroy;
|
||||
wl_signal_add(&surface->events.destroy, &output->surface_destroy);
|
||||
output->surface = surface;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Presenting surface %p on output %s",
|
||||
surface, output->wlr_output->name);
|
||||
}
|
||||
|
||||
static void server_handle_new_output(struct wl_listener *listener, void *data) {
|
||||
struct fullscreen_server *server =
|
||||
wl_container_of(listener, server, new_output);
|
||||
struct wlr_output *wlr_output = data;
|
||||
|
||||
wlr_output_init_render(wlr_output, server->allocator, server->renderer);
|
||||
|
||||
struct fullscreen_output *output = calloc(1, sizeof(*output));
|
||||
output->wlr_output = wlr_output;
|
||||
output->server = server;
|
||||
output->frame.notify = output_handle_frame;
|
||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||
wl_list_insert(&server->outputs, &output->link);
|
||||
|
||||
wlr_output_layout_add_auto(server->output_layout, wlr_output);
|
||||
wlr_output_create_global(wlr_output, server->wl_display);
|
||||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
wlr_output_state_set_enabled(&state, true);
|
||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
||||
if (mode != NULL) {
|
||||
wlr_output_state_set_mode(&state, mode);
|
||||
}
|
||||
wlr_output_commit_state(wlr_output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
}
|
||||
|
||||
static void server_handle_present_surface(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct fullscreen_server *server =
|
||||
wl_container_of(listener, server, present_surface);
|
||||
struct wlr_fullscreen_shell_v1_present_surface_event *event = data;
|
||||
|
||||
struct fullscreen_output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
if (event->output == NULL || event->output == output->wlr_output) {
|
||||
output_set_surface(output, event->surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
wlr_log_init(WLR_DEBUG, NULL);
|
||||
|
||||
char *startup_cmd = NULL;
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "s:")) != -1) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
startup_cmd = optarg;
|
||||
break;
|
||||
default:
|
||||
printf("usage: %s [-s startup-command]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (optind < argc) {
|
||||
printf("usage: %s [-s startup-command]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct fullscreen_server server = {0};
|
||||
server.wl_display = wl_display_create();
|
||||
server.backend = wlr_backend_autocreate(wl_display_get_event_loop(server.wl_display), NULL);
|
||||
server.renderer = wlr_renderer_autocreate(server.backend);
|
||||
wlr_renderer_init_wl_display(server.renderer, server.wl_display);
|
||||
server.allocator = wlr_allocator_autocreate(server.backend,
|
||||
server.renderer);
|
||||
|
||||
wlr_compositor_create(server.wl_display, 5, server.renderer);
|
||||
|
||||
server.output_layout = wlr_output_layout_create(server.wl_display);
|
||||
|
||||
wl_list_init(&server.outputs);
|
||||
server.new_output.notify = server_handle_new_output;
|
||||
wl_signal_add(&server.backend->events.new_output, &server.new_output);
|
||||
|
||||
server.fullscreen_shell = wlr_fullscreen_shell_v1_create(server.wl_display);
|
||||
server.present_surface.notify = server_handle_present_surface;
|
||||
wl_signal_add(&server.fullscreen_shell->events.present_surface,
|
||||
&server.present_surface);
|
||||
|
||||
const char *socket = wl_display_add_socket_auto(server.wl_display);
|
||||
if (!socket) {
|
||||
wl_display_destroy(server.wl_display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!wlr_backend_start(server.backend)) {
|
||||
wl_display_destroy(server.wl_display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
setenv("WAYLAND_DISPLAY", socket, true);
|
||||
if (startup_cmd != NULL) {
|
||||
if (fork() == 0) {
|
||||
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
|
||||
socket);
|
||||
wl_display_run(server.wl_display);
|
||||
|
||||
wl_display_destroy_clients(server.wl_display);
|
||||
wl_display_destroy(server.wl_display);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -25,10 +25,6 @@ compositors = {
|
|||
'output-layout': {
|
||||
'src': ['output-layout.c', 'cat.c'],
|
||||
},
|
||||
'fullscreen-shell': {
|
||||
'src': 'fullscreen-shell.c',
|
||||
'proto': ['fullscreen-shell-unstable-v1'],
|
||||
},
|
||||
'scene-graph': {
|
||||
'src': 'scene-graph.c',
|
||||
'proto': ['xdg-shell'],
|
||||
|
|
|
|||
|
|
@ -87,16 +87,14 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
|
|||
layers_arr.size / sizeof(struct wlr_output_layer_state));
|
||||
|
||||
if (!wlr_output_test_state(output->wlr_output, &output_state)) {
|
||||
wlr_log(WLR_ERROR, "wlr_output_test() failed");
|
||||
wlr_log(WLR_ERROR, "wlr_output_test_state() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
wlr_output_effective_resolution(output->wlr_output, &width, &height);
|
||||
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state,
|
||||
NULL, NULL);
|
||||
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state, NULL);
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = width, .height = height },
|
||||
.color = { 0.3, 0.3, 0.3, 1 },
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state output_state;
|
||||
wlr_output_state_init(&output_state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
|
||||
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = wlr_output->width, .height = wlr_output->height },
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state output_state;
|
||||
wlr_output_state_init(&output_state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = wlr_output->width, .height = wlr_output->height },
|
||||
.color = {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state output_state;
|
||||
wlr_output_state_init(&output_state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
|
||||
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = wlr_output->width, .height = wlr_output->height },
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state state;
|
||||
wlr_output_state_init(&state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL);
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = wlr_output->width, .height = wlr_output->height },
|
||||
.color = {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state output_state;
|
||||
wlr_output_state_init(&output_state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
|
||||
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = wlr_output->width, .height = wlr_output->height },
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
struct wlr_output_state output_state;
|
||||
wlr_output_state_init(&output_state);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
|
||||
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
|
||||
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
|
||||
.box = { .width = width, .height = height },
|
||||
.color = { 0.25, 0.25, 0.25, 1 },
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef BACKEND_WLR_BACKEND_H
|
||||
#define BACKEND_WLR_BACKEND_H
|
||||
|
||||
#include <wlr/backend.h>
|
||||
|
||||
/**
|
||||
* Get the supported buffer capabilities.
|
||||
*
|
||||
* This functions returns a bitfield of supported wlr_buffer_cap.
|
||||
*/
|
||||
uint32_t backend_get_buffer_caps(struct wlr_backend *backend);
|
||||
|
||||
#endif
|
||||
|
|
@ -15,6 +15,11 @@
|
|||
#include "backend/drm/properties.h"
|
||||
#include "backend/drm/renderer.h"
|
||||
|
||||
struct wlr_drm_viewport {
|
||||
struct wlr_fbox src_box;
|
||||
struct wlr_box dst_box;
|
||||
};
|
||||
|
||||
struct wlr_drm_plane {
|
||||
uint32_t type;
|
||||
uint32_t id;
|
||||
|
|
@ -26,6 +31,8 @@ struct wlr_drm_plane {
|
|||
struct wlr_drm_fb *queued_fb;
|
||||
/* Buffer currently displayed on screen */
|
||||
struct wlr_drm_fb *current_fb;
|
||||
/* Viewport belonging to the last committed fb */
|
||||
struct wlr_drm_viewport viewport;
|
||||
|
||||
struct wlr_drm_format_set formats;
|
||||
|
||||
|
|
@ -139,13 +146,20 @@ struct wlr_drm_connector_state {
|
|||
bool active;
|
||||
drmModeModeInfo mode;
|
||||
struct wlr_drm_fb *primary_fb;
|
||||
struct wlr_drm_viewport primary_viewport;
|
||||
struct wlr_drm_fb *cursor_fb;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
|
||||
// used by atomic
|
||||
uint32_t mode_id;
|
||||
uint32_t gamma_lut;
|
||||
uint32_t fb_damage_clips;
|
||||
int primary_in_fence_fd, out_fence_fd;
|
||||
bool vrr_enabled;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -164,6 +178,8 @@ struct wlr_drm_page_flip {
|
|||
struct wl_list link; // wlr_drm_connector.page_flips
|
||||
struct wlr_drm_page_flip_connector *connectors;
|
||||
size_t connectors_len;
|
||||
// True if DRM_MODE_PAGE_FLIP_ASYNC was set
|
||||
bool async;
|
||||
};
|
||||
|
||||
struct wlr_drm_page_flip_connector {
|
||||
|
|
@ -198,6 +214,10 @@ struct wlr_drm_connector {
|
|||
// Last committed page-flip
|
||||
struct wlr_drm_page_flip *pending_page_flip;
|
||||
|
||||
// Atomic modesetting only
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
|
||||
int32_t refresh;
|
||||
};
|
||||
|
||||
|
|
@ -211,7 +231,6 @@ void scan_drm_connectors(struct wlr_drm_backend *state,
|
|||
void scan_drm_leases(struct wlr_drm_backend *drm);
|
||||
bool commit_drm_device(struct wlr_drm_backend *drm,
|
||||
const struct wlr_backend_output_state *states, size_t states_len, bool test_only);
|
||||
void restore_drm_device(struct wlr_drm_backend *drm);
|
||||
int handle_drm_event(int fd, uint32_t mask, void *data);
|
||||
void destroy_drm_connector(struct wlr_drm_connector *conn);
|
||||
bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
#define BACKEND_DRM_FB_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
struct wlr_drm_format_set;
|
||||
|
||||
struct wlr_drm_fb {
|
||||
struct wlr_buffer *wlr_buf;
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ struct wlr_drm_interface {
|
|||
bool (*commit)(struct wlr_drm_backend *drm,
|
||||
const struct wlr_drm_device_state *state,
|
||||
struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only);
|
||||
// Turn off everything
|
||||
bool (*reset)(struct wlr_drm_backend *drm);
|
||||
};
|
||||
|
||||
extern const struct wlr_drm_interface atomic_iface;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ struct wlr_drm_connector_props {
|
|||
// atomic-modesetting only
|
||||
|
||||
uint32_t crtc_id;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
};
|
||||
|
||||
struct wlr_drm_crtc_props {
|
||||
|
|
@ -38,6 +40,7 @@ struct wlr_drm_crtc_props {
|
|||
|
||||
uint32_t active;
|
||||
uint32_t mode_id;
|
||||
uint32_t out_fence_ptr;
|
||||
};
|
||||
|
||||
struct wlr_drm_plane_props {
|
||||
|
|
@ -61,6 +64,7 @@ struct wlr_drm_plane_props {
|
|||
uint32_t fb_damage_clips;
|
||||
uint32_t hotspot_x;
|
||||
uint32_t hotspot_y;
|
||||
uint32_t in_fence_fd;
|
||||
};
|
||||
|
||||
bool get_drm_connector_props(int fd, uint32_t id,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ struct wlr_drm_renderer {
|
|||
struct wlr_drm_surface {
|
||||
struct wlr_drm_renderer *renderer;
|
||||
struct wlr_swapchain *swapchain;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *timeline;
|
||||
uint64_t point;
|
||||
};
|
||||
|
||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||
|
|
@ -32,7 +35,8 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
|
|||
void finish_drm_surface(struct wlr_drm_surface *surf);
|
||||
|
||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
||||
struct wlr_buffer *buffer);
|
||||
struct wlr_buffer *buffer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
|
||||
|
||||
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);
|
||||
|
|
|
|||
|
|
@ -18,26 +18,24 @@ const char *drm_connector_status_str(drmModeConnection status);
|
|||
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
|
||||
float vrefresh);
|
||||
|
||||
// Part of match_obj
|
||||
enum {
|
||||
UNMATCHED = (uint32_t)-1,
|
||||
SKIP = (uint32_t)-2,
|
||||
};
|
||||
// Part of match_connectors_with_crtcs
|
||||
#define UNMATCHED ((uint32_t)-1)
|
||||
|
||||
/*
|
||||
* Tries to match some DRM objects with some other DRM resource.
|
||||
* e.g. Match CRTCs with Encoders, CRTCs with Planes.
|
||||
/**
|
||||
* Tries to match DRM connectors with DRM CRTCs.
|
||||
*
|
||||
* objs contains a bit array which resources it can be matched with.
|
||||
* e.g. Bit 0 set means can be matched with res[0]
|
||||
* conns contains an array of bitmasks describing compatible CRTCs. For
|
||||
* instance bit 0 set in an connector element means that it's compatible with
|
||||
* CRTC 0.
|
||||
*
|
||||
* res contains an index of which objs it is matched with or UNMATCHED.
|
||||
* prev_crtcs contains connector indices each CRTC was previously matched with,
|
||||
* or UNMATCHED.
|
||||
*
|
||||
* This solution is left in out.
|
||||
* Returns the total number of matched solutions.
|
||||
* new_crtcs is populated with the new connector indices.
|
||||
*/
|
||||
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
|
||||
size_t num_res, const uint32_t res[static restrict num_res],
|
||||
uint32_t out[static restrict num_res]);
|
||||
void match_connectors_with_crtcs(size_t num_conns,
|
||||
const uint32_t conns[static restrict num_conns],
|
||||
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
|
||||
uint32_t new_crtcs[static restrict num_crtcs]);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
struct wlr_libinput_backend {
|
||||
struct wlr_backend backend;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
|
||||
struct wlr_wl_backend {
|
||||
struct wlr_backend backend;
|
||||
|
|
@ -21,6 +22,7 @@ struct wlr_wl_backend {
|
|||
/* local state */
|
||||
bool started;
|
||||
struct wl_event_loop *event_loop;
|
||||
struct wl_event_queue *busy_loop_queue;
|
||||
struct wl_list outputs;
|
||||
int drm_fd;
|
||||
struct wl_list buffers; // wlr_wl_buffer.link
|
||||
|
|
@ -40,6 +42,8 @@ struct wlr_wl_backend {
|
|||
struct wp_presentation *presentation;
|
||||
struct wl_shm *shm;
|
||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
||||
struct wp_linux_drm_syncobj_manager_v1 *drm_syncobj_manager_v1;
|
||||
struct wl_list drm_syncobj_timelines; // wlr_wl_drm_syncobj_timeline.link
|
||||
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
|
||||
struct wl_list seats; // wlr_wl_seat.link
|
||||
struct zwp_tablet_manager_v2 *tablet_manager;
|
||||
|
|
@ -58,6 +62,19 @@ struct wlr_wl_buffer {
|
|||
bool released;
|
||||
struct wl_list link; // wlr_wl_backend.buffers
|
||||
struct wl_listener buffer_destroy;
|
||||
|
||||
bool has_drm_syncobj_waiter;
|
||||
struct wlr_drm_syncobj_timeline_waiter drm_syncobj_waiter;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *fallback_signal_timeline;
|
||||
uint64_t fallback_signal_point;
|
||||
};
|
||||
|
||||
struct wlr_wl_drm_syncobj_timeline {
|
||||
struct wlr_drm_syncobj_timeline *base;
|
||||
struct wlr_addon addon;
|
||||
struct wl_list link; // wlr_wl_backend.drm_syncobj_timelines
|
||||
struct wp_linux_drm_syncobj_timeline_v1 *wl;
|
||||
};
|
||||
|
||||
struct wlr_wl_presentation_feedback {
|
||||
|
|
@ -88,6 +105,7 @@ struct wlr_wl_output {
|
|||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
|
||||
struct wp_linux_drm_syncobj_surface_v1 *drm_syncobj_surface_v1;
|
||||
struct wl_list presentation_feedbacks;
|
||||
|
||||
char *title;
|
||||
|
|
@ -190,6 +208,7 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl,
|
|||
uint32_t global_name);
|
||||
void destroy_wl_seat(struct wlr_wl_seat *seat);
|
||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
|
||||
void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline);
|
||||
|
||||
extern const struct wlr_pointer_impl wl_pointer_impl;
|
||||
extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef RENDER_ALLOCATOR_ALLOCATOR_H
|
||||
#define RENDER_ALLOCATOR_ALLOCATOR_H
|
||||
|
||||
#include <wlr/render/allocator.h>
|
||||
|
||||
struct wlr_allocator *allocator_autocreate_with_drm_fd(
|
||||
uint32_t backend_caps, struct wlr_renderer *renderer, int drm_fd);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef RENDER_ALLOCATOR_DRM_DUMB_H
|
||||
#define RENDER_ALLOCATOR_DRM_DUMB_H
|
||||
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/dmabuf.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "render/allocator/allocator.h"
|
||||
|
||||
struct wlr_drm_dumb_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
#define RENDER_ALLOCATOR_GBM_H
|
||||
|
||||
#include <gbm.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/dmabuf.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "render/allocator/allocator.h"
|
||||
|
||||
struct wlr_gbm_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef RENDER_ALLOCATOR_SHM_H
|
||||
#define RENDER_ALLOCATOR_SHM_H
|
||||
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "render/allocator/allocator.h"
|
||||
|
||||
struct wlr_shm_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
|
|
|||
23
include/render/allocator/udmabuf.h
Normal file
23
include/render/allocator/udmabuf.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef RENDER_ALLOCATOR_UDMABUF_H
|
||||
#define RENDER_ALLOCATOR_UDMABUF_H
|
||||
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
|
||||
struct wlr_udmabuf_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
||||
size_t size;
|
||||
struct wlr_shm_attributes shm;
|
||||
struct wlr_dmabuf_attributes dmabuf;
|
||||
};
|
||||
|
||||
struct wlr_udmabuf_allocator {
|
||||
struct wlr_allocator base;
|
||||
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct wlr_allocator *wlr_udmabuf_allocator_create(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -2,30 +2,14 @@
|
|||
#define RENDER_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
/**
|
||||
* The formula is approximated via a 3D look-up table. A 3D LUT is a
|
||||
* three-dimensional array where each element is an RGB triplet. The flat lut_3d
|
||||
* array has a length of dim_len³.
|
||||
*
|
||||
* Color channel values in the range [0.0, 1.0] are mapped linearly to
|
||||
* 3D LUT indices such that 0.0 maps exactly to the first element and 1.0 maps
|
||||
* exactly to the last element in each dimension.
|
||||
*
|
||||
* The offset of the RGB triplet given red, green and blue indices r_index,
|
||||
* g_index and b_index is:
|
||||
*
|
||||
* offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index)
|
||||
*/
|
||||
struct wlr_color_transform_lut3d {
|
||||
float *lut_3d;
|
||||
size_t dim_len;
|
||||
};
|
||||
|
||||
enum wlr_color_transform_type {
|
||||
COLOR_TRANSFORM_SRGB,
|
||||
COLOR_TRANSFORM_LUT_3D,
|
||||
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||
COLOR_TRANSFORM_LCMS2,
|
||||
COLOR_TRANSFORM_LUT_3X1D,
|
||||
COLOR_TRANSFORM_PIPELINE,
|
||||
};
|
||||
|
||||
struct wlr_color_transform {
|
||||
|
|
@ -33,7 +17,84 @@ struct wlr_color_transform {
|
|||
struct wlr_addon_set addons; // per-renderer helper state
|
||||
|
||||
enum wlr_color_transform_type type;
|
||||
struct wlr_color_transform_lut3d lut3d;
|
||||
};
|
||||
|
||||
struct wlr_color_transform_inverse_eotf {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
enum wlr_color_transfer_function tf;
|
||||
};
|
||||
|
||||
/**
|
||||
* The formula is approximated via three 1D look-up tables. The flat lut_3x1d
|
||||
* array has a length of 3 * dim.
|
||||
*
|
||||
* The offset of a color value for a given channel and color index is:
|
||||
*
|
||||
* offset = channel_index * dim + color_index
|
||||
*/
|
||||
struct wlr_color_transform_lut_3x1d {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
uint16_t *lut_3x1d;
|
||||
size_t dim;
|
||||
};
|
||||
|
||||
struct wlr_color_transform_pipeline {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
struct wlr_color_transform **transforms;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
||||
enum wlr_color_transform_type type);
|
||||
|
||||
/**
|
||||
* Get a struct wlr_color_transform_lcms2 from a generic struct wlr_color_transform.
|
||||
* Asserts that the base type is COLOR_TRANSFORM_LCMS2.
|
||||
*/
|
||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a LCMS2 color transform for a given RGB triplet.
|
||||
*/
|
||||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
/**
|
||||
* Gets a wlr_color_transform_inverse_eotf from a generic wlr_color_transform.
|
||||
* Asserts that the base type is COLOR_TRANSFORM_INVERSE_EOTF
|
||||
*/
|
||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Get a struct wlr_color_transform_lut_3x1d from a generic
|
||||
* struct wlr_color_transform. Asserts that the base type is
|
||||
* COLOR_TRANSFORM_LUT_3X1D.
|
||||
*/
|
||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Obtain primaries values from a well-known primaries name.
|
||||
*/
|
||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
||||
enum wlr_color_named_primaries named);
|
||||
|
||||
/**
|
||||
* Compute the matrix to convert RGB color values to CIE 1931 XYZ.
|
||||
*/
|
||||
void wlr_color_primaries_to_xyz(const struct wlr_color_primaries *primaries, float matrix[static 9]);
|
||||
|
||||
/**
|
||||
* Get default luminances for a transfer function.
|
||||
*/
|
||||
void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_function tf,
|
||||
struct wlr_color_luminances *lum);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ struct wlr_egl {
|
|||
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
|
||||
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
|
||||
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
|
||||
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
|
||||
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
|
||||
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
|
||||
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR;
|
||||
} procs;
|
||||
|
||||
bool has_modifiers;
|
||||
|
|
@ -105,4 +109,12 @@ bool wlr_egl_make_current(struct wlr_egl *egl, struct wlr_egl_context *save_cont
|
|||
|
||||
bool wlr_egl_unset_current(struct wlr_egl *egl);
|
||||
|
||||
EGLSyncKHR wlr_egl_create_sync(struct wlr_egl *egl, int fence_fd);
|
||||
|
||||
void wlr_egl_destroy_sync(struct wlr_egl *egl, EGLSyncKHR sync);
|
||||
|
||||
int wlr_egl_dup_fence_fd(struct wlr_egl *egl, EGLSyncKHR sync);
|
||||
|
||||
bool wlr_egl_wait_sync(struct wlr_egl *egl, EGLSyncKHR sync);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include <GLES2/gl2ext.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wlr/render/egl.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
|
|
@ -138,6 +137,8 @@ struct wlr_gles2_render_pass {
|
|||
float projection_matrix[9];
|
||||
struct wlr_egl_context prev_ctx;
|
||||
struct wlr_gles2_render_timer *timer;
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
};
|
||||
|
||||
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
|
||||
|
|
@ -169,6 +170,7 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
|
|||
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
|
||||
|
||||
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
|
||||
struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer);
|
||||
struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer,
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/render/interface.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
|
@ -40,6 +41,7 @@ struct wlr_vk_device {
|
|||
|
||||
int drm_fd;
|
||||
|
||||
bool sync_file_import_export;
|
||||
bool implicit_sync_interop;
|
||||
bool sampler_ycbcr_conversion;
|
||||
|
||||
|
|
@ -150,6 +152,9 @@ struct wlr_vk_pipeline_layout {
|
|||
enum wlr_vk_texture_transform {
|
||||
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
|
||||
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
|
||||
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
|
||||
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
|
||||
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
|
||||
};
|
||||
|
||||
enum wlr_vk_shader_source {
|
||||
|
|
@ -160,8 +165,12 @@ enum wlr_vk_shader_source {
|
|||
// Constants used to pick the color transform for the blend-to-output
|
||||
// fragment shader. Must match those in shaders/output.frag
|
||||
enum wlr_vk_output_transform {
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 0,
|
||||
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 1,
|
||||
WLR_VK_OUTPUT_TRANSFORM_IDENTITY = 0,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
|
||||
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
|
||||
WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
|
||||
};
|
||||
|
||||
struct wlr_vk_pipeline_key {
|
||||
|
|
@ -190,13 +199,24 @@ struct wlr_vk_render_format_setup {
|
|||
bool use_blending_buffer;
|
||||
VkRenderPass render_pass;
|
||||
|
||||
VkPipeline output_pipe_identity;
|
||||
VkPipeline output_pipe_srgb;
|
||||
VkPipeline output_pipe_pq;
|
||||
VkPipeline output_pipe_lut3d;
|
||||
VkPipeline output_pipe_gamma22;
|
||||
VkPipeline output_pipe_bt1886;
|
||||
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wl_list pipelines; // struct wlr_vk_pipeline.link
|
||||
};
|
||||
|
||||
// Final output framebuffer and image view
|
||||
struct wlr_vk_render_buffer_out {
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
};
|
||||
|
||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
||||
struct wlr_vk_render_buffer {
|
||||
struct wlr_buffer *wlr_buffer;
|
||||
|
|
@ -208,36 +228,40 @@ struct wlr_vk_render_buffer {
|
|||
uint32_t mem_count;
|
||||
VkImage image;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image,
|
||||
// without any color transform.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
} linear;
|
||||
|
||||
// Framebuffer and image view for rendering directly onto the buffer image.
|
||||
// This requires that the image support an _SRGB VkFormat, and does
|
||||
// not work with color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
} srgb;
|
||||
|
||||
// Framebuffer, image view, and blending image to render indirectly
|
||||
// onto the buffer image. This works for general image types and permits
|
||||
// color transforms.
|
||||
struct {
|
||||
struct wlr_vk_render_buffer_out out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
bool transitioned;
|
||||
|
||||
VkImage blend_image;
|
||||
VkImageView blend_image_view;
|
||||
VkDeviceMemory blend_memory;
|
||||
VkDescriptorSet blend_descriptor_set;
|
||||
struct wlr_vk_descriptor_pool *blend_attachment_pool;
|
||||
bool blend_transitioned;
|
||||
} plain;
|
||||
} two_pass;
|
||||
};
|
||||
|
||||
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf, bool srgb);
|
||||
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
|
||||
const struct wlr_dmabuf_attributes *dmabuf);
|
||||
|
||||
struct wlr_vk_command_buffer {
|
||||
|
|
@ -253,6 +277,8 @@ struct wlr_vk_command_buffer {
|
|||
|
||||
// For DMA-BUF implicit sync interop, may be NULL
|
||||
VkSemaphore binary_semaphore;
|
||||
|
||||
struct wl_array wait_semaphores; // VkSemaphore
|
||||
};
|
||||
|
||||
#define VULKAN_COMMAND_BUFFERS_CAP 64
|
||||
|
|
@ -331,7 +357,15 @@ struct wlr_vk_vert_pcr_data {
|
|||
float uv_size[2];
|
||||
};
|
||||
|
||||
struct wlr_vk_frag_texture_pcr_data {
|
||||
float matrix[4][4]; // only a 3x3 subset is used
|
||||
float alpha;
|
||||
float luminance_multiplier;
|
||||
};
|
||||
|
||||
struct wlr_vk_frag_output_pcr_data {
|
||||
float matrix[4][4]; // only a 3x3 subset is used
|
||||
float luminance_multiplier;
|
||||
float lut_3d_offset;
|
||||
float lut_3d_scale;
|
||||
};
|
||||
|
|
@ -339,6 +373,7 @@ struct wlr_vk_frag_output_pcr_data {
|
|||
struct wlr_vk_texture_view {
|
||||
struct wl_list link; // struct wlr_vk_texture.views
|
||||
const struct wlr_vk_pipeline_layout *layout;
|
||||
bool srgb;
|
||||
|
||||
VkDescriptorSet ds;
|
||||
VkImageView image_view;
|
||||
|
|
@ -353,7 +388,7 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
|
|||
const struct wlr_vk_pipeline_layout_key *key);
|
||||
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(
|
||||
struct wlr_vk_texture *texture,
|
||||
const struct wlr_vk_pipeline_layout *layout);
|
||||
const struct wlr_vk_pipeline_layout *layout, bool srgb);
|
||||
|
||||
// Creates a vulkan renderer for the given device.
|
||||
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
|
||||
|
|
@ -367,17 +402,34 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
|
|||
// finished execution.
|
||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
|
||||
|
||||
struct wlr_vk_render_pass_texture {
|
||||
struct wlr_vk_texture *texture;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
};
|
||||
|
||||
struct wlr_vk_render_pass {
|
||||
struct wlr_render_pass base;
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wlr_vk_render_buffer *render_buffer;
|
||||
struct wlr_vk_render_buffer_out *render_buffer_out;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wlr_vk_command_buffer *command_buffer;
|
||||
struct rect_union updated_region;
|
||||
VkPipeline bound_pipeline;
|
||||
float projection[9];
|
||||
bool failed;
|
||||
bool srgb_pathway; // if false, rendering via intermediate blending buffer
|
||||
bool two_pass; // rendering via intermediate blending buffer
|
||||
struct wlr_color_transform *color_transform;
|
||||
|
||||
bool has_primaries;
|
||||
struct wlr_color_primaries primaries;
|
||||
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
|
||||
struct wl_array textures; // struct wlr_vk_render_pass_texture
|
||||
};
|
||||
|
||||
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
|
||||
|
|
@ -419,8 +471,10 @@ bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
|
|||
struct wlr_vk_renderer *renderer);
|
||||
|
||||
bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
|
||||
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb);
|
||||
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture);
|
||||
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb,
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
|
||||
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
|
||||
int sync_file_fds[static WLR_DMABUF_MAX_PLANES]);
|
||||
|
||||
bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||
VkFormat src_format, VkImage src_image,
|
||||
|
|
@ -436,13 +490,12 @@ struct wlr_vk_texture {
|
|||
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
||||
VkImage image;
|
||||
const struct wlr_vk_format *format;
|
||||
enum wlr_vk_texture_transform transform;
|
||||
struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
|
||||
bool dmabuf_imported;
|
||||
bool owned; // if dmabuf_imported: whether we have ownership of the image
|
||||
bool transitioned; // if dma_imported: whether we transitioned it away from preinit
|
||||
bool has_alpha; // whether the image is has alpha channel
|
||||
bool using_mutable_srgb; // is this accessed through _SRGB format view
|
||||
bool using_mutable_srgb; // can be accessed through _SRGB format view
|
||||
struct wl_list foreign_link; // wlr_vk_renderer.foreign_textures
|
||||
struct wl_list destroy_link; // wlr_vk_command_buffer.destroy_textures
|
||||
struct wl_list link; // wlr_vk_renderer.textures
|
||||
|
|
@ -450,10 +503,8 @@ struct wlr_vk_texture {
|
|||
// If imported from a wlr_buffer
|
||||
struct wlr_buffer *buffer;
|
||||
struct wlr_addon buffer_addon;
|
||||
// For DMA-BUF implicit sync interop
|
||||
VkSemaphore foreign_semaphores[WLR_DMABUF_MAX_PLANES];
|
||||
|
||||
struct wl_list views; // struct wlr_vk_texture_ds.link
|
||||
struct wl_list views; // struct wlr_vk_texture_view.link
|
||||
};
|
||||
|
||||
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
|
||||
|
|
@ -485,6 +536,7 @@ struct wlr_vk_shared_buffer {
|
|||
VkDeviceSize buf_size;
|
||||
void *cpu_mapping;
|
||||
struct wl_array allocs; // struct wlr_vk_allocation
|
||||
int64_t last_used_ms;
|
||||
};
|
||||
|
||||
// Suballocated range on a buffer.
|
||||
|
|
@ -500,6 +552,7 @@ struct wlr_vk_color_transform {
|
|||
struct wl_list link; // wlr_vk_renderer, list of all color transforms
|
||||
|
||||
struct {
|
||||
size_t dim;
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
VkDeviceMemory memory;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd);
|
||||
/**
|
||||
* Get the supported render formats. Buffers allocated with a format from this
|
||||
* list may be attached via wlr_renderer_begin_with_buffer.
|
||||
* list may be used with wlr_renderer_begin_buffer_pass().
|
||||
*/
|
||||
const struct wlr_drm_format_set *wlr_renderer_get_render_formats(
|
||||
struct wlr_renderer *renderer);
|
||||
|
|
|
|||
|
|
@ -50,15 +50,6 @@ struct wlr_dmabuf_buffer *dmabuf_buffer_create(
|
|||
*/
|
||||
bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Check whether a buffer is fully opaque.
|
||||
*
|
||||
* When true is returned, the buffer is guaranteed to be fully opaque, but the
|
||||
* reverse is not true: false may be returned in cases where the buffer is fully
|
||||
* opaque.
|
||||
*/
|
||||
bool buffer_is_opaque(struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
|
||||
* a texture from it, and copying its struct wl_resource.
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef TYPES_WLR_MATRIX_H
|
||||
#define TYPES_WLR_MATRIX_H
|
||||
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
|
||||
/**
|
||||
* Writes a 2D orthographic projection matrix to mat of (width, height) with a
|
||||
* specified wl_output_transform.
|
||||
*
|
||||
* Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
|
||||
*/
|
||||
void matrix_projection(float mat[static 9], int width, int height,
|
||||
enum wl_output_transform transform);
|
||||
|
||||
#endif
|
||||
|
|
@ -8,6 +8,8 @@ void output_pending_resolution(struct wlr_output *output,
|
|||
const struct wlr_output_state *state, int *width, int *height);
|
||||
bool output_pending_enabled(struct wlr_output *output,
|
||||
const struct wlr_output_state *state);
|
||||
const struct wlr_output_image_description *output_pending_image_description(
|
||||
struct wlr_output *output, const struct wlr_output_state *state);
|
||||
|
||||
bool output_pick_format(struct wlr_output *output,
|
||||
const struct wlr_drm_format_set *display_formats,
|
||||
|
|
@ -18,11 +20,18 @@ bool output_ensure_buffer(struct wlr_output *output,
|
|||
bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
|
||||
struct wlr_texture *texture, bool own_texture, const struct wlr_fbox *src_box,
|
||||
int dst_width, int dst_height, enum wl_output_transform transform,
|
||||
int32_t hotspot_x, int32_t hotspot_y);
|
||||
int32_t hotspot_x, int32_t hotspot_y, struct wlr_drm_syncobj_timeline *wait_timeline,
|
||||
uint64_t wait_point);
|
||||
|
||||
void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event);
|
||||
|
||||
bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state);
|
||||
|
||||
void output_state_get_buffer_src_box(const struct wlr_output_state *state,
|
||||
struct wlr_fbox *out);
|
||||
void output_state_get_buffer_dst_box(const struct wlr_output_state *state,
|
||||
struct wlr_box *out);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef TYPES_WLR_REGION_H
|
||||
#define TYPES_WLR_REGION_H
|
||||
|
||||
#include <wlr/types/wlr_region.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct wl_client;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
|
||||
|
||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height);
|
||||
|
||||
void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
/*
|
||||
* This is a deprecated interface of wlroots. It will be removed in a future
|
||||
* version.
|
||||
*/
|
||||
|
||||
#ifndef WLR_TYPES_WLR_MATRIX_H
|
||||
#define WLR_TYPES_WLR_MATRIX_H
|
||||
#ifndef UTIL_MATRIX_H
|
||||
#define UTIL_MATRIX_H
|
||||
|
||||
#include <wayland-server-protocol.h>
|
||||
|
||||
|
|
@ -17,17 +12,12 @@ void wlr_matrix_identity(float mat[static 9]);
|
|||
void wlr_matrix_multiply(float mat[static 9], const float a[static 9],
|
||||
const float b[static 9]);
|
||||
|
||||
void wlr_matrix_transpose(float mat[static 9], const float a[static 9]);
|
||||
|
||||
/** Writes a 2D translation matrix to mat of magnitude (x, y) */
|
||||
void wlr_matrix_translate(float mat[static 9], float x, float y);
|
||||
|
||||
/** Writes a 2D scale matrix to mat of magnitude (x, y) */
|
||||
void wlr_matrix_scale(float mat[static 9], float x, float y);
|
||||
|
||||
/** Writes a 2D rotation matrix to mat at an angle of rad radians */
|
||||
void wlr_matrix_rotate(float mat[static 9], float rad);
|
||||
|
||||
/** Writes a transformation matrix which applies the specified
|
||||
* wl_output_transform to mat */
|
||||
void wlr_matrix_transform(float mat[static 9],
|
||||
|
|
@ -38,7 +28,22 @@ void wlr_matrix_transform(float mat[static 9],
|
|||
* rotation. The result is written to mat, which can be applied to each
|
||||
* coordinate of the box to get a new coordinate from [-1,1]. */
|
||||
void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box,
|
||||
enum wl_output_transform transform, float rotation,
|
||||
const float projection[static 9]);
|
||||
enum wl_output_transform transform, const float projection[static 9]);
|
||||
|
||||
/**
|
||||
* Writes a 2D orthographic projection matrix to mat of (width, height) with a
|
||||
* specified wl_output_transform.
|
||||
*
|
||||
* Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
|
||||
*/
|
||||
void matrix_projection(float mat[static 9], int width, int height,
|
||||
enum wl_output_transform transform);
|
||||
|
||||
/**
|
||||
* Compute the inverse of a matrix.
|
||||
*
|
||||
* The matrix needs to be inversible.
|
||||
*/
|
||||
void matrix_invert(float out[static 9], float m[static 9]);
|
||||
|
||||
#endif
|
||||
14
include/util/mem.h
Normal file
14
include/util/mem.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef UTIL_MEM_H
|
||||
#define UTIL_MEM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* Allocate a new block of memory and copy *src to it, then store the address
|
||||
* of the new allocation in *out. Returns true if it worked, or false if
|
||||
* allocation failed.
|
||||
*/
|
||||
bool memdup(void *out, const void *src, size_t size);
|
||||
|
||||
#endif // UTIL_MEM_H
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static const long NSEC_PER_SEC = 1000000000;
|
||||
|
||||
/**
|
||||
* Get the current time, in milliseconds.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,10 +25,21 @@ struct wlr_backend_output_state {
|
|||
|
||||
/**
|
||||
* A backend provides a set of input and output devices.
|
||||
*
|
||||
* Buffer capabilities and features can change over the lifetime of a backend,
|
||||
* for instance when a child backend is added to a multi-backend.
|
||||
*/
|
||||
struct wlr_backend {
|
||||
const struct wlr_backend_impl *impl;
|
||||
|
||||
// Bitfield of supported buffer capabilities (see enum wlr_buffer_cap)
|
||||
uint32_t buffer_caps;
|
||||
|
||||
struct {
|
||||
// Whether wait/signal timelines are supported in output commits
|
||||
bool timeline;
|
||||
} features;
|
||||
|
||||
struct {
|
||||
/** Raised when destroyed */
|
||||
struct wl_signal destroy;
|
||||
|
|
@ -54,13 +65,12 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_event_loop *loop,
|
|||
struct wlr_session **session_ptr);
|
||||
/**
|
||||
* Start the backend. This may signal new_input or new_output immediately, but
|
||||
* may also wait until the display's event loop begins. Returns false on
|
||||
* failure.
|
||||
* may also wait until the event loop is started. Returns false on failure.
|
||||
*/
|
||||
bool wlr_backend_start(struct wlr_backend *backend);
|
||||
/**
|
||||
* Destroy the backend and clean up all of its resources. Normally called
|
||||
* automatically when the struct wl_display is destroyed.
|
||||
* automatically when the event loop is destroyed.
|
||||
*/
|
||||
void wlr_backend_destroy(struct wlr_backend *backend);
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ struct wlr_backend_impl {
|
|||
bool (*start)(struct wlr_backend *backend);
|
||||
void (*destroy)(struct wlr_backend *backend);
|
||||
int (*get_drm_fd)(struct wlr_backend *backend);
|
||||
uint32_t (*get_buffer_caps)(struct wlr_backend *backend);
|
||||
bool (*test)(struct wlr_backend *backend,
|
||||
const struct wlr_backend_output_state *states, size_t states_len);
|
||||
bool (*commit)(struct wlr_backend *backend,
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ struct wlr_session {
|
|||
*/
|
||||
bool active;
|
||||
|
||||
/*
|
||||
* 0 if virtual terminals are not supported
|
||||
* i.e. seat != "seat0"
|
||||
*/
|
||||
unsigned vtnr;
|
||||
char seat[256];
|
||||
|
||||
struct udev *udev;
|
||||
|
|
@ -60,13 +55,16 @@ struct wlr_session {
|
|||
struct wl_list devices; // wlr_device.link
|
||||
|
||||
struct wl_event_loop *event_loop;
|
||||
struct wl_listener event_loop_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal active;
|
||||
struct wl_signal add_drm_card; // struct wlr_session_add_event
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener event_loop_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_session_add_event {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,76 @@
|
|||
#ifndef WLR_CONFIG_H
|
||||
#define WLR_CONFIG_H
|
||||
|
||||
/**
|
||||
* Whether the DRM backend is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_drm_backend" variable.
|
||||
*
|
||||
* Required for <wlr/backend/drm.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_DRM_BACKEND
|
||||
/**
|
||||
* Whether the libinput backend is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_libinput_backend" vartiable.
|
||||
*
|
||||
* Required for <wlr/backend/libinput.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_LIBINPUT_BACKEND
|
||||
/**
|
||||
* Whether the X11 backend is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_x11_backend" variable.
|
||||
*
|
||||
* Required for <wlr/backend/x11.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_X11_BACKEND
|
||||
|
||||
/**
|
||||
* Whether the GLES2 renderer is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_gles2_renderer" variable.
|
||||
*
|
||||
* Required for <wlr/render/gles2.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_GLES2_RENDERER
|
||||
/**
|
||||
* Whether the Vulkan renderer is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_vulkan_renderer" variable.
|
||||
*
|
||||
* Required for <wlr/render/vulkan.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_VULKAN_RENDERER
|
||||
|
||||
/**
|
||||
* Whether the GBM allocator is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_gbm_allocator" variable.
|
||||
*/
|
||||
#mesondefine WLR_HAS_GBM_ALLOCATOR
|
||||
/**
|
||||
* Whether the udmabuf allocator is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_udmabuf_allocator" variable.
|
||||
*/
|
||||
#mesondefine WLR_HAS_UDMABUF_ALLOCATOR
|
||||
|
||||
/**
|
||||
* Whether Xwayland support is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_xwayland" variable.
|
||||
*
|
||||
* Required for <wlr/xwayland/…>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_XWAYLAND
|
||||
|
||||
/**
|
||||
* Whether session support is compile-time enabled. Equivalent to the
|
||||
* pkg-config "have_session" variable.
|
||||
*
|
||||
* Required for <wlr/backend/session.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_SESSION
|
||||
|
||||
/**
|
||||
* Whether traditional color management support is compile-time enabled.
|
||||
* Equivalent to the pkg-config "have_color_management" variable.
|
||||
*
|
||||
* Required for ICC profile support in <wlr/render/color.h>.
|
||||
*/
|
||||
#mesondefine WLR_HAS_COLOR_MANAGEMENT
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ struct wlr_buffer_resource_interface {
|
|||
void wlr_buffer_init(struct wlr_buffer *buffer,
|
||||
const struct wlr_buffer_impl *impl, int width, int height);
|
||||
|
||||
/**
|
||||
* Emit the destroy event and clean up common buffer state.
|
||||
*/
|
||||
void wlr_buffer_finish(struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Allows the registration of a struct wl_resource implementation.
|
||||
*
|
||||
|
|
|
|||
45
include/wlr/interfaces/wlr_ext_image_capture_source_v1.h
Normal file
45
include/wlr/interfaces/wlr_ext_image_capture_source_v1.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
|
||||
#define WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
||||
|
||||
struct wlr_ext_image_copy_capture_frame_v1;
|
||||
struct wlr_swapchain;
|
||||
struct wlr_renderer;
|
||||
struct wlr_seat;
|
||||
|
||||
struct wlr_ext_image_capture_source_v1_interface {
|
||||
// TODO: drop with_cursors flag
|
||||
void (*start)(struct wlr_ext_image_capture_source_v1 *source, bool with_cursors);
|
||||
void (*stop)(struct wlr_ext_image_capture_source_v1 *source);
|
||||
void (*schedule_frame)(struct wlr_ext_image_capture_source_v1 *source);
|
||||
void (*copy_frame)(struct wlr_ext_image_capture_source_v1 *source,
|
||||
struct wlr_ext_image_copy_capture_frame_v1 *dst_frame,
|
||||
struct wlr_ext_image_capture_source_v1_frame_event *frame_event);
|
||||
struct wlr_ext_image_capture_source_v1_cursor *(*get_pointer_cursor)(
|
||||
struct wlr_ext_image_capture_source_v1 *source, struct wlr_seat *seat);
|
||||
};
|
||||
|
||||
void wlr_ext_image_capture_source_v1_init(struct wlr_ext_image_capture_source_v1 *source,
|
||||
const struct wlr_ext_image_capture_source_v1_interface *impl);
|
||||
void wlr_ext_image_capture_source_v1_finish(struct wlr_ext_image_capture_source_v1 *source);
|
||||
bool wlr_ext_image_capture_source_v1_create_resource(struct wlr_ext_image_capture_source_v1 *source,
|
||||
struct wl_client *client, uint32_t new_id);
|
||||
bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(
|
||||
struct wlr_ext_image_capture_source_v1 *source,
|
||||
struct wlr_swapchain *swapchain, struct wlr_renderer *renderer);
|
||||
|
||||
void wlr_ext_image_capture_source_v1_cursor_init(struct wlr_ext_image_capture_source_v1_cursor *source_cursor,
|
||||
const struct wlr_ext_image_capture_source_v1_interface *impl);
|
||||
void wlr_ext_image_capture_source_v1_cursor_finish(struct wlr_ext_image_capture_source_v1_cursor *source_cursor);
|
||||
|
||||
#endif
|
||||
|
|
@ -108,6 +108,10 @@ struct wlr_output_impl {
|
|||
void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
|
||||
const struct wlr_output_impl *impl, struct wl_event_loop *event_loop,
|
||||
const struct wlr_output_state *state);
|
||||
/**
|
||||
* Emit the destroy event and clean up common output state.
|
||||
*/
|
||||
void wlr_output_finish(struct wlr_output *output);
|
||||
/**
|
||||
* Notify compositors that they need to submit a new frame in order to apply
|
||||
* output changes.
|
||||
|
|
|
|||
|
|
@ -19,4 +19,7 @@ void wlr_pointer_init(struct wlr_pointer *pointer,
|
|||
const struct wlr_pointer_impl *impl, const char *name);
|
||||
void wlr_pointer_finish(struct wlr_pointer *pointer);
|
||||
|
||||
void wlr_pointer_notify_button(struct wlr_pointer *pointer,
|
||||
struct wlr_pointer_button_event *event);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,8 +10,100 @@
|
|||
#define WLR_RENDER_COLOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/**
|
||||
* Well-known color primaries.
|
||||
*/
|
||||
enum wlr_color_named_primaries {
|
||||
WLR_COLOR_NAMED_PRIMARIES_SRGB = 1 << 0,
|
||||
WLR_COLOR_NAMED_PRIMARIES_BT2020 = 1 << 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Well-known color transfer functions.
|
||||
*/
|
||||
enum wlr_color_transfer_function {
|
||||
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
|
||||
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies alpha blending modes. Note that premultiplied_electrical
|
||||
* is the default, so there is no "none" or "unset" value.
|
||||
*/
|
||||
enum wlr_alpha_mode {
|
||||
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL,
|
||||
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
|
||||
WLR_COLOR_ALPHA_MODE_STRAIGHT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Well-known color encodings, each representing a set of matrix coefficients
|
||||
* used to convert that particular YCbCr encoding to RGB. NONE means the
|
||||
* value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_encoding {
|
||||
WLR_COLOR_ENCODING_NONE,
|
||||
WLR_COLOR_ENCODING_IDENTITY,
|
||||
WLR_COLOR_ENCODING_BT709,
|
||||
WLR_COLOR_ENCODING_FCC,
|
||||
WLR_COLOR_ENCODING_BT601,
|
||||
WLR_COLOR_ENCODING_SMPTE240,
|
||||
WLR_COLOR_ENCODING_BT2020,
|
||||
WLR_COLOR_ENCODING_BT2020_CL,
|
||||
WLR_COLOR_ENCODING_ICTCP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies whether a particular color-encoding uses full- or limited-range
|
||||
* values. NONE means the value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_range {
|
||||
WLR_COLOR_RANGE_NONE,
|
||||
WLR_COLOR_RANGE_LIMITED,
|
||||
WLR_COLOR_RANGE_FULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Chroma sample locations, corresponding to Chroma420SampleLocType code
|
||||
* points in H.273. NONE means the value is unset or unknown.
|
||||
*/
|
||||
enum wlr_color_chroma_location {
|
||||
WLR_COLOR_CHROMA_LOCATION_NONE,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE0,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE1,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE2,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE3,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE4,
|
||||
WLR_COLOR_CHROMA_LOCATION_TYPE5,
|
||||
};
|
||||
|
||||
/**
|
||||
* CIE 1931 xy chromaticity coordinates.
|
||||
*/
|
||||
struct wlr_color_cie1931_xy {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Color primaries and white point describing a color volume.
|
||||
*/
|
||||
struct wlr_color_primaries {
|
||||
struct wlr_color_cie1931_xy red, green, blue, white;
|
||||
};
|
||||
|
||||
/**
|
||||
* Luminance range and reference white luminance level, in cd/m².
|
||||
*/
|
||||
struct wlr_color_luminances {
|
||||
float min, max, reference;
|
||||
};
|
||||
|
||||
/**
|
||||
* A color transformation formula, which maps a linear color space with
|
||||
* sRGB primaries to an output color space.
|
||||
|
|
@ -36,15 +128,30 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
|
|||
const void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply sRGB encoding.
|
||||
* Returns NULL on failure.
|
||||
* Initialize a color transformation to apply EOTF⁻¹ encoding. Returns
|
||||
* NULL on failure.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void);
|
||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply three 1D look-up tables. dim
|
||||
* is the number of elements in each individual LUT. Returns NULL on failure.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply a sequence of color transforms
|
||||
* one after another.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||
struct wlr_color_transform **transforms, size_t len);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the color transform by 1.
|
||||
*/
|
||||
void wlr_color_transform_ref(struct wlr_color_transform *tr);
|
||||
struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Reduce the reference count of the color transform by 1; freeing it and
|
||||
|
|
@ -52,4 +159,10 @@ void wlr_color_transform_ref(struct wlr_color_transform *tr);
|
|||
*/
|
||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a color transform for a given RGB triplet.
|
||||
*/
|
||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set);
|
|||
const struct wlr_drm_format *wlr_drm_format_set_get(
|
||||
const struct wlr_drm_format_set *set, uint32_t format);
|
||||
|
||||
bool wlr_drm_format_set_remove(struct wlr_drm_format_set *set, uint32_t format,
|
||||
uint64_t modifier);
|
||||
|
||||
bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set,
|
||||
uint32_t format, uint64_t modifier);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
/**
|
||||
* A synchronization timeline.
|
||||
|
|
@ -29,20 +30,24 @@ struct wlr_drm_syncobj_timeline {
|
|||
int drm_fd;
|
||||
uint32_t handle;
|
||||
|
||||
// private state
|
||||
struct wlr_addon_set addons;
|
||||
|
||||
size_t n_refs;
|
||||
struct {
|
||||
size_t n_refs;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drm_syncobj_timeline_waiter;
|
||||
|
||||
typedef void (*wlr_drm_syncobj_timeline_ready_callback)(
|
||||
struct wlr_drm_syncobj_timeline_waiter *waiter);
|
||||
|
||||
struct wlr_drm_syncobj_timeline_waiter {
|
||||
struct {
|
||||
struct wl_signal ready;
|
||||
} events;
|
||||
|
||||
// private state
|
||||
|
||||
int ev_fd;
|
||||
struct wl_event_source *event_source;
|
||||
int ev_fd;
|
||||
struct wl_event_source *event_source;
|
||||
wlr_drm_syncobj_timeline_ready_callback callback;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -62,6 +67,17 @@ struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syn
|
|||
* Unreference a synchronization timeline.
|
||||
*/
|
||||
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
|
||||
/**
|
||||
* Export a drm_syncobj FD from a timeline.
|
||||
*/
|
||||
int wlr_drm_syncobj_timeline_export(struct wlr_drm_syncobj_timeline *timeline);
|
||||
/**
|
||||
* Transfer a point from a timeline to another.
|
||||
*
|
||||
* Both timelines must have been created with the same DRM FD.
|
||||
*/
|
||||
bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
|
||||
uint64_t dst_point, struct wlr_drm_syncobj_timeline *src, uint64_t src_point);
|
||||
/**
|
||||
* Check if a timeline point has been signalled or has materialized.
|
||||
*
|
||||
|
|
@ -78,10 +94,12 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
|||
* Asynchronously wait for a timeline point.
|
||||
*
|
||||
* See wlr_drm_syncobj_timeline_check() for a definition of flags.
|
||||
*
|
||||
* A callback must be provided that will be invoked when the waiter has finished.
|
||||
*/
|
||||
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
|
||||
struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
|
||||
struct wl_event_loop *loop);
|
||||
struct wl_event_loop *loop, wlr_drm_syncobj_timeline_ready_callback callback);
|
||||
/**
|
||||
* Cancel a timeline waiter.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <pixman.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/color.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
struct wlr_renderer;
|
||||
|
|
@ -30,9 +31,23 @@ struct wlr_render_timer;
|
|||
struct wlr_buffer_pass_options {
|
||||
/* Timer to measure the duration of the render pass */
|
||||
struct wlr_render_timer *timer;
|
||||
/* Color transform to apply to the output of the render pass,
|
||||
* leave NULL to indicate sRGB/no custom transform */
|
||||
/* Color transform to apply to the output of the render pass.
|
||||
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
|
||||
* sRGB monitors) */
|
||||
struct wlr_color_transform *color_transform;
|
||||
/** Primaries describing the color volume of the destination buffer */
|
||||
const struct wlr_color_primaries *primaries;
|
||||
|
||||
/* Signal a timeline synchronization point when the render pass completes.
|
||||
*
|
||||
* When a compositor provides a signal timeline, the renderer may skip
|
||||
* implicit signal synchronization.
|
||||
*
|
||||
* Support for this feature is advertised by features.timeline in
|
||||
* struct wlr_renderer.
|
||||
*/
|
||||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -88,6 +103,21 @@ struct wlr_render_texture_options {
|
|||
enum wlr_scale_filter_mode filter_mode;
|
||||
/* Blend mode */
|
||||
enum wlr_render_blend_mode blend_mode;
|
||||
/* Transfer function the source texture is encoded with */
|
||||
enum wlr_color_transfer_function transfer_function;
|
||||
/* Primaries describing the color volume of the source texture */
|
||||
const struct wlr_color_primaries *primaries;
|
||||
|
||||
/* Wait for a timeline synchronization point before texturing.
|
||||
*
|
||||
* When a compositor provides a wait timeline, the renderer may skip
|
||||
* implicit wait synchronization.
|
||||
*
|
||||
* Support for this feature is advertised by features.timeline in
|
||||
* struct wlr_renderer.
|
||||
*/
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
struct wlr_swapchain_slot {
|
||||
struct wlr_buffer *buffer;
|
||||
bool acquired; // waiting for release
|
||||
int age;
|
||||
|
||||
struct wl_listener release;
|
||||
struct {
|
||||
struct wl_listener release;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_swapchain {
|
||||
|
|
@ -23,7 +24,9 @@ struct wlr_swapchain {
|
|||
|
||||
struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
|
||||
|
||||
struct wl_listener allocator_destroy;
|
||||
struct {
|
||||
struct wl_listener allocator_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_swapchain *wlr_swapchain_create(
|
||||
|
|
@ -36,21 +39,12 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
|
|||
* The returned buffer is locked. When the caller is done with it, they must
|
||||
* unlock it by calling wlr_buffer_unlock.
|
||||
*/
|
||||
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
|
||||
int *age);
|
||||
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain);
|
||||
/**
|
||||
* Returns true if this buffer has been created by this swapchain, and false
|
||||
* otherwise.
|
||||
*/
|
||||
bool wlr_swapchain_has_buffer(struct wlr_swapchain *swapchain,
|
||||
struct wlr_buffer *buffer);
|
||||
/**
|
||||
* Mark the buffer as submitted for presentation. This needs to be called by
|
||||
* swap chain users on frame boundaries.
|
||||
*
|
||||
* If the buffer hasn't been created via the swap chain, the call is ignored.
|
||||
*/
|
||||
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -41,15 +41,25 @@ struct wlr_renderer {
|
|||
} events;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* Whether color transforms are supported for input textures
|
||||
*/
|
||||
bool input_color_transform;
|
||||
/**
|
||||
* Does the renderer support color transforms on its output?
|
||||
*/
|
||||
bool output_color_transform;
|
||||
/**
|
||||
* Whether wait/signal timelines are supported.
|
||||
*
|
||||
* See struct wlr_drm_syncobj_timeline.
|
||||
*/
|
||||
bool timeline;
|
||||
} features;
|
||||
|
||||
// private state
|
||||
|
||||
const struct wlr_renderer_impl *impl;
|
||||
struct {
|
||||
const struct wlr_renderer_impl *impl;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ struct wlr_alpha_modifier_surface_v1_state {
|
|||
struct wlr_alpha_modifier_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
// private state
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_alpha_modifier_v1 *wlr_alpha_modifier_v1_create(struct wl_display *display);
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@
|
|||
struct wlr_buffer;
|
||||
struct wlr_renderer;
|
||||
|
||||
/**
|
||||
* Shared-memory attributes for a buffer.
|
||||
*/
|
||||
struct wlr_shm_attributes {
|
||||
int fd;
|
||||
uint32_t format;
|
||||
int width, height, stride;
|
||||
off_t offset;
|
||||
uint32_t format; // FourCC code, see DRM_FORMAT_* in <drm_fourcc.h>
|
||||
int width, height;
|
||||
int stride; // Number of bytes between consecutive pixel lines
|
||||
off_t offset; // Offset in bytes of the first pixel in FD
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -105,6 +109,15 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
|
|||
*/
|
||||
struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource);
|
||||
|
||||
/**
|
||||
* Check whether a buffer is fully opaque.
|
||||
*
|
||||
* When true is returned, the buffer is guaranteed to be fully opaque, but the
|
||||
* reverse is not true: false may be returned in cases where the buffer is fully
|
||||
* opaque.
|
||||
*/
|
||||
bool wlr_buffer_is_opaque(struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* Buffer data pointer access flags.
|
||||
*/
|
||||
|
|
@ -130,6 +143,12 @@ enum wlr_buffer_data_ptr_access_flag {
|
|||
*/
|
||||
bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
|
||||
void **data, uint32_t *format, size_t *stride);
|
||||
/**
|
||||
* Indicate that a pointer to a buffer's underlying memory will no longer be
|
||||
* used.
|
||||
*
|
||||
* This function must be called after wlr_buffer_begin_data_ptr_access().
|
||||
*/
|
||||
void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
|
|
@ -148,12 +167,12 @@ struct wlr_client_buffer {
|
|||
*/
|
||||
struct wlr_buffer *source;
|
||||
|
||||
// private state
|
||||
struct {
|
||||
struct wl_listener source_destroy;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
||||
struct wl_listener source_destroy;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
||||
size_t n_ignore_locks;
|
||||
size_t n_ignore_locks;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -162,4 +181,29 @@ struct wlr_client_buffer {
|
|||
*/
|
||||
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
|
||||
|
||||
/**
|
||||
* A single-pixel buffer. Used by clients to draw solid-color rectangles.
|
||||
*/
|
||||
struct wlr_single_pixel_buffer_v1 {
|
||||
struct wlr_buffer base;
|
||||
|
||||
// Full-scale for each component is UINT32_MAX
|
||||
uint32_t r, g, b, a;
|
||||
|
||||
struct {
|
||||
struct wl_resource *resource;
|
||||
struct wl_listener release;
|
||||
|
||||
// Packed little-endian DRM_FORMAT_ARGB8888. Used for data_ptr_access
|
||||
uint8_t argb8888[4];
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
* If the wlr_buffer is a wlr_single_pixel_buffer_v1 then unwrap it.
|
||||
* Otherwise, returns NULL.
|
||||
*/
|
||||
struct wlr_single_pixel_buffer_v1 *wlr_single_pixel_buffer_v1_try_from_buffer(
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
122
include/wlr/types/wlr_color_management_v1.h
Normal file
122
include/wlr/types/wlr_color_management_v1.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-management-v1-enum.h>
|
||||
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
struct wlr_image_description_v1_data {
|
||||
uint32_t tf_named; // enum wp_color_manager_v1_transfer_function, zero if unset
|
||||
uint32_t primaries_named; // enum wp_color_manager_v1_primaries, zero if unset
|
||||
|
||||
bool has_mastering_display_primaries;
|
||||
struct wlr_color_primaries mastering_display_primaries;
|
||||
|
||||
bool has_mastering_luminance;
|
||||
struct {
|
||||
float min, max; // cd/m²
|
||||
} mastering_luminance;
|
||||
|
||||
uint32_t max_cll, max_fall; // cd/m², zero if unset
|
||||
};
|
||||
|
||||
struct wlr_color_manager_v1_features {
|
||||
bool icc_v2_v4;
|
||||
bool parametric;
|
||||
bool set_primaries;
|
||||
bool set_tf_power;
|
||||
bool set_luminances;
|
||||
bool set_mastering_display_primaries;
|
||||
bool extended_target_volume;
|
||||
bool windows_scrgb;
|
||||
};
|
||||
|
||||
struct wlr_color_manager_v1_options {
|
||||
struct wlr_color_manager_v1_features features;
|
||||
|
||||
const enum wp_color_manager_v1_render_intent *render_intents;
|
||||
size_t render_intents_len;
|
||||
|
||||
const enum wp_color_manager_v1_transfer_function *transfer_functions;
|
||||
size_t transfer_functions_len;
|
||||
|
||||
const enum wp_color_manager_v1_primaries *primaries;
|
||||
size_t primaries_len;
|
||||
};
|
||||
|
||||
struct wlr_color_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wlr_color_manager_v1_features features;
|
||||
|
||||
enum wp_color_manager_v1_render_intent *render_intents;
|
||||
size_t render_intents_len;
|
||||
|
||||
enum wp_color_manager_v1_transfer_function *transfer_functions;
|
||||
size_t transfer_functions_len;
|
||||
|
||||
enum wp_color_manager_v1_primaries *primaries;
|
||||
size_t primaries_len;
|
||||
|
||||
struct wl_list outputs; // wlr_color_management_output_v1.link
|
||||
struct wl_list surface_feedbacks; // wlr_color_management_surface_feedback_v1.link
|
||||
|
||||
uint32_t last_image_desc_identity;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *display,
|
||||
uint32_t version, const struct wlr_color_manager_v1_options *options);
|
||||
|
||||
const struct wlr_image_description_v1_data *
|
||||
wlr_surface_get_image_description_v1_data(struct wlr_surface *surface);
|
||||
|
||||
void wlr_color_manager_v1_set_surface_preferred_image_description(
|
||||
struct wlr_color_manager_v1 *manager, struct wlr_surface *surface,
|
||||
const struct wlr_image_description_v1_data *data);
|
||||
|
||||
/**
|
||||
* Convert a protocol transfer function to enum wlr_color_transfer_function.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_transfer_function value into a protocol transfer function.
|
||||
*/
|
||||
enum wp_color_manager_v1_transfer_function
|
||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf);
|
||||
|
||||
/**
|
||||
* Convert a protocol named primaries to enum wlr_color_named_primaries.
|
||||
* Aborts if there is no matching wlroots entry.
|
||||
*/
|
||||
enum wlr_color_named_primaries
|
||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries);
|
||||
|
||||
/**
|
||||
* Convert an enum wlr_color_named_primaries value into protocol primaries.
|
||||
*/
|
||||
enum wp_color_manager_v1_primaries
|
||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries);
|
||||
|
||||
#endif
|
||||
93
include/wlr/types/wlr_color_representation_v1.h
Normal file
93
include/wlr/types/wlr_color_representation_v1.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
#define WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-protocols/color-representation-v1-enum.h>
|
||||
#include <wlr/render/color.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
// Supported coefficients and range are always paired together
|
||||
struct wlr_color_representation_v1_coeffs_and_range {
|
||||
enum wp_color_representation_surface_v1_coefficients coeffs;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
};
|
||||
|
||||
struct wlr_color_representation_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
||||
struct {
|
||||
// Manager is being destroyed
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
enum wp_color_representation_surface_v1_alpha_mode
|
||||
*supported_alpha_modes;
|
||||
size_t supported_alpha_modes_len;
|
||||
|
||||
struct wlr_color_representation_v1_coeffs_and_range
|
||||
*supported_coeffs_and_ranges;
|
||||
size_t supported_coeffs_and_ranges_len;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
// Options used when initialising a wlr_color_representation_manager_v1
|
||||
struct wlr_color_representation_v1_options {
|
||||
enum wp_color_representation_surface_v1_alpha_mode
|
||||
*supported_alpha_modes;
|
||||
size_t supported_alpha_modes_len;
|
||||
|
||||
const struct wlr_color_representation_v1_coeffs_and_range
|
||||
*supported_coeffs_and_ranges;
|
||||
size_t supported_coeffs_and_ranges_len;
|
||||
};
|
||||
|
||||
struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version,
|
||||
const struct wlr_color_representation_v1_options *options);
|
||||
|
||||
// This is all the color-representation state which can be attached to a
|
||||
// surface, double-buffered and made current on commit
|
||||
struct wlr_color_representation_v1_surface_state {
|
||||
// The enum premultiplied_electrical has value zero and is defined
|
||||
// to be the default if unspecified.
|
||||
enum wp_color_representation_surface_v1_alpha_mode alpha_mode;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_coefficients
|
||||
uint32_t coefficients;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_range
|
||||
uint32_t range;
|
||||
|
||||
// If zero then indicates unset, otherwise values correspond to
|
||||
// enum wp_color_representation_surface_v1_chroma_location
|
||||
uint32_t chroma_location;
|
||||
};
|
||||
|
||||
// Get the current color representation state committed to a surface
|
||||
const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
|
||||
struct wlr_surface *surface);
|
||||
|
||||
enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
|
||||
enum wp_color_representation_surface_v1_alpha_mode wp_val);
|
||||
enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
|
||||
enum wp_color_representation_surface_v1_coefficients wp_val);
|
||||
enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
|
||||
enum wp_color_representation_surface_v1_range wp_val);
|
||||
enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
|
||||
enum wp_color_representation_surface_v1_chroma_location wp_val);
|
||||
|
||||
#endif // WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
|
||||
|
|
@ -14,10 +14,11 @@
|
|||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
enum wlr_surface_state_field {
|
||||
WLR_SURFACE_STATE_BUFFER = 1 << 0,
|
||||
WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1,
|
||||
|
|
@ -97,6 +98,13 @@ struct wlr_surface_role {
|
|||
* such object exists.
|
||||
*/
|
||||
void (*commit)(struct wlr_surface *surface);
|
||||
/**
|
||||
* Called when the surface is mapped. May be NULL.
|
||||
*
|
||||
* If the role is represented by an object, this is only called if
|
||||
* such object exists.
|
||||
*/
|
||||
void (*map)(struct wlr_surface *surface);
|
||||
/**
|
||||
* Called when the surface is unmapped. May be NULL.
|
||||
*
|
||||
|
|
@ -115,8 +123,11 @@ struct wlr_surface_output {
|
|||
struct wlr_output *output;
|
||||
|
||||
struct wl_list link; // wlr_surface.current_outputs
|
||||
struct wl_listener bind;
|
||||
struct wl_listener destroy;
|
||||
|
||||
struct {
|
||||
struct wl_listener bind;
|
||||
struct wl_listener destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_surface {
|
||||
|
|
@ -180,28 +191,47 @@ struct wlr_surface {
|
|||
struct wl_resource *role_resource;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* Signals that the client has sent a wl_surface.commit request.
|
||||
*
|
||||
* The state to be committed can be accessed in wlr_surface.pending.
|
||||
*
|
||||
* The commit may not be applied immediately, in which case it's marked
|
||||
* as "cached" and put into a queue. See wlr_surface_lock_pending().
|
||||
*/
|
||||
struct wl_signal client_commit;
|
||||
/**
|
||||
* Signals that a commit has been applied.
|
||||
*
|
||||
* The new state can be accessed in wlr_surface.current.
|
||||
*/
|
||||
struct wl_signal commit;
|
||||
|
||||
/**
|
||||
* The `map` event signals that the surface has a non-null buffer
|
||||
* committed and is ready to be displayed.
|
||||
* Signals that the surface has a non-null buffer committed and is
|
||||
* ready to be displayed.
|
||||
*/
|
||||
struct wl_signal map;
|
||||
/**
|
||||
* The `unmap` event signals that the surface shouldn't be displayed
|
||||
* anymore. This can happen when a null buffer is committed,
|
||||
* the associated role object is destroyed, or when the role-specific
|
||||
* conditions for the surface to be mapped no longer apply.
|
||||
* Signals that the surface shouldn't be displayed anymore. This can
|
||||
* happen when a null buffer is committed, the associated role object
|
||||
* is destroyed, or when the role-specific conditions for the surface
|
||||
* to be mapped no longer apply.
|
||||
*/
|
||||
struct wl_signal unmap;
|
||||
|
||||
/**
|
||||
* Signals that a new child sub-surface has been added.
|
||||
*
|
||||
* Note: unlike other new_* signals, new_subsurface is emitted when
|
||||
* the subsurface is added to the parent surface's current state,
|
||||
* not when the object is created.
|
||||
*/
|
||||
struct wl_signal new_subsurface; // struct wlr_subsurface
|
||||
|
||||
/**
|
||||
* Signals that the surface is being destroyed.
|
||||
*/
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
|
|
@ -210,33 +240,33 @@ struct wlr_surface {
|
|||
struct wlr_addon_set addons;
|
||||
void *data;
|
||||
|
||||
// private state
|
||||
|
||||
struct wl_listener role_resource_destroy;
|
||||
|
||||
struct {
|
||||
int32_t scale;
|
||||
enum wl_output_transform transform;
|
||||
int width, height;
|
||||
int buffer_width, buffer_height;
|
||||
} previous;
|
||||
struct wl_listener role_resource_destroy;
|
||||
|
||||
bool unmap_commit;
|
||||
struct {
|
||||
int32_t scale;
|
||||
enum wl_output_transform transform;
|
||||
int width, height;
|
||||
int buffer_width, buffer_height;
|
||||
} previous;
|
||||
|
||||
bool opaque;
|
||||
bool unmap_commit;
|
||||
|
||||
bool handling_commit;
|
||||
bool pending_rejected;
|
||||
bool opaque;
|
||||
|
||||
int32_t preferred_buffer_scale;
|
||||
bool preferred_buffer_transform_sent;
|
||||
enum wl_output_transform preferred_buffer_transform;
|
||||
bool handling_commit;
|
||||
bool pending_rejected;
|
||||
|
||||
struct wl_list synced; // wlr_surface_synced.link
|
||||
size_t synced_len;
|
||||
int32_t preferred_buffer_scale;
|
||||
bool preferred_buffer_transform_sent;
|
||||
enum wl_output_transform preferred_buffer_transform;
|
||||
|
||||
struct wl_resource *pending_buffer_resource;
|
||||
struct wl_listener pending_buffer_resource_destroy;
|
||||
struct wl_list synced; // wlr_surface_synced.link
|
||||
size_t synced_len;
|
||||
|
||||
struct wl_resource *pending_buffer_resource;
|
||||
struct wl_listener pending_buffer_resource_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_renderer;
|
||||
|
|
@ -245,13 +275,15 @@ struct wlr_compositor {
|
|||
struct wl_global *global;
|
||||
struct wlr_renderer *renderer; // may be NULL
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct wl_listener renderer_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal new_surface;
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
struct wl_listener renderer_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
|
||||
|
|
@ -381,7 +413,7 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface,
|
|||
* surface coordinates.
|
||||
* X and y may be negative, if there are subsurfaces with negative position.
|
||||
*/
|
||||
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
|
||||
void wlr_surface_get_extents(struct wlr_surface *surface, struct wlr_box *box);
|
||||
|
||||
/**
|
||||
* Get the struct wlr_surface corresponding to a wl_surface resource.
|
||||
|
|
@ -453,6 +485,8 @@ void wlr_surface_set_preferred_buffer_scale(struct wlr_surface *surface,
|
|||
void wlr_surface_set_preferred_buffer_transform(struct wlr_surface *surface,
|
||||
enum wl_output_transform transform);
|
||||
|
||||
struct wlr_surface_synced;
|
||||
|
||||
/**
|
||||
* Implementation for struct wlr_surface_synced.
|
||||
*
|
||||
|
|
@ -469,6 +503,11 @@ struct wlr_surface_synced_impl {
|
|||
void (*finish_state)(void *state);
|
||||
// Move a state. If NULL, memcpy() is used.
|
||||
void (*move_state)(void *dst, void *src);
|
||||
|
||||
// Called when the state is committed. If NULL, this is a no-op.
|
||||
// If an object is a surface role object which has state synchronized with
|
||||
// the surface state, the role commit hook should be preferred over this.
|
||||
void (*commit)(struct wlr_surface_synced *synced);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "content-type-v1-protocol.h"
|
||||
#include <wayland-protocols/content-type-v1-enum.h>
|
||||
|
||||
struct wlr_surface;
|
||||
|
||||
|
|
@ -23,9 +23,9 @@ struct wlr_content_type_manager_v1 {
|
|||
|
||||
void *data;
|
||||
|
||||
// private state
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_content_type_manager_v1 *wlr_content_type_manager_v1_create(
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
||||
struct wlr_input_device;
|
||||
struct wlr_surface;
|
||||
struct wlr_xcursor_manager;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include "cursor-shape-v1-protocol.h"
|
||||
#include <wayland-protocols/cursor-shape-v1-enum.h>
|
||||
|
||||
/**
|
||||
* Manager for the cursor-shape-v1 protocol.
|
||||
|
|
@ -28,9 +28,9 @@ struct wlr_cursor_shape_manager_v1 {
|
|||
|
||||
void *data;
|
||||
|
||||
// private state
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
enum wlr_cursor_shape_manager_v1_device_type {
|
||||
|
|
|
|||
|
|
@ -15,32 +15,27 @@
|
|||
#include <pixman.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
/* For triple buffering, a history of two frames is required. */
|
||||
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
|
||||
|
||||
struct wlr_box;
|
||||
|
||||
struct wlr_damage_ring_buffer {
|
||||
struct wlr_buffer *buffer;
|
||||
struct wl_listener destroy;
|
||||
pixman_region32_t damage;
|
||||
|
||||
struct wlr_damage_ring *ring;
|
||||
struct wl_list link; // wlr_damage_ring.buffers
|
||||
|
||||
struct {
|
||||
struct wl_listener destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_damage_ring {
|
||||
int32_t width, height;
|
||||
|
||||
// Difference between the current buffer and the previous one
|
||||
pixman_region32_t current;
|
||||
|
||||
// private state
|
||||
|
||||
pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
|
||||
size_t previous_idx;
|
||||
|
||||
struct wl_list buffers; // wlr_damage_ring_buffer.link
|
||||
struct {
|
||||
struct wl_list buffers; // wlr_damage_ring_buffer.link
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
|
||||
|
|
@ -48,30 +43,17 @@ void wlr_damage_ring_init(struct wlr_damage_ring *ring);
|
|||
void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
|
||||
|
||||
/**
|
||||
* Set ring bounds and damage the ring fully.
|
||||
*
|
||||
* Next time damage will be added, it will be cropped to the ring bounds.
|
||||
* If at least one of the dimensions is 0, bounds are removed.
|
||||
*
|
||||
* By default, a damage ring doesn't have bounds.
|
||||
* Add a region to the current damage. The region must be in the buffer-local
|
||||
* coordinate space.
|
||||
*/
|
||||
void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring,
|
||||
int32_t width, int32_t height);
|
||||
|
||||
/**
|
||||
* Add a region to the current damage.
|
||||
*
|
||||
* Returns true if the region intersects the ring bounds, false otherwise.
|
||||
*/
|
||||
bool wlr_damage_ring_add(struct wlr_damage_ring *ring,
|
||||
void wlr_damage_ring_add(struct wlr_damage_ring *ring,
|
||||
const pixman_region32_t *damage);
|
||||
|
||||
/**
|
||||
* Add a box to the current damage.
|
||||
*
|
||||
* Returns true if the box intersects the ring bounds, false otherwise.
|
||||
* Add a box to the current damage. The box must be in the buffer-local
|
||||
* coordinate space.
|
||||
*/
|
||||
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
|
||||
void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
|
||||
const struct wlr_box *box);
|
||||
|
||||
/**
|
||||
|
|
@ -79,20 +61,6 @@ bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
|
|||
*/
|
||||
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
|
||||
|
||||
/**
|
||||
* Rotate the damage ring. This needs to be called after using the accumulated
|
||||
* damage, e.g. after rendering to an output's back buffer.
|
||||
*/
|
||||
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
|
||||
|
||||
/**
|
||||
* Get accumulated damage, which is the difference between the current buffer
|
||||
* and the buffer with age of buffer_age; in context of rendering, this is
|
||||
* the region that needs to be redrawn.
|
||||
*/
|
||||
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
||||
int buffer_age, pixman_region32_t *damage);
|
||||
|
||||
/**
|
||||
* Get accumulated buffer damage and rotate the damage ring.
|
||||
*
|
||||
|
|
@ -102,6 +70,8 @@ void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
|
|||
*
|
||||
* Users should damage the ring if an error occurs while rendering or
|
||||
* submitting the new buffer to the backend.
|
||||
*
|
||||
* The returned damage will be in the buffer-local coordinate space.
|
||||
*/
|
||||
void wlr_damage_ring_rotate_buffer(struct wlr_damage_ring *ring,
|
||||
struct wlr_buffer *buffer, pixman_region32_t *damage);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
/**
|
||||
* Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
|
||||
* The implementation will be dropped in a future wlroots version.
|
||||
*
|
||||
* Consider using `wlr_ext_data_control_manager_v1` as a replacement.
|
||||
*/
|
||||
struct wlr_data_control_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list devices; // wlr_data_control_device_v1.link
|
||||
|
|
@ -21,7 +27,9 @@ struct wlr_data_control_manager_v1 {
|
|||
struct wl_signal new_device; // wlr_data_control_device_v1
|
||||
} events;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_data_control_device_v1 {
|
||||
|
|
@ -33,9 +41,11 @@ struct wlr_data_control_device_v1 {
|
|||
struct wl_resource *selection_offer_resource; // current selection offer
|
||||
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
|
||||
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
struct {
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create(
|
||||
|
|
|
|||
|
|
@ -16,13 +16,15 @@ struct wlr_data_device_manager {
|
|||
struct wl_global *global;
|
||||
struct wl_list data_sources;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
enum wlr_data_offer_type {
|
||||
|
|
@ -40,7 +42,9 @@ struct wlr_data_offer {
|
|||
enum wl_data_device_manager_dnd_action preferred_action;
|
||||
bool in_ask;
|
||||
|
||||
struct wl_listener source_destroy;
|
||||
struct {
|
||||
struct wl_listener source_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -89,9 +93,11 @@ struct wlr_drag_icon {
|
|||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct wl_listener surface_destroy;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener surface_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
enum wlr_drag_grab_type {
|
||||
|
|
@ -124,11 +130,14 @@ struct wlr_drag {
|
|||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct wl_listener source_destroy;
|
||||
struct wl_listener seat_client_destroy;
|
||||
struct wl_listener icon_destroy;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener source_destroy;
|
||||
struct wl_listener seat_client_destroy;
|
||||
struct wl_listener focus_destroy;
|
||||
struct wl_listener icon_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drag_motion_event {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ struct wlr_drm_buffer {
|
|||
struct wl_resource *resource; // can be NULL if the client destroyed it
|
||||
struct wlr_dmabuf_attributes dmabuf;
|
||||
|
||||
struct wl_listener release;
|
||||
struct {
|
||||
struct wl_listener release;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -40,12 +42,12 @@ struct wlr_drm {
|
|||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
// private state
|
||||
struct {
|
||||
char *node_name;
|
||||
struct wlr_drm_format_set formats;
|
||||
|
||||
char *node_name;
|
||||
struct wlr_drm_format_set formats;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drm_buffer *wlr_drm_buffer_try_from_resource(
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ struct wlr_drm_lease_v1_manager {
|
|||
struct wl_list devices; // wlr_drm_lease_device_v1.link
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
|
||||
/**
|
||||
* Upon receiving this signal, call
|
||||
* wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
|
||||
|
|
@ -29,6 +30,10 @@ struct wlr_drm_lease_v1_manager {
|
|||
*/
|
||||
struct wl_signal request;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drm_lease_device_v1 {
|
||||
|
|
@ -43,9 +48,11 @@ struct wlr_drm_lease_device_v1 {
|
|||
struct wl_list requests; // wlr_drm_lease_request_v1.link
|
||||
struct wl_list link; // wlr_drm_lease_v1_manager.devices
|
||||
|
||||
struct wl_listener backend_destroy;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener backend_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drm_lease_v1;
|
||||
|
|
@ -55,12 +62,12 @@ struct wlr_drm_lease_connector_v1 {
|
|||
|
||||
struct wlr_output *output;
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
/** NULL if no client is currently leasing this connector */
|
||||
struct wlr_drm_lease_v1 *active_lease;
|
||||
|
||||
struct wl_listener destroy;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.connectors
|
||||
|
||||
struct {
|
||||
struct wl_listener destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_drm_lease_request_v1 {
|
||||
|
|
@ -84,14 +91,13 @@ struct wlr_drm_lease_v1 {
|
|||
|
||||
struct wlr_drm_lease_device_v1 *device;
|
||||
|
||||
struct wlr_drm_lease_connector_v1 **connectors;
|
||||
size_t n_connectors;
|
||||
|
||||
struct wl_list link; // wlr_drm_lease_device_v1.leases
|
||||
|
||||
struct wl_listener destroy;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,11 +17,13 @@ struct wlr_export_dmabuf_manager_v1 {
|
|||
struct wl_global *global;
|
||||
struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_export_dmabuf_frame_v1 {
|
||||
|
|
@ -33,8 +35,10 @@ struct wlr_export_dmabuf_frame_v1 {
|
|||
|
||||
bool cursor_locked;
|
||||
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener output_destroy;
|
||||
struct {
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener output_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
|
||||
|
|
|
|||
51
include/wlr/types/wlr_ext_data_control_v1.h
Normal file
51
include/wlr/types/wlr_ext_data_control_v1.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
|
||||
#define WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
|
||||
struct wlr_ext_data_control_manager_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list devices; // wlr_ext_data_control_device_v1.link
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
struct wl_signal new_device; // wlr_ext_data_control_device_v1
|
||||
} events;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_device_v1 {
|
||||
struct wl_resource *resource;
|
||||
struct wlr_ext_data_control_manager_v1 *manager;
|
||||
struct wl_list link; // wlr_ext_data_control_manager_v1.devices
|
||||
|
||||
struct wlr_seat *seat;
|
||||
struct wl_resource *selection_offer_resource; // current selection offer
|
||||
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
|
||||
|
||||
struct {
|
||||
struct wl_listener seat_destroy;
|
||||
struct wl_listener seat_set_selection;
|
||||
struct wl_listener seat_set_primary_selection;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
|
||||
struct wl_display *display, uint32_t version);
|
||||
|
||||
void wlr_ext_data_control_device_v1_destroy(
|
||||
struct wlr_ext_data_control_device_v1 *device);
|
||||
|
||||
#endif
|
||||
|
|
@ -16,13 +16,15 @@ struct wlr_ext_foreign_toplevel_list_v1 {
|
|||
struct wl_list resources; // wl_resource_get_link()
|
||||
struct wl_list toplevels; // ext_foreign_toplevel_handle_v1.link
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
|
||||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
struct wlr_ext_foreign_toplevel_handle_v1 {
|
||||
|
|
@ -64,4 +66,7 @@ void wlr_ext_foreign_toplevel_handle_v1_update_state(
|
|||
struct wlr_ext_foreign_toplevel_handle_v1 *toplevel,
|
||||
const struct wlr_ext_foreign_toplevel_handle_v1_state *state);
|
||||
|
||||
struct wlr_ext_foreign_toplevel_handle_v1 *wlr_ext_foreign_toplevel_handle_v1_from_resource(
|
||||
struct wl_resource *resource);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
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