Compare commits
473 Commits
0.14.0
...
dkondor-up
Author | SHA1 | Date |
---|---|---|
blank X | c5e3ca6249 | |
Simon Ser | 29938b7425 | |
Isaac Freund | eb1a451803 | |
Isaac Freund | a819c512ec | |
Alexander Orzechowski | c4824b680a | |
Simon Ser | ec3780e6ea | |
Kirill Primak | 68c5fa340d | |
Kirill Primak | 304c61307a | |
Tadeo Kondrak | b0fee56974 | |
Kirill Primak | 7dde2b66d6 | |
Thomas Hebb | ea77cc5cb2 | |
nyorain | a59a957f2b | |
Simon Ser | df945b665c | |
Isaac Freund | 4b358c2f91 | |
Simon Ser | 7864f26d73 | |
blank X | b309e8fc39 | |
Daniel Kondor | 80d10b9c98 | |
Simon Ser | 9f41627aa1 | |
Stacy Harper | 8e566f716c | |
Isaac Freund | 07ccc6e0b3 | |
Simon Ser | c0b120a30c | |
Simon Ser | bedfec94bb | |
Simon Ser | a15c327718 | |
Simon Ser | 4377b55292 | |
Guido Günther | 4c59f7d46a | |
David Rosca | 31914928d2 | |
Isaac Freund | 1c3e0816f3 | |
Isaac Freund | ad01cdf0b2 | |
Isaac Freund | fecde72be3 | |
Isaac Freund | fb1f613510 | |
Isaac Freund | 0215dffba5 | |
Chris Chamberlain | d8ca494558 | |
Chris Chamberlain | f6d3efbf4b | |
Simon Ser | e3fefda023 | |
Kirill Primak | 0fcc842291 | |
Kirill Primak | 7964bdae76 | |
Kirill Primak | df7d280343 | |
Kirill Primak | f463ca669a | |
Simon Ser | 818fc4a87b | |
Simon Ser | 36a2b19485 | |
Simon Ser | 1fbd13ec79 | |
Simon Ser | 90e9d327dd | |
Simon Ser | 83bdb3ad07 | |
Simon Ser | ad28490cf4 | |
Simon Ser | c50c4fc5cc | |
Simon Ser | 1d8340754b | |
Simon Ser | 77d811a21b | |
Kirill Primak | c9f3c2b4f7 | |
tiosgz | ca1af8119c | |
Simon Ser | efeb8346cf | |
Simon Ser | 45069fb623 | |
Simon Ser | 60b7267e18 | |
Simon Ser | f016eca97c | |
Simon Ser | 7201aae3d6 | |
Simon Ser | 92080b3a01 | |
Simon Ser | 0d32118a80 | |
Simon Ser | 1bf9676e87 | |
Simon Ser | de0bc78319 | |
Simon Ser | 051d1ce90e | |
Simon Ser | ffd4a27714 | |
Quantum | 812ab2e716 | |
Moon Sungjoon | 611b9ca843 | |
Isaac Freund | a44b2af672 | |
Simon Ser | ba974a4e9f | |
Simon Zeni | dd84c5a1cc | |
Simon Ser | 697a1cd0f5 | |
Simon Ser | e93435016e | |
Simon Ser | 2540de494e | |
Simon Ser | 456b971099 | |
Rouven Czerwinski | 6bfb930aa7 | |
Simon Ser | fbaefd90fc | |
John Lindgren | bff5b2c559 | |
Jonathan Wong | 0fb479ca61 | |
Rouven Czerwinski | d37eb5c2ea | |
Simon Ser | 254ab890e7 | |
Simon Ser | 83d78f9fd4 | |
Simon Ser | ef1669d33e | |
Simon Ser | 98f2efde98 | |
Simon Ser | d5df8d5cbf | |
Simon Ser | e163a7cf48 | |
Simon Ser | affe9eda57 | |
Simon Ser | d78cb808b1 | |
Simon Ser | 585a908a01 | |
Simon Zeni | 1d3dd7fc08 | |
Simon Ser | b234edcf58 | |
Simon Ser | 2e33139ef7 | |
Simon Ser | f29abe4c77 | |
Simon Ser | e4f748c6e9 | |
Simon Ser | bf57825560 | |
Simon Ser | bcefb71cf6 | |
Joshua Ashton | f132d66816 | |
Simon Ser | 5332935afc | |
Simon Ser | 1d9c1bcea6 | |
Isaac Freund | c9ba9e82b6 | |
Simon Ser | 3b93da70a0 | |
Simon Ser | 3d73b899ff | |
Simon Zeni | d70d74ad4f | |
Simon Zeni | 52c34e8253 | |
Simon Ser | e656697a7d | |
Simon Ser | 6bb8973309 | |
Simon Ser | 86f5ecf468 | |
Simon Ser | a37f538ca0 | |
Manuel Stoeckl | d0bb7df630 | |
Manuel Stoeckl | e879d566bb | |
Manuel Stoeckl | 3d7d6ec06f | |
Manuel Stoeckl | 7508f87fcb | |
Simon Zeni | ee210758fc | |
Simon Zeni | c0fd60be63 | |
Simon Zeni | 25bb92faee | |
Simon Ser | 33eba9080c | |
Érico Nogueira | e736ebc63c | |
Simon Zeni | fdf3169b41 | |
Simon Zeni | d1ebd52ab2 | |
Simon Zeni | 42549a1c9a | |
Simon Zeni | a143093339 | |
Simon Zeni | 5f11198605 | |
Simon Zeni | 5a98eae0dc | |
Simon Zeni | d07c87f668 | |
Simon Zeni | 6dc6af1534 | |
Simon Zeni | 0c76aef202 | |
Simon Zeni | a6538ced35 | |
Simon Zeni | 6d6e70b9e0 | |
Simon Ser | 142d10e591 | |
Demi Marie Obenour | b5d4bc3c62 | |
Simon Ser | a04cfca4da | |
Simon Ser | 9a4e1095ca | |
Roman Gilg | 8274c85d21 | |
Raphael Robatsch | 4a8e681a5f | |
Cole Mickens | 3a685b10b6 | |
Simon Zeni | 02a1ae169e | |
Isaac Freund | ab16861e86 | |
Simon Ser | 76bab68e70 | |
Simon Ser | fa77aeb80e | |
Simon Ser | f20c49d78a | |
Isaac Freund | e326b76959 | |
Simon Ser | eb5f23d6d0 | |
Kirill Primak | fc1ed72bdc | |
Isaac Freund | 8634dd3e6a | |
Simon Ser | e13f3f8608 | |
Simon Ser | 2ff4e113e2 | |
Simon Ser | 3e801d68f2 | |
Jan Beich | 760e166578 | |
Simon Ser | 8bc1086cac | |
Simon Ser | d1b75674d4 | |
tiosgz | cc2ebd9fc0 | |
Ronan Pigott | 8e225261f0 | |
Ronan Pigott | e2aff8a9b0 | |
Ronan Pigott | 6ad0f819e2 | |
Simon Ser | 83090de034 | |
Simon Ser | b2f6ff45c2 | |
Simon Ser | 0817c52a21 | |
Simon Ser | 3b96aa04db | |
Simon Ser | a80f2b2816 | |
Haelwenn (lanodan) Monnier | a92293a15a | |
Haelwenn (lanodan) Monnier | 6666604f17 | |
Haelwenn (lanodan) Monnier | 4fb652c27f | |
MarkusVolk | ebe3cfaceb | |
Simon Ser | cbedbd0fc0 | |
Simon Ser | 5619cf368b | |
Simon Ser | c43130cb89 | |
Simon Ser | bf42630d32 | |
Simon Ser | 3d6ca9942d | |
Simon Ser | fb393ddf84 | |
Simon Ser | a4ccca0834 | |
Simon Ser | db4c93028d | |
Simon Zeni | 70e8277175 | |
Simon Ser | 7c10a77e0a | |
Kirill Primak | 6c3a71d9f6 | |
buffet | 3dc99ed281 | |
Simon Ser | 36cf387427 | |
Simon Ser | f7ea33da0a | |
Joshua Ashton | b62ce3c3c8 | |
Anthony Super | e22a386319 | |
nyorain | 8e34692250 | |
Kirill Primak | 2edf468aeb | |
Kirill Primak | 2af8cc769a | |
Kirill Primak | 1089b7b8d6 | |
Simon Ser | 1b65a80e9d | |
Isaac Freund | 4fae8f7be3 | |
Isaac Freund | 2a8d385386 | |
fwsmit | dc22a06184 | |
Kirill Primak | c3e54021f8 | |
Kirill Primak | cdaab82020 | |
Kirill Primak | 28248dd83b | |
Jan Beich | 31af2b67b0 | |
Simon Ser | 13cdb84ee8 | |
tiosgz | ce66244fd2 | |
tiosgz | 893434b2d4 | |
Elyes HAOUAS | dc3d1530bf | |
Simon Ser | 323b8498ad | |
Simon Ser | 1d7e438d8a | |
Simon Ser | 61b83441a1 | |
Simon Ser | 62be833aef | |
Simon Ser | 42138a073b | |
Simon Ser | 6d281d96cb | |
Simon Ser | 780052d4da | |
Simon Ser | d6be1d68b7 | |
Simon Ser | ea7357b703 | |
Simon Ser | 833437d592 | |
Simon Ser | 744a5c2fef | |
Simon Ser | 665a164f27 | |
Simon Ser | 0e34208344 | |
Kirill Primak | db4afc2408 | |
Simon Ser | 3d0848daae | |
José Expósito | 20d9448257 | |
José Expósito | 5f3e490c80 | |
José Expósito | 4c3e307ec8 | |
José Expósito | 62e62b6942 | |
José Expósito | 52d2491931 | |
José Expósito | 95970b3619 | |
José Expósito | d069a783bc | |
José Expósito | fb15538247 | |
Hubert Hirtz | d96d2f5f23 | |
Kirill Primak | 754f40f9cb | |
Kirill Primak | 59fa3637c3 | |
Simon Ser | 3c26244340 | |
Simon Ser | 43833fba64 | |
Simon Ser | 3d4afbe945 | |
Simon Ser | 27b529f8a0 | |
Simon Ser | 63040d6744 | |
Simon Ser | fdc22449d6 | |
Simon Ser | 7939bf8cc6 | |
Simon Ser | f6f0e010d1 | |
Simon Ser | b25759cd20 | |
Tadeo Kondrak | 30d3c76817 | |
Tadeo Kondrak | e0daa65aa6 | |
Simon Ser | 2e12de96ca | |
Simon Ser | 0c5ff5efab | |
Simon Ser | 2e590026e9 | |
Simon Ser | 597ba2b932 | |
Simon Ser | 211b3b760e | |
Kirill Primak | ccc84f11a4 | |
Kirill Primak | 0e2d369106 | |
Kirill Primak | b72a217fcc | |
Simon Zeni | 9579d62a16 | |
Simon Ser | 6cb25ebad7 | |
Kirill Primak | 52da68b591 | |
Guido Günther | e479dc1ef0 | |
Simon Ser | 4e7a8707cc | |
Andri Yngvason | 105fdecd0c | |
Andri Yngvason | 04d234bac1 | |
Simon Ser | a181a37b12 | |
Simon Ser | 7832005a1f | |
Quantum | 679f5ed966 | |
Simon Ser | e05c884891 | |
Simon Ser | 44f0f7a0a7 | |
Simon Ser | 9195b77e14 | |
Simon Ser | 04d105760d | |
Simon Ser | 968c1df7e9 | |
Simon Ser | 872993f95d | |
Simon Zeni | 3984c81faa | |
Simon Zeni | c67e3fe3b7 | |
Simon Zeni | 94ed8f9496 | |
Simon Zeni | e5a949a955 | |
Simon Ser | 42dba9dc90 | |
Simon Ser | b01d97a38f | |
Simon Ser | 04304c322e | |
muradm | 35f0a0d570 | |
Simon Ser | 0c8fba1a2f | |
Simon Ser | de1c73021c | |
Simon Ser | 274c8189d4 | |
Simon Ser | 3c74bd0c91 | |
Simon Ser | 3fbf6e02a3 | |
Simon Ser | 88919464ef | |
Simon Ser | ba0525c5c0 | |
Simon Ser | 0978a702d7 | |
Simon Ser | 0fe3b45361 | |
Simon Ser | 24c397dbf8 | |
Simon Ser | bb82b6dada | |
Simon Ser | cbe099dcc7 | |
Kirill Primak | 610f0c0805 | |
Kirill Primak | cf56596565 | |
Kirill Primak | ba55c7c4ff | |
Kirill Primak | 90e62390d9 | |
Simon Ser | 3ac99fa4dc | |
Simon Ser | 56b6b80b9a | |
Kirill Primak | 242c23743f | |
Simon Ser | d290b13871 | |
Simon Ser | 62924cc523 | |
Simon Ser | 55ca93469c | |
Simon Ser | 38cd1b4f4f | |
Simon Ser | 5aa5137fae | |
Simon Ser | 7df2ae88fa | |
Devin J. Pohly | 00c2bae1d3 | |
Devin J. Pohly | e2e68ff680 | |
Devin J. Pohly | 9ed16e39fa | |
Devin J. Pohly | b7cd06e8fa | |
Devin J. Pohly | 526652a554 | |
Simon Ser | b0972a94c3 | |
Simon Ser | 267eb02c31 | |
Simon Ser | d9523faa76 | |
Simon Ser | ee6c841d47 | |
Simon Ser | d9d8fc1ab9 | |
Simon Ser | c8d97e2791 | |
Devin J. Pohly | 7ec9523ea3 | |
Devin J. Pohly | d5263be355 | |
Devin J. Pohly | 0f534e32e4 | |
Devin J. Pohly | a1d462fa81 | |
Simon Ser | b18c254e5f | |
Simon Ser | 1ad3cd7f36 | |
Simon Ser | ea800b7418 | |
Simon Ser | 2ddd8e8036 | |
Tudor Brindus | bfc69decdd | |
Simon Ser | e4d0ec9ee1 | |
Simon Ser | 501b29db03 | |
Simon Ser | 97954154bc | |
Simon Ser | 86e9309808 | |
Simon Ser | c41bd320be | |
Simon Ser | c7d489b5b6 | |
Kirill Primak | 5f645598d8 | |
Simon Ser | 5dfaf5ea9c | |
Simon Ser | 749b3c00f0 | |
Simon Ser | 3ce2ea9e16 | |
Simon Ser | b37731cdbb | |
Simon Ser | 65c0ab00b6 | |
Kirill Primak | 72a156b18a | |
Kirill Primak | 664307f968 | |
Isaac Freund | f2f3df9fb1 | |
Guido Günther | de1522aeee | |
Rouven Czerwinski | 9b7803a9b3 | |
Simon Ser | 18c2dce65e | |
Simon Ser | 46c42e55c6 | |
Kirill Primak | 109405729b | |
Rouven Czerwinski | cdd9a60f72 | |
Rouven Czerwinski | aa78c50bf1 | |
Rouven Czerwinski | 59b292b691 | |
Simon Ser | 7544b7abf9 | |
Michele Sorcinelli | cae7b98136 | |
Tudor Brindus | 0c19a28266 | |
Isaac Freund | 3364eec07e | |
Simon Ser | ad7651a370 | |
Simon Ser | ee1156b62b | |
Simon Ser | 93964012e6 | |
Simon Ser | 20404ed8bb | |
Simon Ser | 3f9e4f7a44 | |
Kirill Primak | 111d4eafd7 | |
Kirill Primak | debd6c5f0b | |
Kirill Primak | 11f799e88e | |
Kirill Primak | a6a80850b7 | |
Simon Ser | 604674dc54 | |
Simon Ser | eb0ce659cf | |
Simon Ser | 88f65db87f | |
Tudor Brindus | 033c9cab74 | |
Simon Ser | c27263c105 | |
Simon Ser | d48ffac56b | |
Simon Ser | ca0b19fc9c | |
Simon Ser | 1936e136df | |
Simon Ser | df0e75ba05 | |
Simon Ser | 8a3cd28973 | |
Simon Ser | b913e64f95 | |
Simon Ser | 923258b0be | |
Kirill Primak | f12bacf4b4 | |
Quantum | 456c6e2279 | |
Manuel Stoeckl | f5df956c18 | |
Manuel Stoeckl | 44e8451cd9 | |
Manuel Stoeckl | 4dc52bcb6c | |
Simon Ser | f76960388f | |
Simon Ser | 6973361d60 | |
Simon Ser | 3132c0ab10 | |
Simon Ser | f211bc983a | |
Simon Ser | 4ddde1a7bd | |
Simon Ser | d17a009062 | |
Simon Ser | 55ac7e335a | |
Simon Ser | c55f70c8b7 | |
Simon Ser | c74dc45bb6 | |
Simon Ser | 9b99570869 | |
Simon Ser | ebb661532c | |
Simon Ser | f5900c1f00 | |
Simon Ser | 85d7ad2eef | |
Simon Ser | 6aadf811aa | |
Simon Ser | 0fb55c76d0 | |
Simon Ser | 1a5b6722a8 | |
Simon Ser | d6f0fc251e | |
Simon Ser | d1c931cbe8 | |
Dylan Araps | e5063ef3a3 | |
Simon Zeni | 6f19295647 | |
yuiiio | 7667ab73bd | |
Simon Ser | 770a561bce | |
Simon Ser | 4b316a3823 | |
Simon Ser | 3cf2535c23 | |
Simon Ser | ace2eda073 | |
Simon Zeni | 04d4fb536d | |
Simon Zeni | 0778151f94 | |
Simon Zeni | 646a25667e | |
Simon Zeni | f09c88c1b7 | |
Simon Ser | 2fa47c1837 | |
ayaka | 70fb21c35b | |
Simon Ser | 66c42f4fcb | |
Simon Ser | cc8bc0db20 | |
Simon Ser | 8afb4d8bf0 | |
Simon Ser | f94eb174c7 | |
Vyivel | a93b18dbd5 | |
Simon Ser | a47f89cf7c | |
Simon Ser | bcd5d8504c | |
Simon Ser | 709190c4c8 | |
Simon Ser | aec062d0d3 | |
Simon Ser | 87e8c60faf | |
Simon Ser | 28aa803916 | |
Simon Ser | 5544973814 | |
Simon Ser | 9dba176e8d | |
Simon Ser | 9b70eab194 | |
Simon Ser | 4c51a0f6eb | |
Simon Ser | 4554f17377 | |
Simon Ser | d7c68ce632 | |
Simon Ser | a0baba4fa0 | |
Simon Ser | 0abb67c478 | |
Simon Ser | 7b25b0ff88 | |
Simon Zeni | 60f4d8f409 | |
Simon Zeni | d086501fba | |
Simon Zeni | 6d8029b07e | |
Simon Ser | f67cfb2ce2 | |
Simon Ser | fde56c20b4 | |
Simon Ser | 017555651b | |
Vyivel | a362d21d6b | |
Simon Ser | c1b27cc499 | |
Simon Ser | d71ed635b9 | |
Simon Ser | e035f2b9c4 | |
Simon Ser | b934fbaf04 | |
Simon Ser | 22fd411bc3 | |
Simon Ser | c1902cdb3f | |
Simon Ser | 8eef6a8843 | |
Simon Ser | 2d36d7fb67 | |
Simon Ser | 84906a832f | |
Simon Ser | a48e569d38 | |
Simon Ser | c2bd63c186 | |
Simon Zeni | 4c7657ee62 | |
Simon Zeni | e192d87731 | |
Simon Zeni | d975f35bba | |
Simon Ser | 3fdf8cf07e | |
Simon Ser | 9a8097682b | |
Simon Ser | d3d1c69aca | |
Simon Ser | 8a4957570f | |
Simon Ser | e5b5592a95 | |
Simon Ser | 4e07d4cbf9 | |
Simon Ser | d7b19fb294 | |
Simon Ser | c868e509b7 | |
Simon Ser | f7e3d325fe | |
Simon Ser | 78121ad2d8 | |
Simon Ser | 4dee7a2f6f | |
Simon Ser | 5f26360bd8 | |
Simon Ser | e8c408b31b | |
Simon Ser | 82af6e7208 | |
Simon Ser | 475d9701e2 | |
Simon Ser | c7018a45b7 | |
Simon Ser | 0a522cb798 | |
Simon Ser | a38baec1f8 | |
Simon Ser | 29be2d47e4 | |
Simon Ser | 7ad44051a2 | |
Simon Ser | 08e5b909f9 | |
Simon Ser | 18adb43a44 | |
Simon Ser | 29c8df7e0a | |
Simon Ser | 7ec66a9990 | |
Simon Ser | ea585dba0f | |
Simon Ser | 57b70a478c | |
Simon Ser | 5888c96da8 | |
Simon Ser | e6cb11d882 | |
Simon Ser | a6ed4ae308 | |
Simon Ser | dbb0e2f75b | |
Simon Ser | 1db976cecb | |
Simon Ser | 1c4b5bcab3 | |
Simon Ser | 1b4fb4b537 | |
Simon Ser | bcbdee43f7 | |
Simon Ser | 7cbcc65ad0 | |
Simon Ser | ddc98bf593 | |
Simon Ser | 634a20d89c | |
Simon Ser | f6ae028e99 | |
Simon Ser | 787842c459 | |
Simon Ser | 31db232704 | |
Simon Ser | d2b6b570ea | |
Simon Ser | a2419eb4ea | |
Simon Ser | b69db15da6 | |
Simon Ser | 264d4e2bce | |
Simon Ser | 0467a7523a |
|
@ -2,11 +2,14 @@ image: alpine/edge
|
|||
packages:
|
||||
- eudev-dev
|
||||
- ffmpeg-dev
|
||||
- glslang
|
||||
- libinput-dev
|
||||
- libxkbcommon-dev
|
||||
- mesa-dev
|
||||
- meson
|
||||
- pixman-dev
|
||||
- vulkan-headers
|
||||
- vulkan-loader-dev
|
||||
- wayland-dev
|
||||
- wayland-protocols
|
||||
- xcb-util-image-dev
|
||||
|
@ -15,11 +18,11 @@ packages:
|
|||
- xwayland
|
||||
- libseat-dev
|
||||
sources:
|
||||
- https://github.com/swaywm/wlroots
|
||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
tasks:
|
||||
- setup: |
|
||||
cd wlroots
|
||||
meson build --default-library=both -Dauto_features=enabled -Dlibseat=disabled -Dxcb-errors=disabled
|
||||
meson build --fatal-meson-warnings --default-library=both -Dauto_features=enabled -Dxcb-errors=disabled
|
||||
- build: |
|
||||
cd wlroots
|
||||
ninja -C build
|
||||
|
|
|
@ -15,19 +15,31 @@ packages:
|
|||
- xcb-util-wm
|
||||
- xorg-xwayland
|
||||
- seatd
|
||||
- vulkan-icd-loader
|
||||
- vulkan-headers
|
||||
- glslang
|
||||
sources:
|
||||
- https://github.com/swaywm/wlroots
|
||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
tasks:
|
||||
- setup: |
|
||||
cd wlroots
|
||||
CC=gcc meson build-gcc --default-library=both -Dauto_features=enabled --prefix /usr
|
||||
CC=clang meson build-clang -Dauto_features=enabled
|
||||
CC=gcc meson build-gcc --fatal-meson-warnings --default-library=both -Dauto_features=enabled --prefix /usr -Db_sanitize=address,undefined
|
||||
CC=clang meson build-clang --fatal-meson-warnings -Dauto_features=enabled
|
||||
- gcc: |
|
||||
cd wlroots/build-gcc
|
||||
ninja
|
||||
sudo ninja install
|
||||
cd ../tinywl
|
||||
make
|
||||
CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" make
|
||||
- clang: |
|
||||
cd wlroots/build-clang
|
||||
ninja
|
||||
- smoke-test: |
|
||||
cd wlroots/tinywl
|
||||
sudo modprobe vkms
|
||||
udevadm settle
|
||||
export WLR_BACKENDS=drm
|
||||
export WLR_RENDERER=pixman
|
||||
export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
|
||||
sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
|
||||
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]
|
||||
|
|
|
@ -5,9 +5,12 @@ packages:
|
|||
- devel/libudev-devd
|
||||
- devel/meson # implies ninja
|
||||
- devel/pkgconf
|
||||
- graphics/glslang
|
||||
- graphics/libdrm
|
||||
- graphics/mesa-libs
|
||||
- graphics/png
|
||||
- graphics/vulkan-headers
|
||||
- graphics/vulkan-loader
|
||||
- graphics/wayland
|
||||
- graphics/wayland-protocols
|
||||
- multimedia/ffmpeg
|
||||
|
@ -23,11 +26,11 @@ packages:
|
|||
- sysutils/seatd
|
||||
- gmake
|
||||
sources:
|
||||
- https://github.com/swaywm/wlroots
|
||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
tasks:
|
||||
- wlroots: |
|
||||
cd wlroots
|
||||
meson build -Dauto_features=enabled
|
||||
meson build --fatal-meson-warnings -Dauto_features=enabled
|
||||
ninja -C build
|
||||
sudo ninja -C build install
|
||||
- tinywl: |
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
|
||||
alpine:
|
||||
extends: .dalligi
|
||||
archlinux:
|
||||
extends: .dalligi
|
||||
freebsd:
|
||||
extends: .dalligi
|
107
CONTRIBUTING.md
107
CONTRIBUTING.md
|
@ -1,22 +1,21 @@
|
|||
# Contributing to wlroots
|
||||
|
||||
Contributing just involves sending a pull request. You will probably be more
|
||||
successful with your contribution if you visit
|
||||
[#sway-devel on Libera Chat](https://web.libera.chat/?channels=#sway-devel) upfront and
|
||||
discuss your plans.
|
||||
Contributing just involves sending a merge request. You will probably be more
|
||||
successful with your contribution if you visit [#sway-devel on Libera Chat]
|
||||
upfront and discuss your plans.
|
||||
|
||||
Note: rules are made to be broken. Adjust or ignore any/all of these as you see
|
||||
fit, but be prepared to justify it to your peers.
|
||||
|
||||
## Pull Requests
|
||||
## Merge Requests
|
||||
|
||||
If you already have your own pull request habits, feel free to use them. If you
|
||||
If you already have your own merge request habits, feel free to use them. If you
|
||||
don't, however, allow me to make a suggestion: feature branches pulled from
|
||||
upstream. Try this:
|
||||
|
||||
1. Fork wlroots
|
||||
2. `git clone https://github.com/username/wlroots && cd wlroots`
|
||||
3. `git remote add upstream https://github.com/swaywm/wlroots`
|
||||
2. `git clone git@gitlab.freedesktop.org:<username>/wlroots.git && cd wlroots`
|
||||
3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git`
|
||||
|
||||
You only need to do this once. You're never going to use your fork's master
|
||||
branch. Instead, when you start working on a feature, do this:
|
||||
|
@ -25,42 +24,74 @@ branch. Instead, when you start working on a feature, do this:
|
|||
2. `git checkout -b add-so-and-so-feature upstream/master`
|
||||
3. Add and commit your changes
|
||||
4. `git push -u origin add-so-and-so-feature`
|
||||
5. Make a pull request from your feature branch
|
||||
5. Make a merge request from your feature branch
|
||||
|
||||
When you submit your pull request, your commit log should do most of the talking
|
||||
When you submit your merge request, your commit log should do most of the talking
|
||||
when it comes to describing your changes and their motivation. In addition to
|
||||
this, your pull request's comments will ideally include a test plan that the
|
||||
this, your merge request's comments will ideally include a test plan that the
|
||||
reviewers can use to (1) demonstrate the problem on master, if applicable and
|
||||
(2) verify that the problem no longer exists with your changes applied (or that
|
||||
your new features work correctly). Document all of the edge cases you're aware
|
||||
of so we can adequately test them - then verify the test plan yourself before
|
||||
submitting.
|
||||
|
||||
## Commit Log
|
||||
|
||||
Unlike many projects using GitHub and GitLab, wlroots has a [linear, "recipe"
|
||||
style] history. This means that every commit should be small, digestible,
|
||||
stand-alone, and functional. Rather than a purely chronological commit history
|
||||
like this:
|
||||
|
||||
```
|
||||
doc: final docs for view transforms
|
||||
fix tests when disabled, redo broken doc formatting
|
||||
better transformed-view iteration (thanks Hannah!)
|
||||
try to catch more cases in tests
|
||||
tests: add new spline test
|
||||
fix compilation on splines
|
||||
doc: notes on reticulating splines
|
||||
compositor: add spline reticulation for view transforms
|
||||
```
|
||||
|
||||
We aim to have a clean history which only reflects the final state, broken up
|
||||
into functional groupings:
|
||||
|
||||
```
|
||||
compositor: add spline reticulation for view transforms
|
||||
compositor: new iterator for view transforms
|
||||
tests: add view-transform correctness tests
|
||||
doc: fix formatting for view transforms
|
||||
```
|
||||
|
||||
This ensures that the final patch series only contains the final state,
|
||||
without the changes and missteps taken along the development process. A linear
|
||||
history eases reviewing, cherry-picking and reverting changes.
|
||||
|
||||
If you aren't comfortable with manipulating the Git history, have a look at
|
||||
[git-rebase.io].
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Please strive to write good commit messages. Here's some guidelines to follow:
|
||||
|
||||
The first line should be limited to 50 characters and should be a sentence that
|
||||
completes the thought [When applied, this commit will...] *"Implement
|
||||
cmd_move"* or *"Fix #742"* or *"Improve performance of arrange_windows on ARM"*
|
||||
or similar.
|
||||
cmd_move"* or *"Improve performance of arrange_windows on ARM"* or similar.
|
||||
|
||||
The subsequent lines should be separated from the subject line by a single
|
||||
blank line, and include optional details. In this you can give justification
|
||||
for the change, [reference Github
|
||||
issues](https://help.github.com/articles/closing-issues-via-commit-messages/),
|
||||
or explain some of the subtler details of your patch. This is important because
|
||||
when someone finds a line of code they don't understand later, they can use the
|
||||
`git blame` command to find out what the author was thinking when they wrote
|
||||
it. It's also easier to review your pull requests if they're separated into
|
||||
logical commits that have good commit messages and justify themselves in the
|
||||
extended commit description.
|
||||
for the change, [reference issues], or explain some of the subtler
|
||||
details of your patch. This is important because when someone finds a line of
|
||||
code they don't understand later, they can use the `git blame` command to find
|
||||
out what the author was thinking when they wrote it. It's also easier to review
|
||||
your merge requests if they're separated into logical commits that have good
|
||||
commit messages and justify themselves in the extended commit description.
|
||||
|
||||
As a good rule of thumb, anything you might put into the pull request
|
||||
description on Github is probably fair game for going into the extended commit
|
||||
As a good rule of thumb, anything you might put into the merge request
|
||||
description on GitLab is probably fair game for going into the extended commit
|
||||
message as well.
|
||||
|
||||
See [here](https://chris.beams.io/posts/git-commit/) for more details.
|
||||
See [How to Write a Git Commit Message] for more details.
|
||||
|
||||
## Code Review
|
||||
|
||||
|
@ -70,23 +101,29 @@ changes will typically see review from several people. Be prepared to receive
|
|||
some feedback - you may be asked to make changes to your work. Our code review
|
||||
process is:
|
||||
|
||||
1. **Triage** the pull request. Do the commit messages make sense? Is a test
|
||||
1. **Triage** the merge request. Do the commit messages make sense? Is a test
|
||||
plan necessary and/or present? Add anyone as reviewers that you think should
|
||||
be there (using the relevant GitHub feature, if you have the permissions, or
|
||||
be there (using the relevant GitLab feature, if you have the permissions, or
|
||||
with an @mention if necessary).
|
||||
2. **Review** the code. Look for code style violations, naming convention
|
||||
violations, buffer overflows, memory leaks, logic errors, non-portable code
|
||||
(including GNU-isms), etc. For significant changes to the public API, loop in
|
||||
a couple more people for discussion.
|
||||
3. **Execute** the test plan, if present.
|
||||
4. **Merge** the pull request when all reviewers approve.
|
||||
4. **Merge** the merge request when all reviewers approve.
|
||||
5. **File** follow-up tickets if appropriate.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Note that as a project hosted on freedesktop.org, wlroots follows its
|
||||
[Code of Conduct], based on the Contributor Covenant. Please conduct yourself
|
||||
in a respectful and civilized manner when communicating with community members
|
||||
on IRC and bug tracker.
|
||||
|
||||
## Style Reference
|
||||
|
||||
wlroots is written in C with a style similar to the [kernel
|
||||
style](https://www.kernel.org/doc/Documentation/process/coding-style.rst), but
|
||||
with a few notable differences.
|
||||
wlroots is written in C with a style similar to the [kernel style], but with a
|
||||
few notable differences.
|
||||
|
||||
Try to keep your code conforming to C11 and POSIX as much as possible, and do
|
||||
not use GNU extensions.
|
||||
|
@ -163,7 +200,7 @@ zeroed value and exit cleanly; this simplifies error handling a lot.
|
|||
### Error Codes
|
||||
|
||||
For functions not returning a value, they should return a (stdbool.h) bool to
|
||||
indicated if they succeeded or not.
|
||||
indicate whether they succeeded or not.
|
||||
|
||||
### Macros
|
||||
|
||||
|
@ -362,3 +399,11 @@ static void subsurface_handle_surface_destroy(struct wl_listener *listener,
|
|||
subsurface_destroy(subsurface);
|
||||
}
|
||||
```
|
||||
|
||||
[#sway-devel on Libera Chat]: https://web.libera.chat/gamja/?channels=#sway-devel
|
||||
[linear, "recipe" style]: https://www.bitsnbites.eu/git-history-work-log-vs-recipe/
|
||||
[git-rebase.io]: https://git-rebase.io/
|
||||
[reference issues]: https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically
|
||||
[Code of Conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/
|
||||
[How to Write a Git Commit Message]: https://chris.beams.io/posts/git-commit/
|
||||
[kernel style]: https://www.kernel.org/doc/Documentation/process/coding-style.rst
|
||||
|
|
22
README.md
22
README.md
|
@ -1,7 +1,13 @@
|
|||
# blankie/wlroots - dkondor-upstream-pr-2551
|
||||
|
||||
This branch "frontports" https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2551,
|
||||
should be updated when there's a new wlroots version and be unmaintained
|
||||
when the pull request above is merged
|
||||
|
||||
# wlroots
|
||||
|
||||
Pluggable, composable, unopinionated modules for building a [Wayland]
|
||||
compositor; or about 50,000 lines of code you were going to write anyway.
|
||||
compositor; or about 60,000 lines of code you were going to write anyway.
|
||||
|
||||
- wlroots provides backends that abstract the underlying display and input
|
||||
hardware, including KMS/DRM, libinput, Wayland, X11, and headless backends,
|
||||
|
@ -43,11 +49,11 @@ Install dependencies:
|
|||
* meson
|
||||
* wayland
|
||||
* wayland-protocols
|
||||
* EGL
|
||||
* GLESv2
|
||||
* EGL and GLESv2 (optional, for the GLES2 renderer)
|
||||
* Vulkan loader, headers and glslang (optional, for the Vulkan renderer)
|
||||
* libdrm
|
||||
* GBM
|
||||
* libinput
|
||||
* libinput (optional, for the libinput backend)
|
||||
* xkbcommon
|
||||
* udev
|
||||
* pixman
|
||||
|
@ -75,9 +81,9 @@ Install like so:
|
|||
See [CONTRIBUTING.md].
|
||||
|
||||
[Wayland]: https://wayland.freedesktop.org/
|
||||
[wiki]: https://github.com/swaywm/wlroots/wiki/Getting-started
|
||||
[#sway-devel on Libera Chat]: https://web.libera.chat/?channels=#sway-devel
|
||||
[wiki]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Getting-started
|
||||
[#sway-devel on Libera Chat]: https://web.libera.chat/gamja/?channels=#sway-devel
|
||||
[Sway]: https://github.com/swaywm/sway
|
||||
[wrapper libraries]: https://github.com/search?q=topic%3Abindings+org%3Aswaywm&type=Repositories
|
||||
[wrapper libraries]: https://gitlab.freedesktop.org/wlroots/wlroots/-/wikis/Projects-which-use-wlroots#wrapper-libraries
|
||||
[libseat]: https://git.sr.ht/~kennylevinsen/seatd
|
||||
[CONTRIBUTING.md]: https://github.com/swaywm/wlroots/blob/master/CONTRIBUTING.md
|
||||
[CONTRIBUTING.md]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/CONTRIBUTING.md
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libinput.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend/drm.h>
|
||||
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/backend/libinput.h>
|
||||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/noop.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/backend/wayland.h>
|
||||
#include <wlr/config.h>
|
||||
|
@ -19,13 +16,24 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/multi.h"
|
||||
#include "render/allocator.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
#include <wlr/backend/drm.h>
|
||||
#include "backend/drm/monitor.h"
|
||||
#endif
|
||||
|
||||
#if WLR_HAS_LIBINPUT_BACKEND
|
||||
#include <wlr/backend/libinput.h>
|
||||
#endif
|
||||
|
||||
#if WLR_HAS_X11_BACKEND
|
||||
#include <wlr/backend/x11.h>
|
||||
#endif
|
||||
|
||||
#define WAIT_SESSION_TIMEOUT 10000 // ms
|
||||
|
||||
void wlr_backend_init(struct wlr_backend *backend,
|
||||
const struct wlr_backend_impl *impl) {
|
||||
assert(backend);
|
||||
|
@ -37,8 +45,6 @@ void wlr_backend_init(struct wlr_backend *backend,
|
|||
|
||||
void wlr_backend_finish(struct wlr_backend *backend) {
|
||||
wlr_signal_emit_safe(&backend->events.destroy, backend);
|
||||
wlr_allocator_destroy(backend->allocator);
|
||||
wlr_renderer_destroy(backend->renderer);
|
||||
}
|
||||
|
||||
bool wlr_backend_start(struct wlr_backend *backend) {
|
||||
|
@ -60,35 +66,6 @@ void wlr_backend_destroy(struct wlr_backend *backend) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool backend_create_renderer(struct wlr_backend *backend) {
|
||||
if (backend->renderer != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
backend->renderer = wlr_renderer_autocreate(backend);
|
||||
if (backend->renderer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend) {
|
||||
if (backend->impl->get_renderer) {
|
||||
return backend->impl->get_renderer(backend);
|
||||
}
|
||||
if (backend_get_buffer_caps(backend) != 0) {
|
||||
// If the backend is capable of presenting buffers, automatically create
|
||||
// the renderer if necessary.
|
||||
if (!backend_create_renderer(backend)) {
|
||||
wlr_log(WLR_ERROR, "Failed to create backend renderer");
|
||||
return NULL;
|
||||
}
|
||||
return backend->renderer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) {
|
||||
if (backend->impl->get_session) {
|
||||
return backend->impl->get_session(backend);
|
||||
|
@ -96,6 +73,52 @@ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t get_current_time_ms(void) {
|
||||
struct timespec ts = {0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static struct wlr_session *session_create_and_wait(struct wl_display *disp) {
|
||||
struct wlr_session *session = wlr_session_create(disp);
|
||||
|
||||
if (!session) {
|
||||
wlr_log(WLR_ERROR, "Failed to start a session");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!session->active) {
|
||||
wlr_log(WLR_INFO, "Waiting for a session to become active");
|
||||
|
||||
uint64_t started_at = get_current_time_ms();
|
||||
uint64_t timeout = WAIT_SESSION_TIMEOUT;
|
||||
struct wl_event_loop *event_loop =
|
||||
wl_display_get_event_loop(session->display);
|
||||
|
||||
while (!session->active) {
|
||||
int ret = wl_event_loop_dispatch(event_loop, (int)timeout);
|
||||
if (ret < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to wait for session active: "
|
||||
"wl_event_loop_dispatch failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t now = get_current_time_ms();
|
||||
if (now >= started_at + WAIT_SESSION_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
timeout = started_at + WAIT_SESSION_TIMEOUT - now;
|
||||
}
|
||||
|
||||
if (!session->active) {
|
||||
wlr_log(WLR_ERROR, "Timeout waiting session to become active");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
clockid_t wlr_backend_get_presentation_clock(struct wlr_backend *backend) {
|
||||
if (backend->impl->get_presentation_clock) {
|
||||
return backend->impl->get_presentation_clock(backend);
|
||||
|
@ -118,23 +141,6 @@ uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
|
|||
return backend->impl->get_buffer_caps(backend);
|
||||
}
|
||||
|
||||
struct wlr_allocator *backend_get_allocator(struct wlr_backend *backend) {
|
||||
if (backend->allocator != NULL) {
|
||||
return backend->allocator;
|
||||
}
|
||||
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(backend);
|
||||
if (renderer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
backend->allocator = wlr_allocator_autocreate(backend, renderer);
|
||||
if (backend->allocator == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create backend allocator");
|
||||
}
|
||||
return backend->allocator;
|
||||
}
|
||||
|
||||
static size_t parse_outputs_env(const char *name) {
|
||||
const char *outputs_str = getenv(name);
|
||||
if (outputs_str == NULL) {
|
||||
|
@ -197,20 +203,7 @@ static struct wlr_backend *attempt_headless_backend(
|
|||
return backend;
|
||||
}
|
||||
|
||||
static struct wlr_backend *attempt_noop_backend(struct wl_display *display) {
|
||||
struct wlr_backend *backend = wlr_noop_backend_create(display);
|
||||
if (backend == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t outputs = parse_outputs_env("WLR_NOOP_OUTPUTS");
|
||||
for (size_t i = 0; i < outputs; ++i) {
|
||||
wlr_noop_add_output(backend);
|
||||
}
|
||||
|
||||
return backend;
|
||||
}
|
||||
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
||||
struct wlr_backend *backend, struct wlr_session *session) {
|
||||
struct wlr_device *gpus[8];
|
||||
|
@ -220,7 +213,12 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (num_gpus == 0) {
|
||||
wlr_log(WLR_ERROR, "Found 0 GPUs, cannot create backend");
|
||||
return NULL;
|
||||
} else {
|
||||
wlr_log(WLR_INFO, "Found %zu GPUs", num_gpus);
|
||||
}
|
||||
|
||||
struct wlr_backend *primary_drm = NULL;
|
||||
for (size_t i = 0; i < (size_t)num_gpus; ++i) {
|
||||
|
@ -237,42 +235,53 @@ static struct wlr_backend *attempt_drm_backend(struct wl_display *display,
|
|||
|
||||
wlr_multi_backend_add(backend, drm);
|
||||
}
|
||||
if (!primary_drm) {
|
||||
wlr_log(WLR_ERROR, "Could not successfully create backend on any GPU");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return primary_drm;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct wlr_backend *attempt_backend_by_name(struct wl_display *display,
|
||||
struct wlr_backend *backend, struct wlr_session **session,
|
||||
const char *name) {
|
||||
static bool attempt_backend_by_name(struct wl_display *display,
|
||||
struct wlr_multi_backend *multi, char *name) {
|
||||
struct wlr_backend *backend = NULL;
|
||||
if (strcmp(name, "wayland") == 0) {
|
||||
return attempt_wl_backend(display);
|
||||
backend = attempt_wl_backend(display);
|
||||
#if WLR_HAS_X11_BACKEND
|
||||
} else if (strcmp(name, "x11") == 0) {
|
||||
return attempt_x11_backend(display, NULL);
|
||||
backend = attempt_x11_backend(display, NULL);
|
||||
#endif
|
||||
} else if (strcmp(name, "headless") == 0) {
|
||||
return attempt_headless_backend(display);
|
||||
} else if (strcmp(name, "noop") == 0) {
|
||||
return attempt_noop_backend(display);
|
||||
backend = attempt_headless_backend(display);
|
||||
} else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) {
|
||||
// DRM and libinput need a session
|
||||
if (!*session) {
|
||||
*session = wlr_session_create(display);
|
||||
if (!*session) {
|
||||
if (multi->session == NULL) {
|
||||
multi->session = session_create_and_wait(display);
|
||||
if (multi->session == NULL) {
|
||||
wlr_log(WLR_ERROR, "failed to start a session");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(name, "libinput") == 0) {
|
||||
return wlr_libinput_backend_create(display, *session);
|
||||
#if WLR_HAS_LIBINPUT_BACKEND
|
||||
backend = wlr_libinput_backend_create(display, multi->session);
|
||||
#endif
|
||||
} else {
|
||||
return attempt_drm_backend(display, backend, *session);
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
// attempt_drm_backend adds the multi drm backends itself
|
||||
return attempt_drm_backend(display, &multi->backend,
|
||||
multi->session) != NULL;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "unrecognized backend '%s'", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_log(WLR_ERROR, "unrecognized backend '%s'", name);
|
||||
return NULL;
|
||||
return wlr_multi_backend_add(&multi->backend, backend);
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
|
||||
|
@ -298,17 +307,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
|
|||
char *saveptr;
|
||||
char *name = strtok_r(names, ",", &saveptr);
|
||||
while (name != NULL) {
|
||||
struct wlr_backend *subbackend = attempt_backend_by_name(display,
|
||||
backend, &multi->session, name);
|
||||
if (subbackend == NULL) {
|
||||
wlr_log(WLR_ERROR, "failed to start backend '%s'", name);
|
||||
wlr_session_destroy(multi->session);
|
||||
wlr_backend_destroy(backend);
|
||||
free(names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!wlr_multi_backend_add(backend, subbackend)) {
|
||||
if (!attempt_backend_by_name(display, multi, name)) {
|
||||
wlr_log(WLR_ERROR, "failed to add backend '%s'", name);
|
||||
wlr_session_destroy(multi->session);
|
||||
wlr_backend_destroy(backend);
|
||||
|
@ -348,13 +347,14 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
|
|||
#endif
|
||||
|
||||
// Attempt DRM+libinput
|
||||
multi->session = wlr_session_create(display);
|
||||
multi->session = session_create_and_wait(display);
|
||||
if (!multi->session) {
|
||||
wlr_log(WLR_ERROR, "Failed to start a DRM session");
|
||||
wlr_backend_destroy(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if WLR_HAS_LIBINPUT_BACKEND
|
||||
struct wlr_backend *libinput = wlr_libinput_backend_create(display,
|
||||
multi->session);
|
||||
if (!libinput) {
|
||||
|
@ -364,18 +364,35 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
|
|||
return NULL;
|
||||
}
|
||||
wlr_multi_backend_add(backend, libinput);
|
||||
#else
|
||||
const char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES");
|
||||
if (no_devs && strcmp(no_devs, "1") == 0) {
|
||||
wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, "
|
||||
"starting without libinput backend");
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "libinput support is not compiled in, "
|
||||
"refusing to start");
|
||||
wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check");
|
||||
wlr_session_destroy(multi->session);
|
||||
wlr_backend_destroy(backend);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
struct wlr_backend *primary_drm =
|
||||
attempt_drm_backend(display, backend, multi->session);
|
||||
if (!primary_drm) {
|
||||
wlr_log(WLR_ERROR, "Failed to open any DRM device");
|
||||
wlr_backend_destroy(libinput);
|
||||
wlr_session_destroy(multi->session);
|
||||
wlr_backend_destroy(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drm_backend_monitor_create(backend, primary_drm, multi->session);
|
||||
|
||||
return backend;
|
||||
#endif
|
||||
|
||||
error:
|
||||
wlr_backend_destroy(backend);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <gbm.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
|
@ -55,16 +54,14 @@ static void atomic_add(struct atomic *atom, uint32_t id, uint32_t prop, uint64_t
|
|||
}
|
||||
|
||||
static bool create_mode_blob(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_connector *conn, const struct wlr_output_state *state,
|
||||
uint32_t *blob_id) {
|
||||
if (!drm_connector_state_active(conn, state)) {
|
||||
struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state, uint32_t *blob_id) {
|
||||
if (!state->active) {
|
||||
*blob_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
drmModeModeInfo mode = {0};
|
||||
drm_connector_state_mode(conn, state, &mode);
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &mode,
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &state->mode,
|
||||
sizeof(drmModeModeInfo), blob_id)) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to create mode property blob");
|
||||
return false;
|
||||
|
@ -144,8 +141,8 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
|
|||
goto error;
|
||||
}
|
||||
|
||||
uint32_t width = gbm_bo_get_width(fb->bo);
|
||||
uint32_t height = gbm_bo_get_height(fb->bo);
|
||||
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);
|
||||
|
@ -166,14 +163,15 @@ error:
|
|||
atom->failed = true;
|
||||
}
|
||||
|
||||
static bool atomic_crtc_commit(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_connector *conn, const struct wlr_output_state *state,
|
||||
uint32_t flags) {
|
||||
static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state, uint32_t flags,
|
||||
bool test_only) {
|
||||
struct wlr_drm_backend *drm = conn->backend;
|
||||
struct wlr_output *output = &conn->output;
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
||||
bool modeset = drm_connector_state_is_modeset(state);
|
||||
bool active = drm_connector_state_active(conn, state);
|
||||
bool modeset = state->modeset;
|
||||
bool active = state->active;
|
||||
|
||||
uint32_t mode_id = crtc->mode_id;
|
||||
if (modeset) {
|
||||
|
@ -183,35 +181,51 @@ static bool atomic_crtc_commit(struct wlr_drm_backend *drm,
|
|||
}
|
||||
|
||||
uint32_t gamma_lut = crtc->gamma_lut;
|
||||
if (state->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
// 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->gamma_lut_size,
|
||||
state->gamma_lut)) {
|
||||
state->base->gamma_lut_size,
|
||||
state->base->gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!create_gamma_lut_blob(drm, state->gamma_lut_size,
|
||||
state->gamma_lut, &gamma_lut)) {
|
||||
if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
|
||||
state->base->gamma_lut, &gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fb_damage_clips = 0;
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_DAMAGE) &&
|
||||
pixman_region32_not_empty((pixman_region32_t *)&state->base->damage) &&
|
||||
crtc->primary->props.fb_damage_clips != 0) {
|
||||
int rects_len;
|
||||
const pixman_box32_t *rects = pixman_region32_rectangles(
|
||||
(pixman_region32_t *)&state->base->damage, &rects_len);
|
||||
if (drmModeCreatePropertyBlob(drm->fd, rects,
|
||||
sizeof(*rects) * rects_len, &fb_damage_clips) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
|
||||
}
|
||||
}
|
||||
|
||||
bool prev_vrr_enabled =
|
||||
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
|
||||
bool vrr_enabled = prev_vrr_enabled;
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
|
||||
drm_connector_supports_vrr(conn)) {
|
||||
vrr_enabled = state->adaptive_sync_enabled;
|
||||
vrr_enabled = state->base->adaptive_sync_enabled;
|
||||
}
|
||||
|
||||
if (test_only) {
|
||||
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
|
||||
}
|
||||
if (modeset) {
|
||||
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
} else if (!(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
|
||||
} else if (!test_only) {
|
||||
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
||||
}
|
||||
|
||||
|
@ -232,6 +246,10 @@ static bool atomic_crtc_commit(struct wlr_drm_backend *drm,
|
|||
atomic_add(&atom, crtc->id, crtc->props.vrr_enabled, vrr_enabled);
|
||||
}
|
||||
set_plane_props(&atom, drm, crtc->primary, crtc->id, 0, 0);
|
||||
if (crtc->primary->props.fb_damage_clips != 0) {
|
||||
atomic_add(&atom, crtc->primary->id,
|
||||
crtc->primary->props.fb_damage_clips, fb_damage_clips);
|
||||
}
|
||||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
set_plane_props(&atom, drm, crtc->cursor, crtc->id,
|
||||
|
@ -250,7 +268,7 @@ static bool atomic_crtc_commit(struct wlr_drm_backend *drm,
|
|||
bool ok = atomic_commit(&atom, conn, flags);
|
||||
atomic_finish(&atom);
|
||||
|
||||
if (ok && !(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
|
||||
if (ok && !test_only) {
|
||||
commit_blob(drm, &crtc->mode_id, mode_id);
|
||||
commit_blob(drm, &crtc->gamma_lut, gamma_lut);
|
||||
|
||||
|
@ -266,6 +284,11 @@ static bool atomic_crtc_commit(struct wlr_drm_backend *drm,
|
|||
rollback_blob(drm, &crtc->gamma_lut, gamma_lut);
|
||||
}
|
||||
|
||||
if (fb_damage_clips != 0 &&
|
||||
drmModeDestroyPropertyBlob(drm->fd, fb_damage_clips) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to destroy FB_DAMAGE_CLIPS property blob");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include "backend/drm/drm.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
struct wlr_drm_backend *get_drm_backend_from_backend(
|
||||
|
@ -24,7 +22,7 @@ struct wlr_drm_backend *get_drm_backend_from_backend(
|
|||
|
||||
static bool backend_start(struct wlr_backend *backend) {
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
|
||||
scan_drm_connectors(drm);
|
||||
scan_drm_connectors(drm, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -35,8 +33,6 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
|
||||
|
||||
restore_drm_outputs(drm);
|
||||
|
||||
struct wlr_drm_connector *conn, *next;
|
||||
wl_list_for_each_safe(conn, next, &drm->outputs, link) {
|
||||
destroy_drm_connector(conn);
|
||||
|
@ -56,8 +52,11 @@ 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) {
|
||||
finish_drm_renderer(&drm->mgpu_renderer);
|
||||
}
|
||||
|
||||
finish_drm_resources(drm);
|
||||
finish_drm_renderer(&drm->renderer);
|
||||
|
||||
free(drm->name);
|
||||
wlr_session_close_file(drm->session, drm->dev);
|
||||
|
@ -65,17 +64,6 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
free(drm);
|
||||
}
|
||||
|
||||
static struct wlr_renderer *backend_get_renderer(
|
||||
struct wlr_backend *backend) {
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
|
||||
|
||||
if (drm->parent) {
|
||||
return drm->parent->renderer.wlr_rend;
|
||||
} else {
|
||||
return drm->renderer.wlr_rend;
|
||||
}
|
||||
}
|
||||
|
||||
static clockid_t backend_get_presentation_clock(struct wlr_backend *backend) {
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
|
||||
return drm->clock;
|
||||
|
@ -91,17 +79,16 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
|
||||
static uint32_t drm_backend_get_buffer_caps(struct wlr_backend *backend) {
|
||||
return WLR_BUFFER_CAP_DMABUF;
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_renderer = backend_get_renderer,
|
||||
.get_presentation_clock = backend_get_presentation_clock,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = backend_get_buffer_caps,
|
||||
.get_buffer_caps = drm_backend_get_buffer_caps,
|
||||
};
|
||||
|
||||
bool wlr_backend_is_drm(struct wlr_backend *b) {
|
||||
|
@ -115,16 +102,18 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
|
|||
|
||||
if (session->active) {
|
||||
wlr_log(WLR_INFO, "DRM fd resumed");
|
||||
scan_drm_connectors(drm);
|
||||
scan_drm_connectors(drm, NULL);
|
||||
|
||||
struct wlr_drm_connector *conn;
|
||||
wl_list_for_each(conn, &drm->outputs, link) {
|
||||
struct wlr_output_mode *mode = NULL;
|
||||
uint32_t committed = WLR_OUTPUT_STATE_ENABLED;
|
||||
if (conn->output.enabled && conn->output.current_mode != NULL) {
|
||||
committed |= WLR_OUTPUT_STATE_MODE;
|
||||
mode = conn->output.current_mode;
|
||||
}
|
||||
struct wlr_output_state state = {
|
||||
.committed = WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_ENABLED,
|
||||
.committed = committed,
|
||||
.enabled = mode != NULL,
|
||||
.mode_type = WLR_OUTPUT_STATE_MODE_FIXED,
|
||||
.mode = mode,
|
||||
|
@ -138,13 +127,24 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
|
|||
|
||||
static void handle_dev_change(struct wl_listener *listener, void *data) {
|
||||
struct wlr_drm_backend *drm = wl_container_of(listener, drm, dev_change);
|
||||
struct wlr_device_change_event *change = data;
|
||||
|
||||
if (!drm->session->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "%s invalidated", drm->name);
|
||||
scan_drm_connectors(drm);
|
||||
switch (change->type) {
|
||||
case WLR_DEVICE_HOTPLUG:
|
||||
wlr_log(WLR_DEBUG, "Received hotplug event for %s", drm->name);
|
||||
scan_drm_connectors(drm, &change->hotplug);
|
||||
break;
|
||||
case WLR_DEVICE_LEASE:
|
||||
wlr_log(WLR_DEBUG, "Received lease event for %s", drm->name);
|
||||
scan_drm_leases(drm);
|
||||
break;
|
||||
default:
|
||||
wlr_log(WLR_DEBUG, "Received unknown change event for %s", drm->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_dev_remove(struct wl_listener *listener, void *data) {
|
||||
|
@ -217,7 +217,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
|||
|
||||
struct wl_event_loop *event_loop = wl_display_get_event_loop(display);
|
||||
drm->drm_event = wl_event_loop_add_fd(event_loop, drm->fd,
|
||||
WL_EVENT_READABLE, handle_drm_event, NULL);
|
||||
WL_EVENT_READABLE, handle_drm_event, drm);
|
||||
if (!drm->drm_event) {
|
||||
wlr_log(WLR_ERROR, "Failed to create DRM event source");
|
||||
goto error_fd;
|
||||
|
@ -234,37 +234,31 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
|||
goto error_event;
|
||||
}
|
||||
|
||||
if (!init_drm_renderer(drm, &drm->renderer)) {
|
||||
if (drm->parent) {
|
||||
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to initialize renderer");
|
||||
goto error_event;
|
||||
goto error_resources;
|
||||
}
|
||||
|
||||
if (drm->parent) {
|
||||
// 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->renderer.wlr_rend;
|
||||
struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
|
||||
const struct wlr_drm_format_set *texture_formats =
|
||||
wlr_renderer_get_dmabuf_texture_formats(renderer);
|
||||
if (texture_formats == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
|
||||
goto error_event;
|
||||
goto error_mgpu_renderer;
|
||||
}
|
||||
|
||||
// Force a linear layout. In case explicit modifiers aren't supported,
|
||||
// the meaning of implicit modifiers changes from one GPU to the other.
|
||||
// In case explicit modifiers are supported, we still have no guarantee
|
||||
// that the buffer producer will support these, so they might fallback
|
||||
// to implicit modifiers.
|
||||
for (size_t i = 0; i < texture_formats->len; i++) {
|
||||
const struct wlr_drm_format *fmt = texture_formats->formats[i];
|
||||
if (fmt->len == 0) {
|
||||
// Modifiers aren't supported. The implicit modifier changes
|
||||
// from a GPU to the other, so we can only accept linear
|
||||
// buffers
|
||||
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format,
|
||||
DRM_FORMAT_MOD_LINEAR);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < fmt->len; j++) {
|
||||
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format,
|
||||
fmt->modifiers[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,10 +270,17 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
|
|||
|
||||
return &drm->backend;
|
||||
|
||||
error_mgpu_renderer:
|
||||
finish_drm_renderer(&drm->mgpu_renderer);
|
||||
error_resources:
|
||||
finish_drm_resources(drm);
|
||||
error_event:
|
||||
wl_list_remove(&drm->session_active.link);
|
||||
wl_event_source_remove(drm->drm_event);
|
||||
error_fd:
|
||||
wl_list_remove(&drm->dev_remove.link);
|
||||
wl_list_remove(&drm->dev_change.link);
|
||||
wl_list_remove(&drm->parent_destroy.link);
|
||||
wlr_session_close_file(drm->session, dev);
|
||||
free(drm);
|
||||
return NULL;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,4 @@
|
|||
#include <assert.h>
|
||||
#include <gbm.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
|
@ -8,17 +7,73 @@
|
|||
#include "backend/drm/iface.h"
|
||||
#include "backend/drm/util.h"
|
||||
|
||||
static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_connector *conn, const struct wlr_output_state *state,
|
||||
uint32_t flags) {
|
||||
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
|
||||
struct wlr_drm_fb *fb2) {
|
||||
struct wlr_dmabuf_attributes dmabuf1 = {0}, dmabuf2 = {0};
|
||||
if (!wlr_buffer_get_dmabuf(fb1->wlr_buf, &dmabuf1) ||
|
||||
!wlr_buffer_get_dmabuf(fb2->wlr_buf, &dmabuf2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dmabuf1.width != dmabuf2.width ||
|
||||
dmabuf1.height != dmabuf2.height ||
|
||||
dmabuf1.format != dmabuf2.format ||
|
||||
dmabuf1.modifier != dmabuf2.modifier ||
|
||||
dmabuf1.n_planes != dmabuf2.n_planes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dmabuf1.n_planes; i++) {
|
||||
if (dmabuf1.stride[i] != dmabuf2.stride[i] ||
|
||||
dmabuf1.offset[i] != dmabuf2.offset[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool legacy_crtc_test(struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state) {
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_BUFFER) && !state->modeset) {
|
||||
struct wlr_drm_fb *pending_fb = crtc->primary->pending_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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool legacy_crtc_commit(struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state,
|
||||
uint32_t flags, bool test_only) {
|
||||
if (!legacy_crtc_test(conn, state)) {
|
||||
return false;
|
||||
}
|
||||
if (test_only) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_drm_backend *drm = conn->backend;
|
||||
struct wlr_output *output = &conn->output;
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
struct wlr_drm_plane *cursor = crtc->cursor;
|
||||
|
||||
bool active = drm_connector_state_active(conn, state);
|
||||
|
||||
uint32_t fb_id = 0;
|
||||
if (active) {
|
||||
if (state->active) {
|
||||
struct wlr_drm_fb *fb = plane_get_next_fb(crtc->primary);
|
||||
if (fb == NULL) {
|
||||
wlr_log(WLR_ERROR, "%s: failed to acquire primary FB",
|
||||
|
@ -28,19 +83,17 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
|||
fb_id = fb->id;
|
||||
}
|
||||
|
||||
if (drm_connector_state_is_modeset(state)) {
|
||||
if (state->modeset) {
|
||||
uint32_t *conns = NULL;
|
||||
size_t conns_len = 0;
|
||||
drmModeModeInfo *mode = NULL;
|
||||
drmModeModeInfo mode_info = {0};
|
||||
if (active) {
|
||||
if (state->active) {
|
||||
conns = &conn->id;
|
||||
conns_len = 1;
|
||||
drm_connector_state_mode(conn, state, &mode_info);
|
||||
mode = &mode_info;
|
||||
mode = (drmModeModeInfo *)&state->mode;
|
||||
}
|
||||
|
||||
uint32_t dpms = active ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF;
|
||||
uint32_t dpms = state->active ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF;
|
||||
if (drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms,
|
||||
dpms) != 0) {
|
||||
wlr_drm_conn_log_errno(conn, WLR_ERROR,
|
||||
|
@ -55,27 +108,27 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc,
|
||||
state->gamma_lut_size, state->gamma_lut)) {
|
||||
state->base->gamma_lut_size, state->base->gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
|
||||
drm_connector_supports_vrr(conn)) {
|
||||
if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC,
|
||||
crtc->props.vrr_enabled,
|
||||
state->adaptive_sync_enabled) != 0) {
|
||||
state->base->adaptive_sync_enabled) != 0) {
|
||||
wlr_drm_conn_log_errno(conn, WLR_ERROR,
|
||||
"drmModeObjectSetProperty(VRR_ENABLED) failed");
|
||||
return false;
|
||||
}
|
||||
output->adaptive_sync_status = state->adaptive_sync_enabled ?
|
||||
output->adaptive_sync_status = state->base->adaptive_sync_enabled ?
|
||||
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED :
|
||||
WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG, "VRR %s",
|
||||
state->adaptive_sync_enabled ? "enabled" : "disabled");
|
||||
state->base->adaptive_sync_enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
|
||||
|
@ -85,12 +138,26 @@ static bool legacy_crtc_commit(struct wlr_drm_backend *drm,
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t cursor_handle = gbm_bo_get_handle(cursor_fb->bo).u32;
|
||||
uint32_t cursor_width = gbm_bo_get_width(cursor_fb->bo);
|
||||
uint32_t cursor_height = gbm_bo_get_height(cursor_fb->bo);
|
||||
if (drmModeSetCursor(drm->fd, crtc->id, cursor_handle,
|
||||
cursor_width, cursor_height)) {
|
||||
wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed");
|
||||
drmModeFB *drm_fb = drmModeGetFB(drm->fd, cursor_fb->id);
|
||||
if (drm_fb == NULL) {
|
||||
wlr_drm_conn_log_errno(conn, WLR_DEBUG, "Failed to get cursor "
|
||||
"BO handle: drmModeGetFB failed");
|
||||
return false;
|
||||
}
|
||||
uint32_t cursor_handle = drm_fb->handle;
|
||||
uint32_t cursor_width = drm_fb->width;
|
||||
uint32_t cursor_height = drm_fb->height;
|
||||
drmModeFreeFB(drm_fb);
|
||||
|
||||
int ret = drmModeSetCursor(drm->fd, crtc->id, cursor_handle,
|
||||
cursor_width, cursor_height);
|
||||
int set_cursor_errno = errno;
|
||||
if (drmCloseBufferHandle(drm->fd, cursor_handle) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed");
|
||||
}
|
||||
if (ret != 0) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG, "drmModeSetCursor failed: %s",
|
||||
strerror(set_cursor_errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -151,6 +218,7 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
|
|||
if (drmModeCrtcSetGamma(drm->fd, crtc->id, size, r, g, b) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to set gamma LUT on CRTC %"PRIu32,
|
||||
crtc->id);
|
||||
free(linear_lut);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@ wlr_files += files(
|
|||
'cvt.c',
|
||||
'drm.c',
|
||||
'legacy.c',
|
||||
'monitor.c',
|
||||
'properties.c',
|
||||
'renderer.c',
|
||||
'util.c',
|
||||
)
|
||||
|
||||
features += { 'drm-backend': true }
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include <stdlib.h>
|
||||
#include "backend/drm/monitor.h"
|
||||
#include "backend/multi.h"
|
||||
#include "backend/session/session.h"
|
||||
|
||||
static void drm_backend_monitor_destroy(struct wlr_drm_backend_monitor* monitor) {
|
||||
wl_list_remove(&monitor->session_add_drm_card.link);
|
||||
wl_list_remove(&monitor->session_destroy.link);
|
||||
wl_list_remove(&monitor->primary_drm_destroy.link);
|
||||
wl_list_remove(&monitor->multi_destroy.link);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
static void handle_add_drm_card(struct wl_listener *listener, void *data) {
|
||||
struct wlr_session_add_event *event = data;
|
||||
struct wlr_drm_backend_monitor *backend_monitor =
|
||||
wl_container_of(listener, backend_monitor, session_add_drm_card);
|
||||
|
||||
struct wlr_device *dev =
|
||||
session_open_if_kms(backend_monitor->session, event->path);
|
||||
if (!dev) {
|
||||
wlr_log(WLR_ERROR, "Unable to open %s as DRM device", event->path);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_DEBUG, "Creating DRM backend for %s after hotplug", event->path);
|
||||
struct wlr_backend *child_drm = wlr_drm_backend_create(
|
||||
backend_monitor->session->display, backend_monitor->session,
|
||||
dev, backend_monitor->primary_drm);
|
||||
if (!child_drm) {
|
||||
wlr_log(WLR_ERROR, "Failed to create DRM backend after hotplug");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_multi_backend_add(backend_monitor->multi, child_drm)) {
|
||||
wlr_log(WLR_ERROR, "Failed to add new drm backend to multi backend");
|
||||
wlr_backend_destroy(child_drm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_backend_start(child_drm)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start new child DRM backend");
|
||||
wlr_backend_destroy(child_drm);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_session_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_drm_backend_monitor *backend_monitor =
|
||||
wl_container_of(listener, backend_monitor, session_destroy);
|
||||
drm_backend_monitor_destroy(backend_monitor);
|
||||
}
|
||||
|
||||
static void handle_primary_drm_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_drm_backend_monitor *backend_monitor =
|
||||
wl_container_of(listener, backend_monitor, primary_drm_destroy);
|
||||
drm_backend_monitor_destroy(backend_monitor);
|
||||
}
|
||||
|
||||
static void handle_multi_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_drm_backend_monitor *backend_monitor =
|
||||
wl_container_of(listener, backend_monitor, multi_destroy);
|
||||
drm_backend_monitor_destroy(backend_monitor);
|
||||
}
|
||||
|
||||
struct wlr_drm_backend_monitor *drm_backend_monitor_create(
|
||||
struct wlr_backend *multi,
|
||||
struct wlr_backend *primary_drm,
|
||||
struct wlr_session *session) {
|
||||
struct wlr_drm_backend_monitor *monitor =
|
||||
calloc(1, sizeof(struct wlr_drm_backend_monitor));
|
||||
if (!monitor) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
monitor->multi = multi;
|
||||
monitor->primary_drm = primary_drm;
|
||||
monitor->session = session;
|
||||
|
||||
monitor->session_add_drm_card.notify = handle_add_drm_card;
|
||||
wl_signal_add(&session->events.add_drm_card, &monitor->session_add_drm_card);
|
||||
|
||||
monitor->session_destroy.notify = handle_session_destroy;
|
||||
wl_signal_add(&session->events.destroy, &monitor->session_destroy);
|
||||
|
||||
monitor->primary_drm_destroy.notify = handle_primary_drm_destroy;
|
||||
wl_signal_add(&primary_drm->events.destroy, &monitor->primary_drm_destroy);
|
||||
|
||||
monitor->multi_destroy.notify = handle_multi_destroy;
|
||||
wl_signal_add(&multi->events.destroy, &monitor->multi_destroy);
|
||||
|
||||
return monitor;
|
||||
}
|
|
@ -25,6 +25,8 @@ static const struct prop_info connector_info[] = {
|
|||
{ "EDID", INDEX(edid) },
|
||||
{ "PATH", INDEX(path) },
|
||||
{ "link-status", INDEX(link_status) },
|
||||
{ "non-desktop", INDEX(non_desktop) },
|
||||
{ "panel orientation", INDEX(panel_orientation) },
|
||||
{ "subconnector", INDEX(subconnector) },
|
||||
{ "vrr_capable", INDEX(vrr_capable) },
|
||||
#undef INDEX
|
||||
|
@ -47,6 +49,7 @@ static const struct prop_info plane_info[] = {
|
|||
{ "CRTC_W", INDEX(crtc_w) },
|
||||
{ "CRTC_X", INDEX(crtc_x) },
|
||||
{ "CRTC_Y", INDEX(crtc_y) },
|
||||
{ "FB_DAMAGE_CLIPS", INDEX(fb_damage_clips) },
|
||||
{ "FB_ID", INDEX(fb_id) },
|
||||
{ "IN_FORMATS", INDEX(in_formats) },
|
||||
{ "SRC_H", INDEX(src_h) },
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <fcntl.h>
|
||||
#include <gbm.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -14,42 +13,30 @@
|
|||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/util.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/allocator.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
#include "render/pixel_format.h"
|
||||
#include "render/swapchain.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "render/wlr_texture.h"
|
||||
|
||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_renderer *renderer) {
|
||||
renderer->backend = drm;
|
||||
|
||||
renderer->gbm = gbm_create_device(drm->fd);
|
||||
if (!renderer->gbm) {
|
||||
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
||||
return false;
|
||||
}
|
||||
|
||||
renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
|
||||
if (!renderer->wlr_rend) {
|
||||
wlr_log(WLR_ERROR, "Failed to create renderer");
|
||||
goto error_gbm;
|
||||
return false;
|
||||
}
|
||||
|
||||
renderer->allocator = allocator_autocreate_with_drm_fd(&drm->backend,
|
||||
renderer->wlr_rend, drm->fd);
|
||||
if (renderer->allocator == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create allocator");
|
||||
goto error_wlr_rend;
|
||||
wlr_renderer_destroy(renderer->wlr_rend);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error_wlr_rend:
|
||||
wlr_renderer_destroy(renderer->wlr_rend);
|
||||
error_gbm:
|
||||
gbm_device_destroy(renderer->gbm);
|
||||
return false;
|
||||
}
|
||||
|
||||
void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
|
||||
|
@ -59,7 +46,6 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
|
|||
|
||||
wlr_allocator_destroy(renderer->allocator);
|
||||
wlr_renderer_destroy(renderer->wlr_rend);
|
||||
gbm_device_destroy(renderer->gbm);
|
||||
}
|
||||
|
||||
bool init_drm_surface(struct wlr_drm_surface *surf,
|
||||
|
@ -73,8 +59,6 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
|
|||
surf->width = width;
|
||||
surf->height = height;
|
||||
|
||||
wlr_buffer_unlock(surf->back_buffer);
|
||||
surf->back_buffer = NULL;
|
||||
wlr_swapchain_destroy(surf->swapchain);
|
||||
surf->swapchain = NULL;
|
||||
|
||||
|
@ -94,38 +78,11 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) {
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_buffer_unlock(surf->back_buffer);
|
||||
wlr_swapchain_destroy(surf->swapchain);
|
||||
|
||||
memset(surf, 0, sizeof(*surf));
|
||||
}
|
||||
|
||||
bool drm_surface_make_current(struct wlr_drm_surface *surf,
|
||||
int *buffer_age) {
|
||||
wlr_buffer_unlock(surf->back_buffer);
|
||||
surf->back_buffer = wlr_swapchain_acquire(surf->swapchain, buffer_age);
|
||||
if (surf->back_buffer == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to acquire swapchain buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!renderer_bind_buffer(surf->renderer->wlr_rend, surf->back_buffer)) {
|
||||
wlr_log(WLR_ERROR, "Failed to bind buffer to renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void drm_surface_unset_current(struct wlr_drm_surface *surf) {
|
||||
assert(surf->back_buffer != NULL);
|
||||
|
||||
renderer_bind_buffer(surf->renderer->wlr_rend, NULL);
|
||||
|
||||
wlr_buffer_unlock(surf->back_buffer);
|
||||
surf->back_buffer = NULL;
|
||||
}
|
||||
|
||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
||||
struct wlr_buffer *buffer) {
|
||||
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
|
||||
|
@ -141,7 +98,8 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!drm_surface_make_current(surf, NULL)) {
|
||||
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
|
||||
if (!dst) {
|
||||
wlr_texture_destroy(tex);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -150,19 +108,20 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
|||
wlr_matrix_identity(mat);
|
||||
wlr_matrix_scale(mat, surf->width, surf->height);
|
||||
|
||||
wlr_renderer_begin(renderer, surf->width, surf->height);
|
||||
if (!wlr_renderer_begin_with_buffer(renderer, dst)) {
|
||||
wlr_buffer_unlock(dst);
|
||||
wlr_texture_destroy(tex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 });
|
||||
wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f);
|
||||
|
||||
wlr_renderer_end(renderer);
|
||||
|
||||
assert(surf->back_buffer != NULL);
|
||||
struct wlr_buffer *out = wlr_buffer_lock(surf->back_buffer);
|
||||
|
||||
drm_surface_unset_current(surf);
|
||||
|
||||
wlr_texture_destroy(tex);
|
||||
|
||||
return out;
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,22 +134,9 @@ void drm_plane_finish_surface(struct wlr_drm_plane *plane) {
|
|||
drm_fb_clear(&plane->queued_fb);
|
||||
drm_fb_clear(&plane->current_fb);
|
||||
|
||||
finish_drm_surface(&plane->surf);
|
||||
finish_drm_surface(&plane->mgpu_surf);
|
||||
}
|
||||
|
||||
static struct wlr_drm_format *create_linear_format(uint32_t format) {
|
||||
struct wlr_drm_format *fmt = wlr_drm_format_create(format);
|
||||
if (fmt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!wlr_drm_format_add(&fmt, DRM_FORMAT_MOD_LINEAR)) {
|
||||
free(fmt);
|
||||
return NULL;
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
struct wlr_drm_format *drm_plane_pick_render_format(
|
||||
struct wlr_drm_plane *plane, struct wlr_drm_renderer *renderer) {
|
||||
const struct wlr_drm_format_set *render_formats =
|
||||
|
@ -203,7 +149,7 @@ struct wlr_drm_format *drm_plane_pick_render_format(
|
|||
const struct wlr_drm_format_set *plane_formats = &plane->formats;
|
||||
|
||||
uint32_t fmt = DRM_FORMAT_ARGB8888;
|
||||
if (!wlr_drm_format_set_has(&plane->formats, fmt, DRM_FORMAT_MOD_INVALID)) {
|
||||
if (!wlr_drm_format_set_get(&plane->formats, fmt)) {
|
||||
const struct wlr_pixel_format_info *format_info =
|
||||
drm_get_pixel_format_info(fmt);
|
||||
assert(format_info != NULL &&
|
||||
|
@ -237,53 +183,6 @@ struct wlr_drm_format *drm_plane_pick_render_format(
|
|||
return format;
|
||||
}
|
||||
|
||||
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
||||
bool with_modifiers) {
|
||||
struct wlr_drm_format *format =
|
||||
drm_plane_pick_render_format(plane, &drm->renderer);
|
||||
if (format == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to pick render format for plane %"PRIu32,
|
||||
plane->id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!with_modifiers) {
|
||||
struct wlr_drm_format *format_implicit_modifier =
|
||||
wlr_drm_format_create(format->format);
|
||||
free(format);
|
||||
format = format_implicit_modifier;
|
||||
}
|
||||
|
||||
drm_plane_finish_surface(plane);
|
||||
|
||||
bool ok = true;
|
||||
if (!drm->parent) {
|
||||
ok = init_drm_surface(&plane->surf, &drm->renderer,
|
||||
width, height, format);
|
||||
} else {
|
||||
struct wlr_drm_format *format_linear = create_linear_format(format->format);
|
||||
if (format_linear == NULL) {
|
||||
free(format);
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = init_drm_surface(&plane->surf, &drm->parent->renderer,
|
||||
width, height, format_linear);
|
||||
free(format_linear);
|
||||
|
||||
if (ok && !init_drm_surface(&plane->mgpu_surf, &drm->renderer,
|
||||
width, height, format)) {
|
||||
finish_drm_surface(&plane->surf);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
free(format);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void drm_fb_clear(struct wlr_drm_fb **fb_ptr) {
|
||||
if (*fb_ptr == NULL) {
|
||||
return;
|
||||
|
@ -295,99 +194,139 @@ void drm_fb_clear(struct wlr_drm_fb **fb_ptr) {
|
|||
*fb_ptr = NULL;
|
||||
}
|
||||
|
||||
bool drm_plane_lock_surface(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_backend *drm) {
|
||||
assert(plane->surf.back_buffer != NULL);
|
||||
struct wlr_buffer *buf = wlr_buffer_lock(plane->surf.back_buffer);
|
||||
|
||||
// Unset the current EGL context ASAP, because other operations may require
|
||||
// making another context current.
|
||||
drm_surface_unset_current(&plane->surf);
|
||||
|
||||
struct wlr_buffer *local_buf;
|
||||
if (drm->parent) {
|
||||
// Perform a copy across GPUs
|
||||
local_buf = drm_surface_blit(&plane->mgpu_surf, buf);
|
||||
if (!local_buf) {
|
||||
wlr_log(WLR_ERROR, "Failed to blit buffer across GPUs");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
local_buf = wlr_buffer_lock(buf);
|
||||
}
|
||||
wlr_buffer_unlock(buf);
|
||||
|
||||
bool ok = drm_fb_import(&plane->pending_fb, drm, local_buf, NULL);
|
||||
if (!ok) {
|
||||
wlr_log(WLR_ERROR, "Failed to import buffer");
|
||||
}
|
||||
wlr_buffer_unlock(local_buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static struct gbm_bo *get_bo_for_dmabuf(struct gbm_device *gbm,
|
||||
struct wlr_dmabuf_attributes *attribs) {
|
||||
if (attribs->modifier != DRM_FORMAT_MOD_INVALID ||
|
||||
attribs->n_planes > 1 || attribs->offset[0] != 0) {
|
||||
struct gbm_import_fd_modifier_data data = {
|
||||
.width = attribs->width,
|
||||
.height = attribs->height,
|
||||
.format = attribs->format,
|
||||
.num_fds = attribs->n_planes,
|
||||
.modifier = attribs->modifier,
|
||||
};
|
||||
|
||||
if ((size_t)attribs->n_planes > sizeof(data.fds) / sizeof(data.fds[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (size_t)attribs->n_planes; ++i) {
|
||||
data.fds[i] = attribs->fd[i];
|
||||
data.strides[i] = attribs->stride[i];
|
||||
data.offsets[i] = attribs->offset[i];
|
||||
}
|
||||
|
||||
return gbm_bo_import(gbm, GBM_BO_IMPORT_FD_MODIFIER,
|
||||
&data, GBM_BO_USE_SCANOUT);
|
||||
} else {
|
||||
struct gbm_import_fd_data data = {
|
||||
.fd = attribs->fd[0],
|
||||
.width = attribs->width,
|
||||
.height = attribs->height,
|
||||
.stride = attribs->stride[0],
|
||||
.format = attribs->format,
|
||||
};
|
||||
|
||||
return gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_fb_handle_wlr_buf_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_drm_fb *fb = wl_container_of(listener, fb, wlr_buf_destroy);
|
||||
static void drm_fb_handle_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_drm_fb *fb = wl_container_of(addon, fb, addon);
|
||||
drm_fb_destroy(fb);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface fb_addon_impl = {
|
||||
.name = "wlr_drm_fb",
|
||||
.destroy = drm_fb_handle_destroy,
|
||||
};
|
||||
|
||||
static uint32_t get_fb_for_bo(struct wlr_drm_backend *drm,
|
||||
struct wlr_dmabuf_attributes *dmabuf, uint32_t handles[static 4]) {
|
||||
uint64_t modifiers[4] = {0};
|
||||
for (int i = 0; i < dmabuf->n_planes; i++) {
|
||||
// KMS requires all BO planes to have the same modifier
|
||||
modifiers[i] = dmabuf->modifier;
|
||||
}
|
||||
|
||||
uint32_t id = 0;
|
||||
if (drm->addfb2_modifiers && dmabuf->modifier != DRM_FORMAT_MOD_INVALID) {
|
||||
if (drmModeAddFB2WithModifiers(drm->fd, dmabuf->width, dmabuf->height,
|
||||
dmabuf->format, handles, dmabuf->stride, dmabuf->offset,
|
||||
modifiers, &id, DRM_MODE_FB_MODIFIERS) != 0) {
|
||||
wlr_log_errno(WLR_DEBUG, "drmModeAddFB2WithModifiers failed");
|
||||
}
|
||||
} else {
|
||||
if (dmabuf->modifier != DRM_FORMAT_MOD_INVALID &&
|
||||
dmabuf->modifier != DRM_FORMAT_MOD_LINEAR) {
|
||||
wlr_log(WLR_ERROR, "Cannot import DRM framebuffer with explicit "
|
||||
"modifier 0x%"PRIX64, dmabuf->modifier);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = drmModeAddFB2(drm->fd, dmabuf->width, dmabuf->height,
|
||||
dmabuf->format, handles, dmabuf->stride, dmabuf->offset, &id, 0);
|
||||
if (ret != 0 && dmabuf->format == DRM_FORMAT_ARGB8888 &&
|
||||
dmabuf->n_planes == 1 && dmabuf->offset[0] == 0) {
|
||||
// Some big-endian machines don't support drmModeAddFB2. Try a
|
||||
// last-resort fallback for ARGB8888 buffers, like Xorg's
|
||||
// modesetting driver does.
|
||||
wlr_log(WLR_DEBUG, "drmModeAddFB2 failed (%s), falling back to "
|
||||
"legacy drmModeAddFB", strerror(-ret));
|
||||
|
||||
uint32_t depth = 32;
|
||||
uint32_t bpp = 32;
|
||||
ret = drmModeAddFB(drm->fd, dmabuf->width, dmabuf->height, depth,
|
||||
bpp, dmabuf->stride[0], handles[0], &id);
|
||||
if (ret != 0) {
|
||||
wlr_log_errno(WLR_DEBUG, "drmModeAddFB failed");
|
||||
}
|
||||
} else if (ret != 0) {
|
||||
wlr_log_errno(WLR_DEBUG, "drmModeAddFB2 failed");
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void close_all_bo_handles(struct wlr_drm_backend *drm,
|
||||
uint32_t handles[static 4]) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (handles[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If multiple planes share the same BO handle, avoid double-closing it
|
||||
bool already_closed = false;
|
||||
for (int j = 0; j < i; ++j) {
|
||||
if (handles[i] == handles[j]) {
|
||||
already_closed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (already_closed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drmCloseBufferHandle(drm->fd, handles[i]) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_poisoned_fb_handle_destroy(struct wlr_addon *addon) {
|
||||
wlr_addon_finish(addon);
|
||||
free(addon);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface poisoned_fb_addon_impl = {
|
||||
.name = "wlr_drm_poisoned_fb",
|
||||
.destroy = drm_poisoned_fb_handle_destroy,
|
||||
};
|
||||
|
||||
static bool is_buffer_poisoned(struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *buf) {
|
||||
return wlr_addon_find(&buf->addons, drm, &poisoned_fb_addon_impl) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the buffer as "poisoned", ie. it cannot be imported into KMS. This
|
||||
* allows us to avoid repeatedly trying to import it when it's not
|
||||
* scanout-capable.
|
||||
*/
|
||||
static void poison_buffer(struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *buf) {
|
||||
struct wlr_addon *addon = calloc(1, sizeof(*addon));
|
||||
if (addon == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return;
|
||||
}
|
||||
wlr_addon_init(addon, &buf->addons, drm, &poisoned_fb_addon_impl);
|
||||
wlr_log(WLR_DEBUG, "Poisoning buffer");
|
||||
}
|
||||
|
||||
static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) {
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
if (!wlr_buffer_get_dmabuf(buf, &attribs)) {
|
||||
wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_buffer_poisoned(drm, buf)) {
|
||||
wlr_log(WLR_DEBUG, "Buffer is poisoned");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_drm_fb *fb = calloc(1, sizeof(*fb));
|
||||
if (!fb) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_dmabuf_attributes attribs;
|
||||
if (!wlr_buffer_get_dmabuf(buf, &attribs)) {
|
||||
wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer");
|
||||
goto error_get_dmabuf;
|
||||
}
|
||||
|
||||
if (attribs.flags != 0) {
|
||||
wlr_log(WLR_DEBUG, "Buffer with DMA-BUF flags 0x%"PRIX32" cannot be "
|
||||
"scanned out", attribs.flags);
|
||||
goto error_get_dmabuf;
|
||||
}
|
||||
|
||||
if (formats && !wlr_drm_format_set_has(formats, attribs.format,
|
||||
attribs.modifier)) {
|
||||
// The format isn't supported by the plane. Try stripping the alpha
|
||||
|
@ -401,66 +340,63 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
|
|||
wlr_log(WLR_DEBUG, "Buffer format 0x%"PRIX32" with modifier "
|
||||
"0x%"PRIX64" cannot be scanned out",
|
||||
attribs.format, attribs.modifier);
|
||||
goto error_get_dmabuf;
|
||||
goto error_fb;
|
||||
}
|
||||
}
|
||||
|
||||
fb->bo = get_bo_for_dmabuf(drm->renderer.gbm, &attribs);
|
||||
if (!fb->bo) {
|
||||
wlr_log(WLR_DEBUG, "Failed to import DMA-BUF in GBM");
|
||||
goto error_get_dmabuf;
|
||||
uint32_t handles[4] = {0};
|
||||
for (int i = 0; i < attribs.n_planes; ++i) {
|
||||
int ret = drmPrimeFDToHandle(drm->fd, attribs.fd[i], &handles[i]);
|
||||
if (ret != 0) {
|
||||
wlr_log_errno(WLR_DEBUG, "drmPrimeFDToHandle failed");
|
||||
goto error_bo_handle;
|
||||
}
|
||||
}
|
||||
|
||||
fb->id = get_fb_for_bo(fb->bo, drm->addfb2_modifiers);
|
||||
fb->id = get_fb_for_bo(drm, &attribs, handles);
|
||||
if (!fb->id) {
|
||||
wlr_log(WLR_DEBUG, "Failed to import GBM BO in KMS");
|
||||
goto error_get_fb_for_bo;
|
||||
wlr_log(WLR_DEBUG, "Failed to import BO in KMS");
|
||||
poison_buffer(drm, buf);
|
||||
goto error_bo_handle;
|
||||
}
|
||||
|
||||
close_all_bo_handles(drm, handles);
|
||||
|
||||
fb->backend = drm;
|
||||
fb->wlr_buf = buf;
|
||||
|
||||
fb->wlr_buf_destroy.notify = drm_fb_handle_wlr_buf_destroy;
|
||||
wl_signal_add(&buf->events.destroy, &fb->wlr_buf_destroy);
|
||||
|
||||
wlr_addon_init(&fb->addon, &buf->addons, drm, &fb_addon_impl);
|
||||
wl_list_insert(&drm->fbs, &fb->link);
|
||||
|
||||
return fb;
|
||||
|
||||
error_get_fb_for_bo:
|
||||
gbm_bo_destroy(fb->bo);
|
||||
error_get_dmabuf:
|
||||
error_bo_handle:
|
||||
close_all_bo_handles(drm, handles);
|
||||
error_fb:
|
||||
free(fb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void drm_fb_destroy(struct wlr_drm_fb *fb) {
|
||||
wl_list_remove(&fb->link);
|
||||
wl_list_remove(&fb->wlr_buf_destroy.link);
|
||||
struct wlr_drm_backend *drm = fb->backend;
|
||||
|
||||
struct gbm_device *gbm = gbm_bo_get_device(fb->bo);
|
||||
if (drmModeRmFB(gbm_device_get_fd(gbm), fb->id) != 0) {
|
||||
wl_list_remove(&fb->link);
|
||||
wlr_addon_finish(&fb->addon);
|
||||
|
||||
if (drmModeRmFB(drm->fd, fb->id) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmModeRmFB failed");
|
||||
}
|
||||
|
||||
gbm_bo_destroy(fb->bo);
|
||||
free(fb);
|
||||
}
|
||||
|
||||
static struct wlr_drm_fb *drm_fb_get(struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *local_buf) {
|
||||
struct wlr_drm_fb *fb;
|
||||
wl_list_for_each(fb, &drm->fbs, link) {
|
||||
if (fb->wlr_buf == local_buf) {
|
||||
return fb;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool drm_fb_import(struct wlr_drm_fb **fb_ptr, struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) {
|
||||
struct wlr_drm_fb *fb = drm_fb_get(drm, buf);
|
||||
if (!fb) {
|
||||
struct wlr_drm_fb *fb;
|
||||
struct wlr_addon *addon = wlr_addon_find(&buf->addons, drm, &fb_addon_impl);
|
||||
if (addon != NULL) {
|
||||
fb = wl_container_of(addon, fb, addon);
|
||||
} else {
|
||||
fb = drm_fb_create(drm, buf, formats);
|
||||
if (!fb) {
|
||||
return false;
|
||||
|
@ -477,16 +413,3 @@ void drm_fb_move(struct wlr_drm_fb **new, struct wlr_drm_fb **old) {
|
|||
*new = *old;
|
||||
*old = NULL;
|
||||
}
|
||||
|
||||
bool drm_surface_render_black_frame(struct wlr_drm_surface *surf) {
|
||||
if (!drm_surface_make_current(surf, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
|
||||
wlr_renderer_begin(renderer, surf->width, surf->height);
|
||||
wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 });
|
||||
wlr_renderer_end(renderer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <drm_fourcc.h>
|
||||
#include <drm_mode.h>
|
||||
#include <drm.h>
|
||||
#include <gbm.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
@ -95,6 +94,7 @@ static const char *get_manufacturer(uint16_t id) {
|
|||
case ID('V', 'E', 'S'): return "Vestel Elektronik Sanayi ve Ticaret A. S.";
|
||||
case ID('V', 'I', 'T'): return "Visitech AS";
|
||||
case ID('V', 'I', 'Z'): return "VIZIO, Inc";
|
||||
case ID('V', 'L', 'V'): return "Valve";
|
||||
case ID('V', 'S', 'C'): return "ViewSonic Corporation";
|
||||
case ID('Y', 'M', 'H'): return "Yamaha Corporation";
|
||||
default: return "Unknown";
|
||||
|
@ -167,61 +167,14 @@ const char *conn_get_name(uint32_t type_id) {
|
|||
case DRM_MODE_CONNECTOR_WRITEBACK: return "Writeback";
|
||||
#ifdef DRM_MODE_CONNECTOR_SPI
|
||||
case DRM_MODE_CONNECTOR_SPI: return "SPI";
|
||||
#endif
|
||||
#ifdef DRM_MODE_CONNECTOR_USB
|
||||
case DRM_MODE_CONNECTOR_USB: return "USB";
|
||||
#endif
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_fb_for_bo(struct gbm_bo *bo, bool with_modifiers) {
|
||||
struct gbm_device *gbm = gbm_bo_get_device(bo);
|
||||
|
||||
int fd = gbm_device_get_fd(gbm);
|
||||
uint32_t width = gbm_bo_get_width(bo);
|
||||
uint32_t height = gbm_bo_get_height(bo);
|
||||
uint32_t format = gbm_bo_get_format(bo);
|
||||
|
||||
uint32_t handles[4] = {0};
|
||||
uint32_t strides[4] = {0};
|
||||
uint32_t offsets[4] = {0};
|
||||
uint64_t modifiers[4] = {0};
|
||||
for (int i = 0; i < gbm_bo_get_plane_count(bo); i++) {
|
||||
handles[i] = gbm_bo_get_handle_for_plane(bo, i).u32;
|
||||
strides[i] = gbm_bo_get_stride_for_plane(bo, i);
|
||||
offsets[i] = gbm_bo_get_offset(bo, i);
|
||||
// KMS requires all BO planes to have the same modifier
|
||||
modifiers[i] = gbm_bo_get_modifier(bo);
|
||||
}
|
||||
|
||||
uint32_t id = 0;
|
||||
if (with_modifiers && gbm_bo_get_modifier(bo) != DRM_FORMAT_MOD_INVALID) {
|
||||
if (drmModeAddFB2WithModifiers(fd, width, height, format, handles,
|
||||
strides, offsets, modifiers, &id, DRM_MODE_FB_MODIFIERS)) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to add DRM framebuffer");
|
||||
}
|
||||
} else {
|
||||
int ret = drmModeAddFB2(fd, width, height, format, handles, strides,
|
||||
offsets, &id, 0);
|
||||
if (ret != 0 && gbm_bo_get_format(bo) == GBM_FORMAT_ARGB8888 &&
|
||||
gbm_bo_get_plane_count(bo) == 1) {
|
||||
// Some big-endian machines don't support drmModeAddFB2. Try a
|
||||
// last-resort fallback for ARGB8888 buffers, like Xorg's
|
||||
// modesetting driver does.
|
||||
wlr_log(WLR_DEBUG, "drmModeAddFB2 failed (%s), falling back to "
|
||||
"legacy drmModeAddFB", strerror(-ret));
|
||||
|
||||
uint32_t depth = 32;
|
||||
uint32_t bpp = gbm_bo_get_bpp(bo);
|
||||
ret = drmModeAddFB(fd, width, height, depth, bpp, strides[0],
|
||||
handles[0], &id);
|
||||
}
|
||||
if (ret != 0) {
|
||||
wlr_log(WLR_ERROR, "Unable to add DRM framebuffer: %s", strerror(-ret));
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (arr[i] == key) {
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/interfaces/wlr_input_device.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/headless.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/gbm_allocator.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
struct wlr_headless_backend *headless_backend_from_backend(
|
||||
|
@ -37,8 +26,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) {
|
|||
}
|
||||
|
||||
struct wlr_headless_input_device *input_device;
|
||||
wl_list_for_each(input_device, &backend->input_devices,
|
||||
wlr_input_device.link) {
|
||||
wl_list_for_each(input_device, &backend->input_devices, link) {
|
||||
wlr_signal_emit_safe(&backend->backend.events.new_input,
|
||||
&input_device->wlr_input_device);
|
||||
}
|
||||
|
@ -55,7 +43,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
}
|
||||
|
||||
wl_list_remove(&backend->display_destroy.link);
|
||||
wl_list_remove(&backend->parent_renderer_destroy.link);
|
||||
|
||||
struct wlr_headless_output *output, *output_tmp;
|
||||
wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) {
|
||||
|
@ -64,33 +51,15 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
|
||||
struct wlr_headless_input_device *input_device, *input_device_tmp;
|
||||
wl_list_for_each_safe(input_device, input_device_tmp,
|
||||
&backend->input_devices, wlr_input_device.link) {
|
||||
&backend->input_devices, link) {
|
||||
wlr_input_device_destroy(&input_device->wlr_input_device);
|
||||
}
|
||||
|
||||
wlr_backend_finish(wlr_backend);
|
||||
|
||||
close(backend->drm_fd);
|
||||
free(backend);
|
||||
}
|
||||
|
||||
static struct wlr_renderer *backend_get_renderer(
|
||||
struct wlr_backend *wlr_backend) {
|
||||
struct wlr_headless_backend *backend =
|
||||
headless_backend_from_backend(wlr_backend);
|
||||
if (backend->parent_renderer != NULL) {
|
||||
return backend->parent_renderer;
|
||||
} else {
|
||||
return wlr_backend->renderer;
|
||||
}
|
||||
}
|
||||
|
||||
static int backend_get_drm_fd(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_headless_backend *backend =
|
||||
headless_backend_from_backend(wlr_backend);
|
||||
return backend->drm_fd;
|
||||
}
|
||||
|
||||
static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) {
|
||||
return WLR_BUFFER_CAP_DATA_PTR
|
||||
| WLR_BUFFER_CAP_DMABUF
|
||||
|
@ -100,8 +69,6 @@ static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) {
|
|||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_renderer = backend_get_renderer,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = get_buffer_caps,
|
||||
};
|
||||
|
||||
|
@ -111,91 +78,6 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
|||
backend_destroy(&backend->backend);
|
||||
}
|
||||
|
||||
static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_headless_backend *backend =
|
||||
wl_container_of(listener, backend, parent_renderer_destroy);
|
||||
backend_destroy(&backend->backend);
|
||||
}
|
||||
|
||||
static bool backend_init(struct wlr_headless_backend *backend,
|
||||
struct wl_display *display, struct wlr_renderer *renderer) {
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
|
||||
backend->display = display;
|
||||
wl_list_init(&backend->outputs);
|
||||
wl_list_init(&backend->input_devices);
|
||||
wl_list_init(&backend->parent_renderer_destroy.link);
|
||||
|
||||
if (renderer == NULL) {
|
||||
renderer = wlr_renderer_autocreate(&backend->backend);
|
||||
if (!renderer) {
|
||||
wlr_log(WLR_ERROR, "Failed to create renderer");
|
||||
return false;
|
||||
}
|
||||
backend->backend.renderer = renderer;
|
||||
} else {
|
||||
backend->parent_renderer = renderer;
|
||||
backend->parent_renderer_destroy.notify = handle_renderer_destroy;
|
||||
wl_signal_add(&renderer->events.destroy, &backend->parent_renderer_destroy);
|
||||
}
|
||||
|
||||
if (backend_get_allocator(&backend->backend) == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to create allocator");
|
||||
return false;
|
||||
}
|
||||
|
||||
backend->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int open_drm_render_node(void) {
|
||||
uint32_t flags = 0;
|
||||
int devices_len = drmGetDevices2(flags, NULL, 0);
|
||||
if (devices_len < 0) {
|
||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
||||
return -1;
|
||||
}
|
||||
drmDevice **devices = calloc(devices_len, sizeof(drmDevice *));
|
||||
if (devices == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return -1;
|
||||
}
|
||||
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||
if (devices_len < 0) {
|
||||
free(devices);
|
||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
for (int i = 0; i < devices_len; i++) {
|
||||
drmDevice *dev = devices[i];
|
||||
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||
wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name);
|
||||
fd = open(name, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to find any DRM render node");
|
||||
}
|
||||
|
||||
out:
|
||||
for (int i = 0; i < devices_len; i++) {
|
||||
drmFreeDevice(&devices[i]);
|
||||
}
|
||||
free(devices);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) {
|
||||
wlr_log(WLR_INFO, "Creating headless backend");
|
||||
|
||||
|
@ -206,55 +88,16 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
backend->drm_fd = open_drm_render_node();
|
||||
if (backend->drm_fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to open DRM render node");
|
||||
}
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
|
||||
if (!backend_init(backend, display, NULL)) {
|
||||
goto error_init;
|
||||
}
|
||||
backend->display = display;
|
||||
wl_list_init(&backend->outputs);
|
||||
wl_list_init(&backend->input_devices);
|
||||
|
||||
backend->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
||||
|
||||
return &backend->backend;
|
||||
|
||||
error_init:
|
||||
close(backend->drm_fd);
|
||||
free(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_headless_backend_create_with_renderer(
|
||||
struct wl_display *display, struct wlr_renderer *renderer) {
|
||||
wlr_log(WLR_INFO, "Creating headless backend with parent renderer");
|
||||
|
||||
struct wlr_headless_backend *backend =
|
||||
calloc(1, sizeof(struct wlr_headless_backend));
|
||||
if (!backend) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate wlr_headless_backend");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drm_fd = wlr_renderer_get_drm_fd(renderer);
|
||||
if (drm_fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to get DRM device FD from parent renderer");
|
||||
backend->drm_fd = -1;
|
||||
} else {
|
||||
backend->drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
|
||||
if (backend->drm_fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!backend_init(backend, display, renderer)) {
|
||||
goto error_init;
|
||||
}
|
||||
|
||||
return &backend->backend;
|
||||
|
||||
error_init:
|
||||
close(backend->drm_fd);
|
||||
free(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool wlr_backend_is_headless(struct wlr_backend *backend) {
|
||||
|
|
|
@ -11,7 +11,16 @@
|
|||
#include "backend/headless.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
static const struct wlr_input_device_impl input_device_impl = { 0 };
|
||||
static void input_device_destroy(struct wlr_input_device *wlr_dev) {
|
||||
struct wlr_headless_input_device *dev =
|
||||
wl_container_of(wlr_dev, dev, wlr_input_device);
|
||||
wl_list_remove(&dev->link);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static const struct wlr_input_device_impl input_device_impl = {
|
||||
.destroy = input_device_destroy,
|
||||
};
|
||||
|
||||
bool wlr_input_device_is_headless(struct wlr_input_device *wlr_dev) {
|
||||
return wlr_dev->impl == &input_device_impl;
|
||||
|
@ -86,7 +95,7 @@ struct wlr_input_device *wlr_headless_add_input_device(
|
|||
wlr_switch_init(wlr_device->switch_device, NULL);
|
||||
}
|
||||
|
||||
wl_list_insert(&backend->input_devices, &wlr_device->link);
|
||||
wl_list_insert(&backend->input_devices, &device->link);
|
||||
|
||||
if (backend->started) {
|
||||
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_device);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/headless.h"
|
||||
#include "util/signal.h"
|
||||
|
@ -18,11 +17,8 @@ static struct wlr_headless_output *headless_output_from_output(
|
|||
return (struct wlr_headless_output *)wlr_output;
|
||||
}
|
||||
|
||||
static bool output_set_custom_mode(struct wlr_output *wlr_output, int32_t width,
|
||||
int32_t height, int32_t refresh) {
|
||||
struct wlr_headless_output *output =
|
||||
headless_output_from_output(wlr_output);
|
||||
|
||||
static bool output_set_custom_mode(struct wlr_headless_output *output,
|
||||
int32_t width, int32_t height, int32_t refresh) {
|
||||
if (refresh <= 0) {
|
||||
refresh = HEADLESS_DEFAULT_REFRESH;
|
||||
}
|
||||
|
@ -58,7 +54,7 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
|
||||
if (!output_set_custom_mode(wlr_output,
|
||||
if (!output_set_custom_mode(output,
|
||||
wlr_output->pending.custom_mode.width,
|
||||
wlr_output->pending.custom_mode.height,
|
||||
wlr_output->pending.custom_mode.refresh)) {
|
||||
|
@ -67,48 +63,27 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
assert(wlr_output->pending.buffer_type ==
|
||||
WLR_OUTPUT_STATE_BUFFER_SCANOUT);
|
||||
|
||||
wlr_buffer_unlock(output->front_buffer);
|
||||
output->front_buffer = wlr_buffer_lock(wlr_output->pending.buffer);
|
||||
|
||||
wlr_output_send_present(wlr_output, NULL);
|
||||
struct wlr_output_event_present present_event = {
|
||||
.commit_seq = wlr_output->commit_seq + 1,
|
||||
.presented = true,
|
||||
};
|
||||
wlr_output_send_present(wlr_output, &present_event);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool output_export_dmabuf(struct wlr_output *wlr_output,
|
||||
struct wlr_dmabuf_attributes *attribs) {
|
||||
struct wlr_headless_output *output =
|
||||
headless_output_from_output(wlr_output);
|
||||
|
||||
if (!output->front_buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_dmabuf_attributes tmp;
|
||||
if (!wlr_buffer_get_dmabuf(output->front_buffer, &tmp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wlr_dmabuf_attributes_copy(attribs, &tmp);
|
||||
}
|
||||
|
||||
static void output_destroy(struct wlr_output *wlr_output) {
|
||||
struct wlr_headless_output *output =
|
||||
headless_output_from_output(wlr_output);
|
||||
wl_list_remove(&output->link);
|
||||
wl_event_source_remove(output->frame_timer);
|
||||
wlr_buffer_unlock(output->front_buffer);
|
||||
free(output);
|
||||
}
|
||||
|
||||
static const struct wlr_output_impl output_impl = {
|
||||
.destroy = output_destroy,
|
||||
.commit = output_commit,
|
||||
.export_dmabuf = output_export_dmabuf,
|
||||
};
|
||||
|
||||
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
|
||||
|
@ -138,15 +113,17 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
|
|||
backend->display);
|
||||
struct wlr_output *wlr_output = &output->wlr_output;
|
||||
|
||||
output_set_custom_mode(wlr_output, width, height, 0);
|
||||
output_set_custom_mode(output, width, height, 0);
|
||||
strncpy(wlr_output->make, "headless", sizeof(wlr_output->make));
|
||||
strncpy(wlr_output->model, "headless", sizeof(wlr_output->model));
|
||||
snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%zd",
|
||||
++backend->last_output_num);
|
||||
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "HEADLESS-%zu", ++backend->last_output_num);
|
||||
wlr_output_set_name(wlr_output, name);
|
||||
|
||||
char description[128];
|
||||
snprintf(description, sizeof(description),
|
||||
"Headless output %zd", backend->last_output_num);
|
||||
"Headless output %zu", backend->last_output_num);
|
||||
wlr_output_set_description(wlr_output, description);
|
||||
|
||||
struct wl_event_loop *ev = wl_display_get_event_loop(backend->display);
|
||||
|
|
|
@ -84,7 +84,7 @@ static void log_libinput(struct libinput *libinput_context,
|
|||
static bool backend_start(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_libinput_backend *backend =
|
||||
get_libinput_backend_from_backend(wlr_backend);
|
||||
wlr_log(WLR_DEBUG, "Initializing libinput");
|
||||
wlr_log(WLR_DEBUG, "Starting libinput backend");
|
||||
|
||||
backend->libinput_context = libinput_udev_create_context(&libinput_impl,
|
||||
backend, backend->session->udev);
|
||||
|
@ -110,9 +110,9 @@ static bool backend_start(struct wlr_backend *wlr_backend) {
|
|||
no_devs = NULL;
|
||||
}
|
||||
}
|
||||
if (!no_devs && backend->wlr_device_lists.length == 0) {
|
||||
if (!no_devs && backend->wlr_device_lists.size == 0) {
|
||||
handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend);
|
||||
if (backend->wlr_device_lists.length == 0) {
|
||||
if (backend->wlr_device_lists.size == 0) {
|
||||
wlr_log(WLR_ERROR, "libinput initialization failed, no input devices");
|
||||
wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check");
|
||||
return false;
|
||||
|
@ -141,13 +141,13 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
struct wlr_libinput_backend *backend =
|
||||
get_libinput_backend_from_backend(wlr_backend);
|
||||
|
||||
for (size_t i = 0; i < backend->wlr_device_lists.length; i++) {
|
||||
struct wl_list *wlr_devices = backend->wlr_device_lists.items[i];
|
||||
struct wlr_input_device *wlr_dev, *next;
|
||||
wl_list_for_each_safe(wlr_dev, next, wlr_devices, link) {
|
||||
wlr_input_device_destroy(wlr_dev);
|
||||
struct wl_list **wlr_devices_ptr;
|
||||
wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) {
|
||||
struct wlr_libinput_input_device *dev, *tmp;
|
||||
wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) {
|
||||
wlr_input_device_destroy(&dev->wlr_input_device);
|
||||
}
|
||||
free(wlr_devices);
|
||||
free(*wlr_devices_ptr);
|
||||
}
|
||||
|
||||
wlr_backend_finish(wlr_backend);
|
||||
|
@ -156,7 +156,7 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
wl_list_remove(&backend->session_destroy.link);
|
||||
wl_list_remove(&backend->session_signal.link);
|
||||
|
||||
wlr_list_finish(&backend->wlr_device_lists);
|
||||
wl_array_release(&backend->wlr_device_lists);
|
||||
if (backend->input_event) {
|
||||
wl_event_source_remove(backend->input_event);
|
||||
}
|
||||
|
@ -211,10 +211,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
|
|||
}
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
|
||||
if (!wlr_list_init(&backend->wlr_device_lists)) {
|
||||
wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno));
|
||||
goto error_backend;
|
||||
}
|
||||
wl_array_init(&backend->wlr_device_lists);
|
||||
|
||||
backend->session = session;
|
||||
backend->display = display;
|
||||
|
@ -229,9 +226,6 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
|
|||
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
||||
|
||||
return &backend->backend;
|
||||
error_backend:
|
||||
free(backend);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct libinput_device *wlr_libinput_get_device_handle(
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <wlr/interfaces/wlr_input_device.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/libinput.h"
|
||||
#include "util/array.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
static struct wlr_libinput_input_device *get_libinput_device_from_device(
|
||||
|
@ -22,10 +23,10 @@ struct wlr_input_device *get_appropriate_device(
|
|||
if (!wlr_devices) {
|
||||
return NULL;
|
||||
}
|
||||
struct wlr_input_device *dev;
|
||||
struct wlr_libinput_input_device *dev;
|
||||
wl_list_for_each(dev, wlr_devices, link) {
|
||||
if (dev->type == desired_type) {
|
||||
return dev;
|
||||
if (dev->wlr_input_device.type == desired_type) {
|
||||
return &dev->wlr_input_device;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -35,7 +36,7 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) {
|
|||
struct wlr_libinput_input_device *dev =
|
||||
get_libinput_device_from_device(wlr_dev);
|
||||
libinput_device_unref(dev->handle);
|
||||
wl_list_remove(&dev->wlr_input_device.link);
|
||||
wl_list_remove(&dev->link);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
@ -62,7 +63,7 @@ static struct wlr_input_device *allocate_device(
|
|||
if (output_name != NULL) {
|
||||
wlr_dev->output_name = strdup(output_name);
|
||||
}
|
||||
wl_list_insert(wlr_devices, &wlr_dev->link);
|
||||
wl_list_insert(wlr_devices, &dev->link);
|
||||
dev->handle = libinput_dev;
|
||||
libinput_device_ref(libinput_dev);
|
||||
wlr_input_device_init(wlr_dev, type, &input_device_impl,
|
||||
|
@ -183,8 +184,13 @@ static void handle_device_added(struct wlr_libinput_backend *backend,
|
|||
}
|
||||
|
||||
if (!wl_list_empty(wlr_devices)) {
|
||||
struct wl_list **dst = wl_array_add(&backend->wlr_device_lists, sizeof(wlr_devices));
|
||||
if (!dst) {
|
||||
goto fail;
|
||||
}
|
||||
*dst = wlr_devices;
|
||||
|
||||
libinput_device_set_user_data(libinput_dev, wlr_devices);
|
||||
wlr_list_push(&backend->wlr_device_lists, wlr_devices);
|
||||
} else {
|
||||
free(wlr_devices);
|
||||
}
|
||||
|
@ -192,7 +198,7 @@ static void handle_device_added(struct wlr_libinput_backend *backend,
|
|||
|
||||
fail:
|
||||
wlr_log(WLR_ERROR, "Could not allocate new device");
|
||||
struct wlr_input_device *dev, *tmp_dev;
|
||||
struct wlr_libinput_input_device *dev, *tmp_dev;
|
||||
wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
|
||||
free(dev);
|
||||
}
|
||||
|
@ -209,15 +215,20 @@ static void handle_device_removed(struct wlr_libinput_backend *backend,
|
|||
if (!wlr_devices) {
|
||||
return;
|
||||
}
|
||||
struct wlr_input_device *dev, *tmp_dev;
|
||||
struct wlr_libinput_input_device *dev, *tmp_dev;
|
||||
wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
|
||||
wlr_input_device_destroy(dev);
|
||||
wlr_input_device_destroy(&dev->wlr_input_device);
|
||||
}
|
||||
for (size_t i = 0; i < backend->wlr_device_lists.length; i++) {
|
||||
if (backend->wlr_device_lists.items[i] == wlr_devices) {
|
||||
wlr_list_del(&backend->wlr_device_lists, i);
|
||||
size_t i = 0;
|
||||
struct wl_list **ptr;
|
||||
wl_array_for_each(ptr, &backend->wlr_device_lists) {
|
||||
struct wl_list *iter = *ptr;
|
||||
if (iter == wlr_devices) {
|
||||
array_remove_at(&backend->wlr_device_lists,
|
||||
i * sizeof(struct wl_list *), sizeof(struct wl_list *));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
free(wlr_devices);
|
||||
}
|
||||
|
@ -261,7 +272,7 @@ void handle_libinput_event(struct wlr_libinput_backend *backend,
|
|||
handle_touch_cancel(event, libinput_dev);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TOUCH_FRAME:
|
||||
// no-op (at least for now)
|
||||
handle_touch_frame(event, libinput_dev);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
|
||||
handle_tablet_tool_axis(event, libinput_dev);
|
||||
|
@ -305,6 +316,14 @@ void handle_libinput_event(struct wlr_libinput_backend *backend,
|
|||
case LIBINPUT_EVENT_GESTURE_PINCH_END:
|
||||
handle_pointer_pinch_end(event, libinput_dev);
|
||||
break;
|
||||
#if LIBINPUT_HAS_HOLD_GESTURES
|
||||
case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
|
||||
handle_pointer_hold_begin(event, libinput_dev);
|
||||
break;
|
||||
case LIBINPUT_EVENT_GESTURE_HOLD_END:
|
||||
handle_pointer_hold_end(event, libinput_dev);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
wlr_log(WLR_DEBUG, "Unknown libinput event %d", event_type);
|
||||
break;
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
msg = ['Required for libinput backend support.']
|
||||
if 'libinput' in backends
|
||||
msg += 'Install "libinput" or disable the libinput backend.'
|
||||
endif
|
||||
|
||||
libinput = dependency(
|
||||
'libinput',
|
||||
version: '>=1.14.0',
|
||||
required: 'libinput' in backends,
|
||||
not_found_message: '\n'.join(msg),
|
||||
)
|
||||
|
||||
if not libinput.found()
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
wlr_files += files(
|
||||
'backend.c',
|
||||
'events.c',
|
||||
|
@ -8,3 +24,12 @@ wlr_files += files(
|
|||
'tablet_tool.c',
|
||||
'touch.c',
|
||||
)
|
||||
|
||||
features += { 'libinput-backend': true }
|
||||
wlr_deps += libinput
|
||||
|
||||
# libinput hold gestures are available since 1.19.0
|
||||
add_project_arguments(
|
||||
'-DLIBINPUT_HAS_HOLD_GESTURES=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()),
|
||||
language: 'c',
|
||||
)
|
||||
|
|
|
@ -260,3 +260,41 @@ void handle_pointer_pinch_end(struct libinput_event *event,
|
|||
};
|
||||
wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_end, &wlr_event);
|
||||
}
|
||||
|
||||
void handle_pointer_hold_begin(struct libinput_event *event,
|
||||
struct libinput_device *libinput_dev) {
|
||||
struct wlr_input_device *wlr_dev =
|
||||
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
|
||||
if (!wlr_dev) {
|
||||
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
|
||||
return;
|
||||
}
|
||||
struct libinput_event_gesture *gevent =
|
||||
libinput_event_get_gesture_event(event);
|
||||
struct wlr_event_pointer_hold_begin wlr_event = {
|
||||
.device = wlr_dev,
|
||||
.time_msec =
|
||||
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
|
||||
.fingers = libinput_event_gesture_get_finger_count(gevent),
|
||||
};
|
||||
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_begin, &wlr_event);
|
||||
}
|
||||
|
||||
void handle_pointer_hold_end(struct libinput_event *event,
|
||||
struct libinput_device *libinput_dev) {
|
||||
struct wlr_input_device *wlr_dev =
|
||||
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
|
||||
if (!wlr_dev) {
|
||||
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
|
||||
return;
|
||||
}
|
||||
struct libinput_event_gesture *gevent =
|
||||
libinput_event_get_gesture_event(event);
|
||||
struct wlr_event_pointer_hold_end wlr_event = {
|
||||
.device = wlr_dev,
|
||||
.time_msec =
|
||||
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
|
||||
.cancelled = libinput_event_gesture_get_cancelled(gevent),
|
||||
};
|
||||
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_end, &wlr_event);
|
||||
}
|
||||
|
|
|
@ -85,7 +85,8 @@ struct wlr_tablet_pad *create_libinput_tablet_pad(
|
|||
libinput_device_tablet_pad_get_num_strips(libinput_dev);
|
||||
|
||||
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
|
||||
wlr_list_push(&wlr_tablet_pad->paths, strdup(udev_device_get_syspath(udev)));
|
||||
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
|
||||
int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev);
|
||||
for (int i = 0; i < groups; ++i) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/libinput.h"
|
||||
#include "util/array.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
static const struct wlr_tablet_impl tablet_impl;
|
||||
|
@ -29,18 +30,9 @@ struct wlr_libinput_tablet_tool {
|
|||
size_t pad_refs;
|
||||
};
|
||||
|
||||
// TODO: Maybe this should be a wlr_list? Do we keep it, or want to get rid of
|
||||
// it?
|
||||
struct tablet_tool_list_elem {
|
||||
struct wl_list link;
|
||||
|
||||
struct wlr_libinput_tablet_tool *tool;
|
||||
};
|
||||
|
||||
struct wlr_libinput_tablet {
|
||||
struct wlr_tablet wlr_tablet;
|
||||
|
||||
struct wl_list tools; // tablet_tool_list_elem::link
|
||||
struct wl_array tools; // struct wlr_libinput_tablet_tool *
|
||||
};
|
||||
|
||||
static void destroy_tool(struct wlr_libinput_tablet_tool *tool) {
|
||||
|
@ -56,17 +48,14 @@ static void destroy_tablet(struct wlr_tablet *wlr_tablet) {
|
|||
struct wlr_libinput_tablet *tablet =
|
||||
wl_container_of(wlr_tablet, tablet, wlr_tablet);
|
||||
|
||||
struct tablet_tool_list_elem *pos;
|
||||
struct tablet_tool_list_elem *tmp;
|
||||
wl_list_for_each_safe(pos, tmp, &tablet->tools, link) {
|
||||
struct wlr_libinput_tablet_tool *tool = pos->tool;
|
||||
wl_list_remove(&pos->link);
|
||||
free(pos);
|
||||
|
||||
struct wlr_libinput_tablet_tool **tool_ptr;
|
||||
wl_array_for_each(tool_ptr, &tablet->tools) {
|
||||
struct wlr_libinput_tablet_tool *tool = *tool_ptr;
|
||||
if (--tool->pad_refs == 0) {
|
||||
destroy_tool(tool);
|
||||
}
|
||||
}
|
||||
wl_array_release(&tablet->tools);
|
||||
|
||||
free(tablet);
|
||||
}
|
||||
|
@ -84,15 +73,18 @@ struct wlr_tablet *create_libinput_tablet(
|
|||
wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet;
|
||||
|
||||
wlr_list_init(&wlr_tablet->paths);
|
||||
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
|
||||
wlr_list_push(&wlr_tablet->paths, strdup(udev_device_get_syspath(udev)));
|
||||
wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev));
|
||||
wl_list_init(&libinput_tablet->tools);
|
||||
|
||||
wlr_tablet_init(wlr_tablet, &tablet_impl);
|
||||
|
||||
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
|
||||
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
|
||||
*dst = strdup(udev_device_get_syspath(udev));
|
||||
|
||||
wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev));
|
||||
|
||||
wl_array_init(&libinput_tablet->tools);
|
||||
|
||||
return wlr_tablet;
|
||||
}
|
||||
|
||||
|
@ -160,9 +152,9 @@ static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool,
|
|||
struct wlr_libinput_tablet *tablet =
|
||||
wl_container_of(wlr_dev, tablet, wlr_tablet);
|
||||
|
||||
struct tablet_tool_list_elem *pos;
|
||||
wl_list_for_each(pos, &tablet->tools, link) {
|
||||
if (pos->tool == tool) { // We already have a ref
|
||||
struct wlr_libinput_tablet_tool **tool_ptr;
|
||||
wl_array_for_each(tool_ptr, &tablet->tools) {
|
||||
if (*tool_ptr == tool) { // We already have a ref
|
||||
// XXX: We *could* optimize the tool to the front of
|
||||
// the list here, since we will probably get the next
|
||||
// couple of events from the same tool.
|
||||
|
@ -173,15 +165,13 @@ static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool,
|
|||
}
|
||||
}
|
||||
|
||||
struct tablet_tool_list_elem *new =
|
||||
calloc(1, sizeof(struct tablet_tool_list_elem));
|
||||
if (!new) {
|
||||
struct wlr_libinput_tablet_tool **dst =
|
||||
wl_array_add(&tablet->tools, sizeof(tool));
|
||||
if (!dst) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate memory for tracking tablet tool");
|
||||
return;
|
||||
}
|
||||
|
||||
new->tool = tool;
|
||||
wl_list_insert(&tablet->tools, &new->link);
|
||||
*dst = tool;
|
||||
++tool->pad_refs;
|
||||
}
|
||||
|
||||
|
@ -294,15 +284,15 @@ void handle_tablet_tool_proximity(struct libinput_event *event,
|
|||
assert(tablet_is_libinput(wlr_dev->tablet));
|
||||
struct wlr_libinput_tablet *tablet =
|
||||
wl_container_of(wlr_dev->tablet, tablet, wlr_tablet);
|
||||
struct tablet_tool_list_elem *pos;
|
||||
struct tablet_tool_list_elem *tmp;
|
||||
|
||||
wl_list_for_each_safe(pos, tmp, &tablet->tools, link) {
|
||||
if (pos->tool == tool) {
|
||||
wl_list_remove(&pos->link);
|
||||
free(pos);
|
||||
size_t i = 0;
|
||||
struct wlr_libinput_tablet_tool **tool_ptr;
|
||||
wl_array_for_each(tool_ptr, &tablet->tools) {
|
||||
if (*tool_ptr == tool) {
|
||||
array_remove_at(&tablet->tools, i * sizeof(tool), sizeof(tool));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
destroy_tool(tool);
|
||||
|
|
|
@ -95,3 +95,14 @@ void handle_touch_cancel(struct libinput_event *event,
|
|||
wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent);
|
||||
wlr_signal_emit_safe(&wlr_dev->touch->events.cancel, &wlr_event);
|
||||
}
|
||||
|
||||
void handle_touch_frame(struct libinput_event *event,
|
||||
struct libinput_device *libinput_dev) {
|
||||
struct wlr_input_device *wlr_dev =
|
||||
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
|
||||
if (!wlr_dev) {
|
||||
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
|
||||
return;
|
||||
}
|
||||
wlr_signal_emit_safe(&wlr_dev->touch->events.frame, NULL);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
wlr_files += files('backend.c')
|
||||
|
||||
subdir('drm')
|
||||
subdir('headless')
|
||||
subdir('libinput')
|
||||
all_backends = ['drm', 'libinput', 'x11']
|
||||
backends = get_option('backends')
|
||||
if 'auto' in backends and get_option('auto_features').enabled()
|
||||
backends = all_backends
|
||||
elif 'auto' in backends and get_option('auto_features').disabled()
|
||||
backends = []
|
||||
endif
|
||||
|
||||
foreach backend : all_backends
|
||||
if backend in backends or 'auto' in backends
|
||||
subdir(backend)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
subdir('multi')
|
||||
subdir('noop')
|
||||
subdir('wayland')
|
||||
subdir('x11')
|
||||
subdir('headless')
|
||||
|
||||
subdir('session')
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#include <time.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/multi.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
|
@ -62,20 +64,6 @@ static void multi_backend_destroy(struct wlr_backend *wlr_backend) {
|
|||
free(backend);
|
||||
}
|
||||
|
||||
static struct wlr_renderer *multi_backend_get_renderer(
|
||||
struct wlr_backend *backend) {
|
||||
struct wlr_multi_backend *multi = multi_backend_from_backend(backend);
|
||||
|
||||
struct subbackend_state *sub;
|
||||
wl_list_for_each(sub, &multi->backends, link) {
|
||||
struct wlr_renderer *rend = wlr_backend_get_renderer(sub->backend);
|
||||
if (rend != NULL) {
|
||||
return rend;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wlr_session *multi_backend_get_session(
|
||||
struct wlr_backend *_backend) {
|
||||
struct wlr_multi_backend *backend = multi_backend_from_backend(_backend);
|
||||
|
@ -109,13 +97,35 @@ 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 const struct wlr_backend_impl backend_impl = {
|
||||
.start = multi_backend_start,
|
||||
.destroy = multi_backend_destroy,
|
||||
.get_renderer = multi_backend_get_renderer,
|
||||
.get_session = multi_backend_get_session,
|
||||
.get_presentation_clock = multi_backend_get_presentation_clock,
|
||||
.get_drm_fd = multi_backend_get_drm_fd,
|
||||
.get_buffer_caps = multi_backend_get_buffer_caps,
|
||||
};
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
|
@ -179,6 +189,9 @@ static struct subbackend_state *multi_backend_get_subbackend(struct wlr_multi_ba
|
|||
|
||||
bool wlr_multi_backend_add(struct wlr_backend *_multi,
|
||||
struct wlr_backend *backend) {
|
||||
assert(_multi && backend);
|
||||
assert(_multi != backend);
|
||||
|
||||
struct wlr_multi_backend *multi = multi_backend_from_backend(_multi);
|
||||
|
||||
if (multi_backend_get_subbackend(multi, backend)) {
|
||||
|
@ -186,15 +199,6 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct wlr_renderer *multi_renderer =
|
||||
multi_backend_get_renderer(&multi->backend);
|
||||
struct wlr_renderer *backend_renderer = wlr_backend_get_renderer(backend);
|
||||
if (multi_renderer != NULL && backend_renderer != NULL && multi_renderer != backend_renderer) {
|
||||
wlr_log(WLR_ERROR, "Could not add backend: multiple renderers at the "
|
||||
"same time aren't supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct subbackend_state *sub = calloc(1, sizeof(struct subbackend_state));
|
||||
if (sub == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not add backend: allocation failed");
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/noop.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
struct wlr_noop_backend *noop_backend_from_backend(
|
||||
struct wlr_backend *wlr_backend) {
|
||||
assert(wlr_backend_is_noop(wlr_backend));
|
||||
return (struct wlr_noop_backend *)wlr_backend;
|
||||
}
|
||||
|
||||
static bool backend_start(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend);
|
||||
wlr_log(WLR_INFO, "Starting noop backend");
|
||||
|
||||
struct wlr_noop_output *output;
|
||||
wl_list_for_each(output, &backend->outputs, link) {
|
||||
wlr_output_update_enabled(&output->wlr_output, true);
|
||||
wlr_signal_emit_safe(&backend->backend.events.new_output,
|
||||
&output->wlr_output);
|
||||
}
|
||||
|
||||
backend->started = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void backend_destroy(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend);
|
||||
if (!wlr_backend) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_noop_output *output, *output_tmp;
|
||||
wl_list_for_each_safe(output, output_tmp, &backend->outputs, link) {
|
||||
wlr_output_destroy(&output->wlr_output);
|
||||
}
|
||||
|
||||
wlr_backend_finish(wlr_backend);
|
||||
|
||||
wl_list_remove(&backend->display_destroy.link);
|
||||
|
||||
free(backend);
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
};
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_noop_backend *noop =
|
||||
wl_container_of(listener, noop, display_destroy);
|
||||
backend_destroy(&noop->backend);
|
||||
}
|
||||
|
||||
struct wlr_backend *wlr_noop_backend_create(struct wl_display *display) {
|
||||
wlr_log(WLR_INFO, "Creating noop backend");
|
||||
|
||||
struct wlr_noop_backend *backend =
|
||||
calloc(1, sizeof(struct wlr_noop_backend));
|
||||
if (!backend) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_backend");
|
||||
return NULL;
|
||||
}
|
||||
wlr_backend_init(&backend->backend, &backend_impl);
|
||||
backend->display = display;
|
||||
wl_list_init(&backend->outputs);
|
||||
|
||||
backend->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &backend->display_destroy);
|
||||
|
||||
return &backend->backend;
|
||||
}
|
||||
|
||||
bool wlr_backend_is_noop(struct wlr_backend *backend) {
|
||||
return backend->impl == &backend_impl;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
wlr_files += files(
|
||||
'backend.c',
|
||||
'output.c',
|
||||
)
|
|
@ -1,98 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "backend/noop.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
|
||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
|
||||
WLR_OUTPUT_STATE_MODE;
|
||||
|
||||
static struct wlr_noop_output *noop_output_from_output(
|
||||
struct wlr_output *wlr_output) {
|
||||
assert(wlr_output_is_noop(wlr_output));
|
||||
return (struct wlr_noop_output *)wlr_output;
|
||||
}
|
||||
|
||||
static bool output_attach_render(struct wlr_output *wlr_output,
|
||||
int *buffer_age) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void output_rollback_render(struct wlr_output *wlr_output) {
|
||||
// This space is intentionally left blank
|
||||
}
|
||||
|
||||
static bool output_commit(struct wlr_output *wlr_output) {
|
||||
uint32_t unsupported =
|
||||
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
|
||||
if (unsupported != 0) {
|
||||
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
|
||||
unsupported);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
|
||||
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
|
||||
wlr_output_update_custom_mode(wlr_output,
|
||||
wlr_output->pending.custom_mode.width,
|
||||
wlr_output->pending.custom_mode.height,
|
||||
wlr_output->pending.custom_mode.refresh);
|
||||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void output_destroy(struct wlr_output *wlr_output) {
|
||||
struct wlr_noop_output *output =
|
||||
noop_output_from_output(wlr_output);
|
||||
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
free(output);
|
||||
}
|
||||
|
||||
static const struct wlr_output_impl output_impl = {
|
||||
.destroy = output_destroy,
|
||||
.attach_render = output_attach_render,
|
||||
.rollback_render = output_rollback_render,
|
||||
.commit = output_commit,
|
||||
};
|
||||
|
||||
bool wlr_output_is_noop(struct wlr_output *wlr_output) {
|
||||
return wlr_output->impl == &output_impl;
|
||||
}
|
||||
|
||||
struct wlr_output *wlr_noop_add_output(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_noop_backend *backend = noop_backend_from_backend(wlr_backend);
|
||||
|
||||
struct wlr_noop_output *output = calloc(1, sizeof(struct wlr_noop_output));
|
||||
if (output == NULL) {
|
||||
wlr_log(WLR_ERROR, "Failed to allocate wlr_noop_output");
|
||||
return NULL;
|
||||
}
|
||||
output->backend = backend;
|
||||
wlr_output_init(&output->wlr_output, &backend->backend, &output_impl,
|
||||
backend->display);
|
||||
struct wlr_output *wlr_output = &output->wlr_output;
|
||||
|
||||
strncpy(wlr_output->make, "noop", sizeof(wlr_output->make));
|
||||
strncpy(wlr_output->model, "noop", sizeof(wlr_output->model));
|
||||
snprintf(wlr_output->name, sizeof(wlr_output->name), "NOOP-%zd",
|
||||
++backend->last_output_num);
|
||||
|
||||
wl_list_insert(&backend->outputs, &output->link);
|
||||
|
||||
if (backend->started) {
|
||||
wlr_output_update_enabled(wlr_output, true);
|
||||
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
|
||||
}
|
||||
|
||||
return wlr_output;
|
||||
}
|
|
@ -139,6 +139,35 @@ static bool is_drm_card(const char *sysname) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void read_udev_change_event(struct wlr_device_change_event *event,
|
||||
struct udev_device *udev_dev) {
|
||||
const char *hotplug = udev_device_get_property_value(udev_dev, "HOTPLUG");
|
||||
if (hotplug != NULL && strcmp(hotplug, "1") == 0) {
|
||||
event->type = WLR_DEVICE_HOTPLUG;
|
||||
struct wlr_device_hotplug_event *hotplug = &event->hotplug;
|
||||
|
||||
const char *connector =
|
||||
udev_device_get_property_value(udev_dev, "CONNECTOR");
|
||||
if (connector != NULL) {
|
||||
hotplug->connector_id = strtoul(connector, NULL, 10);
|
||||
}
|
||||
|
||||
const char *prop =
|
||||
udev_device_get_property_value(udev_dev, "PROPERTY");
|
||||
if (prop != NULL) {
|
||||
hotplug->prop_id = strtoul(prop, NULL, 10);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char *lease = udev_device_get_property_value(udev_dev, "LEASE");
|
||||
if (lease != NULL && strcmp(lease, "1") == 0) {
|
||||
event->type = WLR_DEVICE_LEASE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
||||
struct wlr_session *session = data;
|
||||
|
||||
|
@ -180,7 +209,9 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
|
|||
|
||||
if (strcmp(action, "change") == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
|
||||
wlr_signal_emit_safe(&dev->events.change, NULL);
|
||||
struct wlr_device_change_event event = {0};
|
||||
read_udev_change_event(&event, udev_dev);
|
||||
wlr_signal_emit_safe(&dev->events.change, &event);
|
||||
} else if (strcmp(action, "remove") == 0) {
|
||||
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
|
||||
wlr_signal_emit_safe(&dev->events.remove, NULL);
|
||||
|
@ -339,7 +370,7 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) {
|
|||
|
||||
/* Tests if 'path' is KMS compatible by trying to open it. Returns the opened
|
||||
* device on success. */
|
||||
static struct wlr_device *open_if_kms(struct wlr_session *restrict session,
|
||||
struct wlr_device *session_open_if_kms(struct wlr_session *restrict session,
|
||||
const char *restrict path) {
|
||||
if (!path) {
|
||||
return NULL;
|
||||
|
@ -375,7 +406,7 @@ static ssize_t explicit_find_gpus(struct wlr_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
ret[i] = open_if_kms(session, ptr);
|
||||
ret[i] = session_open_if_kms(session, ptr);
|
||||
if (!ret[i]) {
|
||||
wlr_log(WLR_ERROR, "Unable to open %s as DRM device", ptr);
|
||||
} else {
|
||||
|
@ -511,7 +542,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
}
|
||||
|
||||
struct wlr_device *wlr_dev =
|
||||
open_if_kms(session, udev_device_get_devnode(dev));
|
||||
session_open_if_kms(session, udev_device_get_devnode(dev));
|
||||
if (!wlr_dev) {
|
||||
udev_device_unref(dev);
|
||||
continue;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
@ -15,24 +17,36 @@
|
|||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/wayland.h"
|
||||
#include "render/allocator.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "render/pixel_format.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
#include "drm-client-protocol.h"
|
||||
#include "linux-dmabuf-unstable-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"
|
||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "tablet-unstable-v2-client-protocol.h"
|
||||
#include "relative-pointer-unstable-v1-client-protocol.h"
|
||||
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 {
|
||||
struct wlr_wl_backend *backend;
|
||||
dev_t main_device_id;
|
||||
struct wlr_wl_linux_dmabuf_v1_table_entry *format_table;
|
||||
size_t format_table_size;
|
||||
|
||||
dev_t tranche_target_device_id;
|
||||
};
|
||||
|
||||
struct wlr_wl_linux_dmabuf_v1_table_entry {
|
||||
uint32_t format;
|
||||
uint32_t pad; /* unused */
|
||||
uint64_t modifier;
|
||||
};
|
||||
|
||||
struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend) {
|
||||
assert(wlr_backend_is_wl(backend));
|
||||
return (struct wlr_wl_backend *)backend;
|
||||
|
@ -78,6 +92,16 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
|||
xdg_wm_base_handle_ping,
|
||||
};
|
||||
|
||||
static void presentation_handle_clock_id(void *data,
|
||||
struct wp_presentation *presentation, uint32_t clock) {
|
||||
struct wlr_wl_backend *wl = data;
|
||||
wl->presentation_clock = clock;
|
||||
}
|
||||
|
||||
static const struct wp_presentation_listener presentation_listener = {
|
||||
.clock_id = presentation_handle_clock_id,
|
||||
};
|
||||
|
||||
static void linux_dmabuf_v1_handle_format(void *data,
|
||||
struct zwp_linux_dmabuf_v1 *linux_dmabuf_v1, uint32_t format) {
|
||||
// Note, this event is deprecated
|
||||
|
@ -101,6 +125,119 @@ static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_v1_listener = {
|
|||
.modifier = linux_dmabuf_v1_handle_modifier,
|
||||
};
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_done(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback) {
|
||||
// This space is intentionally left blank
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_format_table(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback, int fd, uint32_t size) {
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data;
|
||||
|
||||
feedback_data->format_table = NULL;
|
||||
|
||||
void *table_data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (table_data == MAP_FAILED) {
|
||||
wlr_log_errno(WLR_ERROR, "failed to mmap DMA-BUF format table");
|
||||
} else {
|
||||
feedback_data->format_table = table_data;
|
||||
feedback_data->format_table_size = size;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_main_device(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback,
|
||||
struct wl_array *dev_id_arr) {
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data;
|
||||
|
||||
dev_t dev_id;
|
||||
assert(dev_id_arr->size == sizeof(dev_id));
|
||||
memcpy(&dev_id, dev_id_arr->data, sizeof(dev_id));
|
||||
|
||||
feedback_data->main_device_id = dev_id;
|
||||
|
||||
drmDevice *device = NULL;
|
||||
if (drmGetDeviceFromDevId(dev_id, 0, &device) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "drmGetDeviceFromDevId failed");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *name = NULL;
|
||||
if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
name = device->nodes[DRM_NODE_RENDER];
|
||||
} else {
|
||||
// Likely a split display/render setup. Pick the primary node and hope
|
||||
// Mesa will open the right render node under-the-hood.
|
||||
assert(device->available_nodes & (1 << DRM_NODE_PRIMARY));
|
||||
name = device->nodes[DRM_NODE_PRIMARY];
|
||||
wlr_log(WLR_DEBUG, "DRM device %s has no render node, "
|
||||
"falling back to primary node", name);
|
||||
}
|
||||
|
||||
feedback_data->backend->drm_render_name = strdup(name);
|
||||
|
||||
drmFreeDevice(&device);
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_tranche_done(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback) {
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data;
|
||||
feedback_data->tranche_target_device_id = 0;
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_tranche_target_device(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback,
|
||||
struct wl_array *dev_id_arr) {
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data;
|
||||
|
||||
dev_t dev_id;
|
||||
assert(dev_id_arr->size == sizeof(dev_id));
|
||||
memcpy(&dev_id, dev_id_arr->data, sizeof(dev_id));
|
||||
|
||||
feedback_data->tranche_target_device_id = dev_id;
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_tranche_formats(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback,
|
||||
struct wl_array *indices_arr) {
|
||||
struct wlr_wl_linux_dmabuf_feedback_v1 *feedback_data = data;
|
||||
|
||||
if (feedback_data->format_table == NULL) {
|
||||
return;
|
||||
}
|
||||
if (feedback_data->tranche_target_device_id != feedback_data->main_device_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t table_cap = feedback_data->format_table_size /
|
||||
sizeof(struct wlr_wl_linux_dmabuf_v1_table_entry);
|
||||
uint16_t *index_ptr;
|
||||
wl_array_for_each(index_ptr, indices_arr) {
|
||||
assert(*index_ptr < table_cap);
|
||||
const struct wlr_wl_linux_dmabuf_v1_table_entry *entry =
|
||||
&feedback_data->format_table[*index_ptr];
|
||||
wlr_drm_format_set_add(&feedback_data->backend->linux_dmabuf_v1_formats,
|
||||
entry->format, entry->modifier);
|
||||
}
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_v1_handle_tranche_flags(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *feedback, uint32_t flags) {
|
||||
// TODO: handle SCANOUT flag
|
||||
}
|
||||
|
||||
static const struct zwp_linux_dmabuf_feedback_v1_listener
|
||||
linux_dmabuf_feedback_v1_listener = {
|
||||
.done = linux_dmabuf_feedback_v1_handle_done,
|
||||
.format_table = linux_dmabuf_feedback_v1_handle_format_table,
|
||||
.main_device = linux_dmabuf_feedback_v1_handle_main_device,
|
||||
.tranche_done = linux_dmabuf_feedback_v1_handle_tranche_done,
|
||||
.tranche_target_device = linux_dmabuf_feedback_v1_handle_tranche_target_device,
|
||||
.tranche_formats = linux_dmabuf_feedback_v1_handle_tranche_formats,
|
||||
.tranche_flags = linux_dmabuf_feedback_v1_handle_tranche_flags,
|
||||
};
|
||||
|
||||
static bool device_has_name(const drmDevice *device, const char *name) {
|
||||
for (size_t i = 0; i < DRM_NODE_MAX; i++) {
|
||||
if (!(device->available_nodes & (1 << i))) {
|
||||
|
@ -165,8 +302,6 @@ 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;
|
||||
|
||||
// TODO: get FD from linux-dmabuf hints instead
|
||||
wl->drm_render_name = get_render_name(name);
|
||||
}
|
||||
|
||||
|
@ -226,17 +361,19 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
} else if (strcmp(iface, zwp_pointer_gestures_v1_interface.name) == 0) {
|
||||
wl->zwp_pointer_gestures_v1 = wl_registry_bind(registry, name,
|
||||
&zwp_pointer_gestures_v1_interface, 1);
|
||||
&zwp_pointer_gestures_v1_interface, version < 3 ? version : 3);
|
||||
} else if (strcmp(iface, wp_presentation_interface.name) == 0) {
|
||||
wl->presentation = wl_registry_bind(registry, name,
|
||||
&wp_presentation_interface, 1);
|
||||
wp_presentation_add_listener(wl->presentation,
|
||||
&presentation_listener, wl);
|
||||
} else if (strcmp(iface, zwp_tablet_manager_v2_interface.name) == 0) {
|
||||
wl->tablet_manager = wl_registry_bind(registry, name,
|
||||
&zwp_tablet_manager_v2_interface, 1);
|
||||
} else if (strcmp(iface, zwp_linux_dmabuf_v1_interface.name) == 0 &&
|
||||
version >= 3) {
|
||||
wl->zwp_linux_dmabuf_v1 = wl_registry_bind(registry, name,
|
||||
&zwp_linux_dmabuf_v1_interface, 3);
|
||||
&zwp_linux_dmabuf_v1_interface, version >= 4 ? 4 : version);
|
||||
zwp_linux_dmabuf_v1_add_listener(wl->zwp_linux_dmabuf_v1,
|
||||
&linux_dmabuf_v1_listener, wl);
|
||||
} else if (strcmp(iface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
|
||||
|
@ -248,6 +385,9 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(iface, wl_shm_interface.name) == 0) {
|
||||
wl->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||
wl_shm_add_listener(wl->shm, &shm_listener, wl);
|
||||
} else if (strcmp(iface, xdg_activation_v1_interface.name) == 0) {
|
||||
wl->activation_v1 = wl_registry_bind(registry, name,
|
||||
&xdg_activation_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,7 +408,7 @@ static const struct wl_registry_listener registry_listener = {
|
|||
*/
|
||||
static bool backend_start(struct wlr_backend *backend) {
|
||||
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
||||
wlr_log(WLR_INFO, "Initializating wayland backend");
|
||||
wlr_log(WLR_INFO, "Starting Wayland backend");
|
||||
|
||||
wl->started = true;
|
||||
|
||||
|
@ -302,9 +442,9 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
wlr_output_destroy(&output->wlr_output);
|
||||
}
|
||||
|
||||
struct wlr_input_device *input_device, *tmp_input_device;
|
||||
struct wlr_wl_input_device *input_device, *tmp_input_device;
|
||||
wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) {
|
||||
wlr_input_device_destroy(input_device);
|
||||
wlr_input_device_destroy(&input_device->wlr_input_device);
|
||||
}
|
||||
|
||||
struct wlr_wl_buffer *buffer, *tmp_buffer;
|
||||
|
@ -343,6 +483,7 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
zwp_relative_pointer_manager_v1_destroy(wl->zwp_relative_pointer_manager_v1);
|
||||
}
|
||||
free(wl->drm_render_name);
|
||||
free(wl->activation_token);
|
||||
xdg_wm_base_destroy(wl->xdg_wm_base);
|
||||
wl_compositor_destroy(wl->compositor);
|
||||
wl_registry_destroy(wl->registry);
|
||||
|
@ -351,6 +492,11 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
free(wl);
|
||||
}
|
||||
|
||||
static clockid_t backend_get_presentation_clock(struct wlr_backend *backend) {
|
||||
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
||||
return wl->presentation_clock;
|
||||
}
|
||||
|
||||
static int backend_get_drm_fd(struct wlr_backend *backend) {
|
||||
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
|
||||
return wl->drm_fd;
|
||||
|
@ -365,6 +511,7 @@ static uint32_t get_buffer_caps(struct wlr_backend *backend) {
|
|||
static const struct wlr_backend_impl backend_impl = {
|
||||
.start = backend_start,
|
||||
.destroy = backend_destroy,
|
||||
.get_presentation_clock = backend_get_presentation_clock,
|
||||
.get_drm_fd = backend_get_drm_fd,
|
||||
.get_buffer_caps = get_buffer_caps,
|
||||
};
|
||||
|
@ -396,6 +543,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
wl_list_init(&wl->outputs);
|
||||
wl_list_init(&wl->seats);
|
||||
wl_list_init(&wl->buffers);
|
||||
wl->presentation_clock = CLOCK_MONOTONIC;
|
||||
|
||||
wl->remote_display = wl_display_connect(remote);
|
||||
if (!wl->remote_display) {
|
||||
|
@ -408,10 +556,9 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
|
||||
goto error_display;
|
||||
}
|
||||
|
||||
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
||||
|
||||
wl_display_roundtrip(wl->remote_display); // get globals
|
||||
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats
|
||||
|
||||
if (!wl->compositor) {
|
||||
wlr_log(WLR_ERROR,
|
||||
|
@ -424,6 +571,35 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
goto error_registry;
|
||||
}
|
||||
|
||||
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 &&
|
||||
zwp_linux_dmabuf_v1_get_version(wl->zwp_linux_dmabuf_v1) >=
|
||||
ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) {
|
||||
linux_dmabuf_feedback_v1 =
|
||||
zwp_linux_dmabuf_v1_get_default_feedback(wl->zwp_linux_dmabuf_v1);
|
||||
if (linux_dmabuf_feedback_v1 == NULL) {
|
||||
wlr_log(WLR_ERROR, "Allocation failed");
|
||||
goto error_registry;
|
||||
}
|
||||
zwp_linux_dmabuf_feedback_v1_add_listener(linux_dmabuf_feedback_v1,
|
||||
&linux_dmabuf_feedback_v1_listener, &feedback_data);
|
||||
|
||||
if (wl->legacy_drm != NULL) {
|
||||
wl_drm_destroy(wl->legacy_drm);
|
||||
wl->legacy_drm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display);
|
||||
int fd = wl_display_get_fd(wl->remote_display);
|
||||
wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
|
||||
|
@ -446,19 +622,17 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
wl->drm_fd = -1;
|
||||
}
|
||||
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(&wl->backend);
|
||||
struct wlr_allocator *allocator = backend_get_allocator(&wl->backend);
|
||||
if (renderer == NULL || allocator == NULL) {
|
||||
goto error_drm_fd;
|
||||
}
|
||||
|
||||
wl->local_display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &wl->local_display_destroy);
|
||||
|
||||
const char *token = getenv("XDG_ACTIVATION_TOKEN");
|
||||
if (token != NULL) {
|
||||
wl->activation_token = strdup(token);
|
||||
unsetenv("XDG_ACTIVATION_TOKEN");
|
||||
}
|
||||
|
||||
return &wl->backend;
|
||||
|
||||
error_drm_fd:
|
||||
close(wl->drm_fd);
|
||||
error_remote_display_src:
|
||||
wl_event_source_remove(wl->remote_display_src);
|
||||
error_registry:
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
wayland_client = dependency('wayland-client',
|
||||
fallback: ['wayland', 'wayland_client_dep'],
|
||||
default_options: wayland_project_options,
|
||||
)
|
||||
wlr_deps += wayland_client
|
||||
|
||||
wlr_files += files(
|
||||
'backend.c',
|
||||
'output.c',
|
||||
|
@ -12,6 +18,7 @@ client_protos = [
|
|||
'presentation-time',
|
||||
'relative-pointer-unstable-v1',
|
||||
'tablet-unstable-v2',
|
||||
'xdg-activation-v1',
|
||||
'xdg-decoration-unstable-v1',
|
||||
'xdg-shell',
|
||||
]
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
#include "render/pixel_format.h"
|
||||
#include "render/swapchain.h"
|
||||
#include "render/wlr_renderer.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
#include "xdg-activation-v1-client-protocol.h"
|
||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
|
@ -76,6 +76,7 @@ static void presentation_feedback_handle_presented(void *data,
|
|||
};
|
||||
struct wlr_output_event_present event = {
|
||||
.commit_seq = feedback->commit_seq,
|
||||
.presented = true,
|
||||
.when = &t,
|
||||
.seq = ((uint64_t)seq_hi << 32) | seq_lo,
|
||||
.refresh = refresh_ns,
|
||||
|
@ -90,7 +91,11 @@ static void presentation_feedback_handle_discarded(void *data,
|
|||
struct wp_presentation_feedback *wp_feedback) {
|
||||
struct wlr_wl_presentation_feedback *feedback = data;
|
||||
|
||||
wlr_output_send_present(&feedback->output->wlr_output, NULL);
|
||||
struct wlr_output_event_present event = {
|
||||
.commit_seq = feedback->commit_seq,
|
||||
.presented = false,
|
||||
};
|
||||
wlr_output_send_present(&feedback->output->wlr_output, &event);
|
||||
|
||||
presentation_feedback_destroy(feedback);
|
||||
}
|
||||
|
@ -161,18 +166,8 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
|
|||
dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) {
|
||||
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
|
||||
}
|
||||
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED) {
|
||||
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED;
|
||||
}
|
||||
if (dmabuf->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST) {
|
||||
flags |= ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST;
|
||||
}
|
||||
struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
|
||||
params, dmabuf->width, dmabuf->height, dmabuf->format, flags);
|
||||
params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
|
||||
// TODO: handle create() errors
|
||||
return wl_buffer;
|
||||
}
|
||||
|
@ -262,7 +257,6 @@ static bool output_test(struct wlr_output *wlr_output) {
|
|||
}
|
||||
|
||||
if ((wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) &&
|
||||
wlr_output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT &&
|
||||
!test_buffer(output->backend, wlr_output->pending.buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -288,9 +282,6 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
}
|
||||
|
||||
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
assert(wlr_output->pending.buffer_type ==
|
||||
WLR_OUTPUT_STATE_BUFFER_SCANOUT);
|
||||
|
||||
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||
if (output->backend->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||
|
@ -350,7 +341,11 @@ static bool output_commit(struct wlr_output *wlr_output) {
|
|||
wp_presentation_feedback_add_listener(wp_feedback,
|
||||
&presentation_feedback_listener, feedback);
|
||||
} else {
|
||||
wlr_output_send_present(wlr_output, NULL);
|
||||
struct wlr_output_event_present present_event = {
|
||||
.commit_seq = wlr_output->commit_seq + 1,
|
||||
.presented = true,
|
||||
};
|
||||
wlr_output_send_present(wlr_output, &present_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,12 +520,14 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
|||
wlr_output_update_custom_mode(wlr_output, 1280, 720, 0);
|
||||
strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make));
|
||||
strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model));
|
||||
snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%zd",
|
||||
++backend->last_output_num);
|
||||
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "WL-%zu", ++backend->last_output_num);
|
||||
wlr_output_set_name(wlr_output, name);
|
||||
|
||||
char description[128];
|
||||
snprintf(description, sizeof(description),
|
||||
"Wayland output %zd", backend->last_output_num);
|
||||
"Wayland output %zu", backend->last_output_num);
|
||||
wlr_output_set_description(wlr_output, description);
|
||||
|
||||
output->backend = backend;
|
||||
|
@ -590,6 +587,12 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: let the compositor do this bit
|
||||
if (backend->activation_v1 && backend->activation_token) {
|
||||
xdg_activation_v1_activate(backend->activation_v1,
|
||||
backend->activation_token, output->surface);
|
||||
}
|
||||
|
||||
// Start the rendering loop by requesting the compositor to render a frame
|
||||
wlr_output_schedule_frame(wlr_output);
|
||||
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
static struct wlr_wl_pointer *output_get_pointer(
|
||||
struct wlr_wl_output *output,
|
||||
const struct wl_pointer *wl_pointer) {
|
||||
struct wlr_input_device *wlr_dev;
|
||||
wl_list_for_each(wlr_dev, &output->backend->devices, link) {
|
||||
if (wlr_dev->type != WLR_INPUT_DEVICE_POINTER) {
|
||||
struct wlr_wl_input_device *dev;
|
||||
wl_list_for_each(dev, &output->backend->devices, link) {
|
||||
if (dev->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) {
|
||||
continue;
|
||||
}
|
||||
struct wlr_wl_pointer *pointer = pointer_get_wl(wlr_dev->pointer);
|
||||
struct wlr_wl_pointer *pointer =
|
||||
pointer_get_wl(dev->wlr_input_device.pointer);
|
||||
if (pointer->output == output && pointer->wl_pointer == wl_pointer) {
|
||||
return pointer;
|
||||
}
|
||||
|
@ -352,7 +353,10 @@ static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
|
|||
}
|
||||
|
||||
static void touch_handle_frame(void *data, struct wl_touch *wl_touch) {
|
||||
// no-op
|
||||
struct wlr_wl_input_device *device = data;
|
||||
assert(device && device->wlr_input_device.touch);
|
||||
|
||||
wlr_signal_emit_safe(&device->wlr_input_device.touch->events.frame, NULL);
|
||||
}
|
||||
|
||||
static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) {
|
||||
|
@ -437,7 +441,7 @@ static void input_device_destroy(struct wlr_input_device *wlr_dev) {
|
|||
}
|
||||
// We can't destroy pointer here because we might have multiple devices
|
||||
// exposing it to compositor.
|
||||
wl_list_remove(&dev->wlr_input_device.link);
|
||||
wl_list_remove(&dev->link);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
@ -464,13 +468,36 @@ struct wlr_wl_input_device *create_wl_input_device(
|
|||
|
||||
unsigned int vendor = 0, product = 0;
|
||||
|
||||
size_t name_size = 8 + strlen(seat->name) + 1;
|
||||
const char *type_name = "unknown";
|
||||
|
||||
switch (type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
type_name = "keyboard";
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
type_name = "pointer";
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
type_name = "touch";
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
||||
type_name = "tablet-tool";
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||
type_name = "tablet-pad";
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_SWITCH:
|
||||
type_name = "switch";
|
||||
break;
|
||||
}
|
||||
|
||||
size_t name_size = 8 + strlen(type_name) + strlen(seat->name) + 1;
|
||||
char name[name_size];
|
||||
(void) snprintf(name, name_size, "wayland-%s", seat->name);
|
||||
(void) snprintf(name, name_size, "wayland-%s-%s", type_name, seat->name);
|
||||
|
||||
wlr_input_device_init(wlr_dev, type, &input_device_impl, name, vendor,
|
||||
product);
|
||||
wl_list_insert(&seat->backend->devices, &wlr_dev->link);
|
||||
wl_list_insert(&seat->backend->devices, &dev->link);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
@ -493,6 +520,21 @@ static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
|
|||
seat->active_pointer = NULL;
|
||||
}
|
||||
|
||||
// pointer->wl_pointer belongs to the wlr_wl_seat
|
||||
|
||||
if (pointer->gesture_swipe != NULL) {
|
||||
zwp_pointer_gesture_swipe_v1_destroy(pointer->gesture_swipe);
|
||||
}
|
||||
if (pointer->gesture_pinch != NULL) {
|
||||
zwp_pointer_gesture_pinch_v1_destroy(pointer->gesture_pinch);
|
||||
}
|
||||
if (pointer->gesture_hold != NULL) {
|
||||
zwp_pointer_gesture_hold_v1_destroy(pointer->gesture_hold);
|
||||
}
|
||||
if (pointer->relative_pointer != NULL) {
|
||||
zwp_relative_pointer_v1_destroy(pointer->relative_pointer);
|
||||
}
|
||||
|
||||
wl_list_remove(&pointer->output_destroy.link);
|
||||
free(pointer);
|
||||
}
|
||||
|
@ -601,6 +643,38 @@ static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_impl = {
|
|||
.end = gesture_pinch_end,
|
||||
};
|
||||
|
||||
static void gesture_hold_begin(void *data,
|
||||
struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1,
|
||||
uint32_t serial, uint32_t time,
|
||||
struct wl_surface *surface, uint32_t fingers) {
|
||||
struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data;
|
||||
struct wlr_input_device *wlr_dev = &input_device->wlr_input_device;
|
||||
struct wlr_event_pointer_hold_begin wlr_event = {
|
||||
.device = wlr_dev,
|
||||
.time_msec = time,
|
||||
.fingers = fingers,
|
||||
};
|
||||
input_device->fingers = fingers;
|
||||
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_begin, &wlr_event);
|
||||
}
|
||||
|
||||
static void gesture_hold_end(void *data,
|
||||
struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1,
|
||||
uint32_t serial, uint32_t time, int32_t cancelled) {
|
||||
struct wlr_wl_input_device *input_device = (struct wlr_wl_input_device *)data;
|
||||
struct wlr_input_device *wlr_dev = &input_device->wlr_input_device;
|
||||
struct wlr_event_pointer_hold_end wlr_event = {
|
||||
.device = wlr_dev,
|
||||
.time_msec = time,
|
||||
.cancelled = cancelled,
|
||||
};
|
||||
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_end, &wlr_event);
|
||||
}
|
||||
|
||||
static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_impl = {
|
||||
.begin = gesture_hold_begin,
|
||||
.end = gesture_hold_end,
|
||||
};
|
||||
|
||||
static void relative_pointer_handle_relative_motion(void *data,
|
||||
struct zwp_relative_pointer_v1 *relative_pointer, uint32_t utime_hi,
|
||||
|
@ -634,9 +708,6 @@ static void pointer_handle_output_destroy(struct wl_listener *listener,
|
|||
void *data) {
|
||||
struct wlr_wl_pointer *pointer =
|
||||
wl_container_of(listener, pointer, output_destroy);
|
||||
if (pointer->relative_pointer) {
|
||||
zwp_relative_pointer_v1_destroy(pointer->relative_pointer);
|
||||
}
|
||||
wlr_input_device_destroy(&pointer->input_device->wlr_input_device);
|
||||
}
|
||||
|
||||
|
@ -678,12 +749,21 @@ void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) {
|
|||
wlr_pointer_init(wlr_dev->pointer, &pointer_impl);
|
||||
|
||||
if (backend->zwp_pointer_gestures_v1) {
|
||||
uint32_t version = zwp_pointer_gestures_v1_get_version(
|
||||
backend->zwp_pointer_gestures_v1);
|
||||
|
||||
pointer->gesture_swipe = zwp_pointer_gestures_v1_get_swipe_gesture(
|
||||
backend->zwp_pointer_gestures_v1, wl_pointer);
|
||||
zwp_pointer_gesture_swipe_v1_add_listener(pointer->gesture_swipe, &gesture_swipe_impl, dev);
|
||||
pointer->gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(
|
||||
backend->zwp_pointer_gestures_v1, wl_pointer);
|
||||
zwp_pointer_gesture_pinch_v1_add_listener(pointer->gesture_pinch, &gesture_pinch_impl, dev);
|
||||
|
||||
if (version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE) {
|
||||
pointer->gesture_hold = zwp_pointer_gestures_v1_get_hold_gesture(
|
||||
backend->zwp_pointer_gestures_v1, wl_pointer);
|
||||
zwp_pointer_gesture_hold_v1_add_listener(pointer->gesture_hold, &gesture_hold_impl, dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (backend->zwp_relative_pointer_manager_v1) {
|
||||
|
@ -766,19 +846,20 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
|
||||
struct wl_pointer *wl_pointer = seat->pointer;
|
||||
|
||||
struct wlr_input_device *device, *tmp;
|
||||
struct wlr_wl_input_device *device, *tmp;
|
||||
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||
if (device->type != WLR_INPUT_DEVICE_POINTER) {
|
||||
if (device->wlr_input_device.type != WLR_INPUT_DEVICE_POINTER) {
|
||||
continue;
|
||||
}
|
||||
struct wlr_wl_pointer *pointer = pointer_get_wl(device->pointer);
|
||||
struct wlr_wl_pointer *pointer =
|
||||
pointer_get_wl(device->wlr_input_device.pointer);
|
||||
if (pointer->wl_pointer != wl_pointer) {
|
||||
continue;
|
||||
}
|
||||
wlr_log(WLR_DEBUG, "dropping pointer %s",
|
||||
pointer->input_device->wlr_input_device.name);
|
||||
struct wlr_wl_output *output = pointer->output;
|
||||
wlr_input_device_destroy(device);
|
||||
wlr_input_device_destroy(&device->wlr_input_device);
|
||||
assert(seat->active_pointer != pointer);
|
||||
assert(output->cursor.pointer != pointer);
|
||||
}
|
||||
|
@ -800,18 +881,16 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) {
|
||||
wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat);
|
||||
|
||||
struct wlr_input_device *device, *tmp;
|
||||
struct wlr_wl_input_device *device, *tmp;
|
||||
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||
if (device->type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||
if (device->wlr_input_device.type != WLR_INPUT_DEVICE_KEYBOARD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct wlr_wl_input_device *input_device =
|
||||
get_wl_input_device_from_input_device(device);
|
||||
if (input_device->seat != seat) {
|
||||
if (device->seat != seat) {
|
||||
continue;
|
||||
}
|
||||
wlr_input_device_destroy(device);
|
||||
wlr_input_device_destroy(&device->wlr_input_device);
|
||||
}
|
||||
assert(seat->keyboard == NULL); // free'ed by input_device_destroy
|
||||
}
|
||||
|
@ -827,10 +906,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) {
|
||||
wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat);
|
||||
|
||||
struct wlr_input_device *device, *tmp;
|
||||
struct wlr_wl_input_device *device, *tmp;
|
||||
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
|
||||
if (device->type == WLR_INPUT_DEVICE_TOUCH) {
|
||||
wlr_input_device_destroy(device);
|
||||
if (device->wlr_input_device.type == WLR_INPUT_DEVICE_TOUCH) {
|
||||
wlr_input_device_destroy(&device->wlr_input_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -336,7 +336,8 @@ static void handle_tablet_pad_path(void *data,
|
|||
struct wlr_wl_input_device *dev = data;
|
||||
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
|
||||
|
||||
wlr_list_push(&tablet_pad->paths, strdup(path));
|
||||
char **dst = wl_array_add(&tablet_pad->paths, sizeof(char *));
|
||||
*dst = strdup(path);
|
||||
}
|
||||
|
||||
static void handle_tablet_pad_buttons(void *data,
|
||||
|
@ -401,7 +402,7 @@ static void handle_tablet_pad_removed(void *data,
|
|||
/* This doesn't free anything, but emits the destroy signal */
|
||||
wlr_input_device_destroy(&dev->wlr_input_device);
|
||||
/* This is a bit ugly, but we need to remove it from our list */
|
||||
wl_list_remove(&dev->wlr_input_device.link);
|
||||
wl_list_remove(&dev->link);
|
||||
|
||||
struct wlr_wl_tablet_pad_group *group, *it;
|
||||
wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) {
|
||||
|
@ -854,7 +855,8 @@ static void handle_tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
|
|||
struct wlr_wl_input_device *dev = data;
|
||||
struct wlr_tablet *tablet = dev->wlr_input_device.tablet;
|
||||
|
||||
wlr_list_push(&tablet->paths, strdup(path));
|
||||
char **dst = wl_array_add(&tablet->paths, sizeof(char *));
|
||||
*dst = strdup(path);
|
||||
}
|
||||
|
||||
static void handle_tablet_done(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) {
|
||||
|
@ -871,7 +873,7 @@ static void handle_tablet_removed(void *data,
|
|||
/* This doesn't free anything, but emits the destroy signal */
|
||||
wlr_input_device_destroy(&dev->wlr_input_device);
|
||||
/* This is a bit ugly, but we need to remove it from our list */
|
||||
wl_list_remove(&dev->wlr_input_device.link);
|
||||
wl_list_remove(&dev->link);
|
||||
|
||||
zwp_tablet_v2_destroy(dev->resource);
|
||||
free(dev);
|
||||
|
|
|
@ -29,11 +29,8 @@
|
|||
#include <wlr/interfaces/wlr_pointer.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "backend/backend.h"
|
||||
#include "backend/x11.h"
|
||||
#include "render/allocator.h"
|
||||
#include "render/drm_format_set.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
|
||||
// See dri2_format_for_depth in mesa
|
||||
|
@ -166,6 +163,8 @@ static bool backend_start(struct wlr_backend *backend) {
|
|||
struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend);
|
||||
x11->started = true;
|
||||
|
||||
wlr_log(WLR_INFO, "Starting X11 backend");
|
||||
|
||||
wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard_dev);
|
||||
|
||||
for (size_t i = 0; i < x11->requested_outputs; ++i) {
|
||||
|
@ -355,6 +354,7 @@ static bool query_formats(struct wlr_x11_backend *x11) {
|
|||
}
|
||||
|
||||
if (x11->have_dri3) {
|
||||
// X11 always supports implicit modifiers
|
||||
wlr_drm_format_set_add(&x11->dri3_formats, format->drm,
|
||||
DRM_FORMAT_MOD_INVALID);
|
||||
if (!query_dri3_modifiers(x11, format)) {
|
||||
|
@ -573,9 +573,9 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
|||
goto error_event;
|
||||
}
|
||||
|
||||
x11->depth = get_depth(x11->screen, 32);
|
||||
x11->depth = get_depth(x11->screen, 24);
|
||||
if (!x11->depth) {
|
||||
wlr_log(WLR_ERROR, "Failed to get 32-bit depth for X11 screen");
|
||||
wlr_log(WLR_ERROR, "Failed to get 24-bit depth for X11 screen");
|
||||
goto error_event;
|
||||
}
|
||||
|
||||
|
@ -611,12 +611,6 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
|
|||
}
|
||||
}
|
||||
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(&x11->backend);
|
||||
struct wlr_allocator *allocator = backend_get_allocator(&x11->backend);
|
||||
if (renderer == NULL || allocator == NULL) {
|
||||
goto error_event;
|
||||
}
|
||||
|
||||
// Windows can only display buffers with the depth they were created with
|
||||
// TODO: look into changing the window's depth at runtime
|
||||
const struct wlr_drm_format *dri3_format =
|
||||
|
|
|
@ -79,6 +79,7 @@ static void send_touch_down_event(struct wlr_x11_output *output,
|
|||
.touch_id = touch_id,
|
||||
};
|
||||
wlr_signal_emit_safe(&output->touch.events.down, &ev);
|
||||
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
|
||||
}
|
||||
|
||||
static void send_touch_motion_event(struct wlr_x11_output *output,
|
||||
|
@ -91,6 +92,7 @@ static void send_touch_motion_event(struct wlr_x11_output *output,
|
|||
.touch_id = touch_id,
|
||||
};
|
||||
wlr_signal_emit_safe(&output->touch.events.motion, &ev);
|
||||
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
|
||||
}
|
||||
|
||||
static void send_touch_up_event(struct wlr_x11_output *output,
|
||||
|
@ -101,10 +103,11 @@ static void send_touch_up_event(struct wlr_x11_output *output,
|
|||
.touch_id = touch_id,
|
||||
};
|
||||
wlr_signal_emit_safe(&output->touch.events.up, &ev);
|
||||
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
|
||||
}
|
||||
|
||||
static struct wlr_x11_touchpoint* get_touchpoint_from_x11_touch_id(struct wlr_x11_output *output,
|
||||
uint32_t id) {
|
||||
static struct wlr_x11_touchpoint *get_touchpoint_from_x11_touch_id(
|
||||
struct wlr_x11_output *output, uint32_t id) {
|
||||
struct wlr_x11_touchpoint *touchpoint;
|
||||
wl_list_for_each(touchpoint, &output->touchpoints, link) {
|
||||
if (touchpoint->x11_id == id) {
|
||||
|
|
|
@ -10,17 +10,14 @@ x11_required = [
|
|||
'xcb-xinput',
|
||||
]
|
||||
|
||||
msg = []
|
||||
if get_option('x11-backend').enabled()
|
||||
msg += 'Install "@0@" or pass "-Dx11-backend=disabled" to disable it.'
|
||||
endif
|
||||
if not get_option('x11-backend').disabled()
|
||||
msg += 'Required for X11 backend support.'
|
||||
msg = ['Required for X11 backend support.']
|
||||
if 'x11' in backends
|
||||
msg += 'Install "@0@" or disable the X11 backend.'
|
||||
endif
|
||||
|
||||
foreach lib : x11_required
|
||||
dep = dependency(lib,
|
||||
required: get_option('x11-backend'),
|
||||
required: 'x11' in backends,
|
||||
not_found_message: '\n'.join(msg).format(lib),
|
||||
)
|
||||
if not dep.found()
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <wlr/util/log.h>
|
||||
|
||||
#include "backend/x11.h"
|
||||
#include "types/wlr_buffer.h"
|
||||
#include "util/signal.h"
|
||||
#include "util/time.h"
|
||||
|
||||
|
@ -141,10 +140,6 @@ static xcb_pixmap_t import_dmabuf(struct wlr_x11_output *output,
|
|||
return XCB_PIXMAP_NONE;
|
||||
}
|
||||
|
||||
if (dmabuf->flags != 0) {
|
||||
return XCB_PIXMAP_NONE;
|
||||
}
|
||||
|
||||
// xcb closes the FDs after sending them, so we need to dup them here
|
||||
struct wlr_dmabuf_attributes dup_attrs = {0};
|
||||
if (!wlr_dmabuf_attributes_copy(&dup_attrs, dmabuf)) {
|
||||
|
@ -258,9 +253,6 @@ static struct wlr_x11_buffer *get_or_create_x11_buffer(
|
|||
static bool output_commit_buffer(struct wlr_x11_output *output) {
|
||||
struct wlr_x11_backend *x11 = output->x11;
|
||||
|
||||
assert(output->wlr_output.pending.buffer_type ==
|
||||
WLR_OUTPUT_STATE_BUFFER_SCANOUT);
|
||||
|
||||
struct wlr_buffer *buffer = output->wlr_output.pending.buffer;
|
||||
struct wlr_x11_buffer *x11_buffer =
|
||||
get_or_create_x11_buffer(output, buffer);
|
||||
|
@ -384,7 +376,7 @@ static void update_x11_output_cursor(struct wlr_x11_output *output,
|
|||
static bool output_cursor_to_picture(struct wlr_x11_output *output,
|
||||
struct wlr_buffer *buffer) {
|
||||
struct wlr_x11_backend *x11 = output->x11;
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(&x11->backend);
|
||||
struct wlr_renderer *renderer = output->wlr_output.renderer;
|
||||
|
||||
if (output->cursor.pic != XCB_NONE) {
|
||||
xcb_render_free_picture(x11->xcb, output->cursor.pic);
|
||||
|
@ -520,13 +512,15 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
|
|||
|
||||
wlr_output_update_custom_mode(wlr_output, 1024, 768, 0);
|
||||
|
||||
snprintf(wlr_output->name, sizeof(wlr_output->name), "X11-%zd",
|
||||
++x11->last_output_num);
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "X11-%zu", ++x11->last_output_num);
|
||||
wlr_output_set_name(wlr_output, name);
|
||||
|
||||
parse_xcb_setup(wlr_output, x11->xcb);
|
||||
|
||||
char description[128];
|
||||
snprintf(description, sizeof(description),
|
||||
"X11 output %zd", x11->last_output_num);
|
||||
"X11 output %zu", x11->last_output_num);
|
||||
wlr_output_set_description(wlr_output, description);
|
||||
|
||||
// The X11 protocol requires us to set a colormap and border pixel if the
|
||||
|
@ -694,9 +688,11 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
|
|||
flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
|
||||
}
|
||||
|
||||
bool presented = complete_notify->mode != XCB_PRESENT_COMPLETE_MODE_SKIP;
|
||||
struct wlr_output_event_present present_event = {
|
||||
.output = &output->wlr_output,
|
||||
.commit_seq = complete_notify->serial,
|
||||
.presented = presented,
|
||||
.when = &t,
|
||||
.seq = complete_notify->msc,
|
||||
.flags = flags,
|
||||
|
|
|
@ -3,14 +3,15 @@ wlroots reads these environment variables
|
|||
# wlroots specific
|
||||
|
||||
* *WLR_BACKENDS*: comma-separated list of backends to use (available backends:
|
||||
libinput, drm, wayland, x11, headless, noop)
|
||||
libinput, drm, wayland, x11, headless)
|
||||
* *WLR_NO_HARDWARE_CURSORS*: set to 1 to use software cursors instead of
|
||||
hardware cursors
|
||||
* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty)
|
||||
* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead
|
||||
of following shell search semantics for "Xwayland")
|
||||
* *WLR_RENDERER*: forces the creation of a specified renderer (available
|
||||
renderers: gles2, pixman)
|
||||
renderers: gles2, pixman, vulkan)
|
||||
* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
|
||||
hardware-accelerated renderers.
|
||||
|
||||
## DRM backend
|
||||
|
||||
|
|
|
@ -128,6 +128,11 @@ static void print_toplevel_state(struct toplevel_v1 *toplevel, bool print_endl)
|
|||
}
|
||||
}
|
||||
|
||||
static void finish_toplevel_state(struct toplevel_state *state) {
|
||||
free(state->title);
|
||||
free(state->app_id);
|
||||
}
|
||||
|
||||
static void toplevel_handle_title(void *data,
|
||||
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel,
|
||||
const char *title) {
|
||||
|
@ -228,6 +233,9 @@ static void toplevel_handle_closed(void *data,
|
|||
printf(" closed\n");
|
||||
|
||||
zwlr_foreign_toplevel_handle_v1_destroy(zwlr_toplevel);
|
||||
finish_toplevel_state(&toplevel->current);
|
||||
finish_toplevel_state(&toplevel->pending);
|
||||
free(toplevel);
|
||||
}
|
||||
|
||||
static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#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>
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
/**
|
||||
|
@ -24,6 +26,7 @@ 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;
|
||||
|
@ -46,7 +49,6 @@ struct fullscreen_output {
|
|||
struct render_data {
|
||||
struct wlr_output *output;
|
||||
struct wlr_renderer *renderer;
|
||||
struct tinywl_view *view;
|
||||
struct timespec *when;
|
||||
};
|
||||
|
||||
|
@ -146,6 +148,8 @@ static void server_handle_new_output(struct wl_listener *listener, void *data) {
|
|||
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(struct fullscreen_output));
|
||||
output->wlr_output = wlr_output;
|
||||
|
@ -203,8 +207,10 @@ int main(int argc, char *argv[]) {
|
|||
struct fullscreen_server server = {0};
|
||||
server.wl_display = wl_display_create();
|
||||
server.backend = wlr_backend_autocreate(server.wl_display);
|
||||
server.renderer = wlr_backend_get_renderer(server.backend);
|
||||
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, server.renderer);
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <wayland-client.h>
|
||||
#include <wayland-cursor.h>
|
||||
#include <wayland-egl.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "egl_common.h"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
@ -177,8 +176,7 @@ static const struct xdg_surface_listener xdg_surface_listener = {
|
|||
|
||||
static void xdg_popup_configure(void *data, struct xdg_popup *xdg_popup,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height) {
|
||||
wlr_log(WLR_DEBUG, "Popup configured %dx%d@%d,%d",
|
||||
width, height, x, y);
|
||||
fprintf(stderr, "Popup configured %dx%d@%d,%d\n", width, height, x, y);
|
||||
popup_width = width;
|
||||
popup_height = height;
|
||||
if (popup_egl_window) {
|
||||
|
@ -197,7 +195,7 @@ static void popup_destroy(void) {
|
|||
}
|
||||
|
||||
static void xdg_popup_done(void *data, struct xdg_popup *xdg_popup) {
|
||||
wlr_log(WLR_DEBUG, "Popup done");
|
||||
fprintf(stderr, "Popup done\n");
|
||||
popup_destroy();
|
||||
}
|
||||
|
||||
|
@ -377,17 +375,17 @@ static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|||
|
||||
static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
|
||||
wlr_log(WLR_DEBUG, "Keyboard enter");
|
||||
fprintf(stderr, "Keyboard enter\n");
|
||||
}
|
||||
|
||||
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface) {
|
||||
wlr_log(WLR_DEBUG, "Keyboard leave");
|
||||
fprintf(stderr, "Keyboard leave\n");
|
||||
}
|
||||
|
||||
static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
|
||||
wlr_log(WLR_DEBUG, "Key event: %d %d", key, state);
|
||||
fprintf(stderr, "Key event: %d %d\n", key, state);
|
||||
}
|
||||
|
||||
static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
|
||||
|
@ -473,7 +471,6 @@ static const struct wl_registry_listener registry_listener = {
|
|||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
wlr_log_init(WLR_DEBUG, NULL);
|
||||
char *namespace = "wlroots";
|
||||
int exclusive_zone = 0;
|
||||
int32_t margin_right = 0, margin_bottom = 0, margin_left = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
threads = dependency('threads')
|
||||
wayland_egl = dependency('wayland-egl')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
wayland_client = dependency('wayland-client')
|
||||
libpng = dependency('libpng', required: false, disabler: true)
|
||||
egl = dependency('egl', required: false, disabler: true)
|
||||
glesv2 = dependency('glesv2', required: false, disabler: true)
|
||||
|
@ -51,6 +52,10 @@ compositors = {
|
|||
'quads': {
|
||||
'src': 'quads.c',
|
||||
},
|
||||
'scene-graph': {
|
||||
'src': 'scene-graph.c',
|
||||
'proto': ['xdg-shell'],
|
||||
},
|
||||
}
|
||||
|
||||
clients = {
|
||||
|
@ -77,7 +82,7 @@ clients = {
|
|||
},
|
||||
'layer-shell': {
|
||||
'src': ['layer-shell.c', 'egl_common.c'],
|
||||
'dep': [wayland_egl, wayland_cursor, wlroots, egl, glesv2],
|
||||
'dep': [wayland_egl, wayland_cursor, egl, glesv2],
|
||||
'proto': [
|
||||
'wlr-layer-shell-unstable-v1',
|
||||
'xdg-shell',
|
||||
|
@ -98,7 +103,7 @@ clients = {
|
|||
},
|
||||
'output-power-management': {
|
||||
'src': 'output-power-management.c',
|
||||
'dep': [wayland_client, wlroots],
|
||||
'dep': [wayland_client],
|
||||
'proto': ['wlr-output-power-management-unstable-v1'],
|
||||
},
|
||||
'pointer-constraints': {
|
||||
|
@ -124,7 +129,7 @@ clients = {
|
|||
libavcodec,
|
||||
libavformat,
|
||||
libavutil,
|
||||
drm.partial_dependency(compile_args: true), # <drm_fourcc.h>
|
||||
drm,
|
||||
threads,
|
||||
],
|
||||
'proto': ['wlr-export-dmabuf-unstable-v1'],
|
||||
|
@ -169,12 +174,10 @@ clients = {
|
|||
},
|
||||
'foreign-toplevel': {
|
||||
'src': 'foreign-toplevel.c',
|
||||
'dep': [wlroots],
|
||||
'proto': ['wlr-foreign-toplevel-management-unstable-v1'],
|
||||
},
|
||||
'virtual-pointer': {
|
||||
'src': 'virtual-pointer.c',
|
||||
'dep': wlroots,
|
||||
'proto': ['wlr-virtual-pointer-unstable-v1'],
|
||||
},
|
||||
'input-method-keyboard-grab': {
|
||||
|
@ -211,7 +214,7 @@ foreach name, info : clients
|
|||
executable(
|
||||
name,
|
||||
[info.get('src'), extra_src],
|
||||
dependencies: [wayland_client, info.get('dep')],
|
||||
dependencies: [wayland_client, info.get('dep', [])],
|
||||
build_by_default: get_option('examples'),
|
||||
)
|
||||
endforeach
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
|
@ -23,6 +23,8 @@
|
|||
struct sample_state {
|
||||
struct wl_display *display;
|
||||
struct wlr_xcursor *xcursor;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
float default_color[4];
|
||||
float clear_color[4];
|
||||
struct wlr_output_layout *layout;
|
||||
|
@ -91,7 +93,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
struct sample_output *output = wl_container_of(listener, output, frame);
|
||||
struct sample_state *sample = output->sample;
|
||||
struct wlr_output *wlr_output = output->output;
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = sample->renderer;
|
||||
|
||||
wlr_output_attach_render(wlr_output, NULL);
|
||||
|
||||
|
@ -145,6 +147,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
sample_output->output = output;
|
||||
sample_output->sample = sample;
|
||||
|
@ -270,6 +275,10 @@ int main(int argc, char *argv[]) {
|
|||
if (!wlr) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
wl_list_init(&state.cursors);
|
||||
wl_list_init(&state.pointers);
|
||||
wl_list_init(&state.outputs);
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_input_device.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 <xkbcommon/xkbcommon.h>
|
||||
#include "cat.h"
|
||||
|
@ -26,6 +28,7 @@ struct sample_state {
|
|||
struct wl_listener new_output;
|
||||
struct wl_listener new_input;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_texture *cat_texture;
|
||||
struct wlr_output_layout *layout;
|
||||
float x_offs, y_offs;
|
||||
|
@ -157,6 +160,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
wlr_output_layout_add_auto(sample->layout, output);
|
||||
sample_output->output = output;
|
||||
|
@ -272,11 +278,13 @@ int main(int argc, char *argv[]) {
|
|||
wl_signal_add(&wlr->events.new_input, &state.new_input);
|
||||
state.new_input.notify = new_input_notify;
|
||||
|
||||
state.renderer = wlr_backend_get_renderer(wlr);
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
state.cat_texture = wlr_texture_from_pixels(state.renderer,
|
||||
DRM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
|
||||
cat_tex.pixel_data);
|
||||
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
if (!wlr_backend_start(wlr)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
|
@ -25,6 +25,8 @@
|
|||
struct sample_state {
|
||||
struct wl_display *display;
|
||||
struct compositor_state *compositor;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_xcursor_manager *xcursor_manager;
|
||||
struct wlr_cursor *cursor;
|
||||
double cur_x, cur_y;
|
||||
|
@ -96,7 +98,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
struct sample_output *sample_output = wl_container_of(listener, sample_output, frame);
|
||||
struct sample_state *state = sample_output->state;
|
||||
struct wlr_output *wlr_output = sample_output->output;
|
||||
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = state->renderer;
|
||||
assert(renderer);
|
||||
|
||||
wlr_output_attach_render(wlr_output, NULL);
|
||||
|
@ -251,6 +253,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
sample_output->output = output;
|
||||
sample_output->state = sample;
|
||||
|
@ -332,6 +337,10 @@ int main(int argc, char *argv[]) {
|
|||
if (!wlr) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
state.cursor = wlr_cursor_create();
|
||||
state.layout = wlr_output_layout_create();
|
||||
wlr_cursor_attach_output_layout(state.cursor, state.layout);
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
#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_keyboard.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
|
@ -23,6 +25,7 @@ struct sample_state {
|
|||
struct wl_listener new_input;
|
||||
struct timespec last_frame;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wl_list outputs;
|
||||
};
|
||||
|
||||
|
@ -102,6 +105,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
|
||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(output);
|
||||
|
@ -194,13 +200,15 @@ int main(int argc, char *argv[]) {
|
|||
state.new_input.notify = new_input_notify;
|
||||
clock_gettime(CLOCK_MONOTONIC, &state.last_frame);
|
||||
|
||||
state.renderer = wlr_backend_get_renderer(wlr);
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
if (!state.renderer) {
|
||||
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
|
||||
wlr_backend_destroy(wlr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
if (!wlr_backend_start(wlr)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#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_keyboard.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
@ -25,6 +26,7 @@ struct sample_state {
|
|||
struct wl_listener new_input;
|
||||
struct timespec last_frame;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_texture *cat_texture;
|
||||
struct wl_list outputs;
|
||||
enum wl_output_transform transform;
|
||||
|
@ -105,6 +107,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
sample_output->x_offs = sample_output->y_offs = 0;
|
||||
sample_output->x_vel = sample_output->y_vel = 128;
|
||||
|
@ -245,7 +250,7 @@ int main(int argc, char *argv[]) {
|
|||
state.new_input.notify = new_input_notify;
|
||||
clock_gettime(CLOCK_MONOTONIC, &state.last_frame);
|
||||
|
||||
state.renderer = wlr_backend_get_renderer(wlr);
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
if (!state.renderer) {
|
||||
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
@ -259,6 +264,8 @@ int main(int argc, char *argv[]) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
if (!wlr_backend_start(wlr)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <assert.h>
|
||||
#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_output.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_surface.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
/* Simple compositor making use of the scene-graph API. Input is unimplemented.
|
||||
*
|
||||
* New surfaces are stacked on top of the existing ones as they appear. */
|
||||
|
||||
static const int border_width = 3;
|
||||
|
||||
struct server {
|
||||
struct wl_display *display;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_scene *scene;
|
||||
|
||||
struct wl_list outputs;
|
||||
struct wl_list surfaces;
|
||||
|
||||
struct wl_listener new_output;
|
||||
struct wl_listener new_surface;
|
||||
};
|
||||
|
||||
struct surface {
|
||||
struct wlr_surface *wlr;
|
||||
struct wlr_scene_surface *scene_surface;
|
||||
struct wlr_scene_rect *border;
|
||||
struct wl_list link;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct output {
|
||||
struct wl_list link;
|
||||
struct server *server;
|
||||
struct wlr_output *wlr;
|
||||
struct wlr_scene_output *scene_output;
|
||||
|
||||
struct wl_listener frame;
|
||||
};
|
||||
|
||||
static void output_handle_frame(struct wl_listener *listener, void *data) {
|
||||
struct output *output = wl_container_of(listener, output, frame);
|
||||
|
||||
if (!wlr_scene_output_commit(output->scene_output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
struct surface *surface;
|
||||
wl_list_for_each(surface, &output->server->surfaces, link) {
|
||||
wlr_surface_send_frame_done(surface->wlr, &now);
|
||||
}
|
||||
}
|
||||
|
||||
static void server_handle_new_output(struct wl_listener *listener, void *data) {
|
||||
struct 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 output *output =
|
||||
calloc(1, sizeof(struct output));
|
||||
output->wlr = 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);
|
||||
|
||||
output->scene_output = wlr_scene_output_create(server->scene, wlr_output);
|
||||
|
||||
if (!wl_list_empty(&wlr_output->modes)) {
|
||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
||||
wlr_output_set_mode(wlr_output, mode);
|
||||
wlr_output_commit(wlr_output);
|
||||
}
|
||||
|
||||
wlr_output_create_global(wlr_output);
|
||||
}
|
||||
|
||||
static void surface_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct surface *surface = wl_container_of(listener, surface, commit);
|
||||
wlr_scene_rect_set_size(surface->border,
|
||||
surface->wlr->current.width + 2 * border_width,
|
||||
surface->wlr->current.height + 2 * border_width);
|
||||
}
|
||||
|
||||
static void surface_handle_destroy(struct wl_listener *listener, void *data) {
|
||||
struct surface *surface = wl_container_of(listener, surface, destroy);
|
||||
wlr_scene_node_destroy(&surface->scene_surface->node);
|
||||
wlr_scene_node_destroy(&surface->border->node);
|
||||
wl_list_remove(&surface->destroy.link);
|
||||
wl_list_remove(&surface->link);
|
||||
free(surface);
|
||||
}
|
||||
|
||||
static void server_handle_new_surface(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct server *server = wl_container_of(listener, server, new_surface);
|
||||
struct wlr_surface *wlr_surface = data;
|
||||
|
||||
int pos = 50 * wl_list_length(&server->surfaces);
|
||||
|
||||
struct surface *surface = calloc(1, sizeof(struct surface));
|
||||
surface->wlr = wlr_surface;
|
||||
surface->commit.notify = surface_handle_commit;
|
||||
wl_signal_add(&wlr_surface->events.commit, &surface->commit);
|
||||
surface->destroy.notify = surface_handle_destroy;
|
||||
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
|
||||
|
||||
/* Border dimensions will be set in surface.commit handler */
|
||||
surface->border = wlr_scene_rect_create(&server->scene->node,
|
||||
0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 });
|
||||
wlr_scene_node_set_position(&surface->border->node, pos, pos);
|
||||
|
||||
surface->scene_surface =
|
||||
wlr_scene_surface_create(&server->scene->node, wlr_surface);
|
||||
wl_list_insert(server->surfaces.prev, &surface->link);
|
||||
|
||||
wlr_scene_node_set_position(&surface->scene_surface->node,
|
||||
pos + border_width, pos + border_width);
|
||||
}
|
||||
|
||||
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 server server = {0};
|
||||
server.display = wl_display_create();
|
||||
server.backend = wlr_backend_autocreate(server.display);
|
||||
server.scene = wlr_scene_create();
|
||||
|
||||
server.renderer = wlr_renderer_autocreate(server.backend);
|
||||
wlr_renderer_init_wl_display(server.renderer, server.display);
|
||||
|
||||
server.allocator = wlr_allocator_autocreate(server.backend,
|
||||
server.renderer);
|
||||
|
||||
struct wlr_compositor *compositor =
|
||||
wlr_compositor_create(server.display, server.renderer);
|
||||
|
||||
wlr_xdg_shell_create(server.display);
|
||||
|
||||
wl_list_init(&server.outputs);
|
||||
wl_list_init(&server.surfaces);
|
||||
|
||||
server.new_output.notify = server_handle_new_output;
|
||||
wl_signal_add(&server.backend->events.new_output, &server.new_output);
|
||||
|
||||
server.new_surface.notify = server_handle_new_surface;
|
||||
wl_signal_add(&compositor->events.new_surface, &server.new_surface);
|
||||
|
||||
const char *socket = wl_display_add_socket_auto(server.display);
|
||||
if (!socket) {
|
||||
wl_display_destroy(server.display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!wlr_backend_start(server.backend)) {
|
||||
wl_display_destroy(server.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.display);
|
||||
|
||||
wl_display_destroy_clients(server.display);
|
||||
wl_display_destroy(server.display);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
|
@ -18,6 +19,8 @@ struct sample_state {
|
|||
struct wl_display *display;
|
||||
struct wl_listener new_output;
|
||||
struct wl_listener new_input;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct timespec last_frame;
|
||||
float color[4];
|
||||
int dec;
|
||||
|
@ -61,8 +64,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
|
|||
|
||||
wlr_output_attach_render(wlr_output, NULL);
|
||||
|
||||
struct wlr_renderer *renderer =
|
||||
wlr_backend_get_renderer(wlr_output->backend);
|
||||
struct wlr_renderer *renderer = sample->renderer;
|
||||
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
|
||||
wlr_renderer_clear(renderer, sample->color);
|
||||
wlr_renderer_end(renderer);
|
||||
|
@ -84,6 +86,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
|
|||
struct wlr_output *output = data;
|
||||
struct sample_state *sample =
|
||||
wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output =
|
||||
calloc(1, sizeof(struct sample_output));
|
||||
sample_output->output = output;
|
||||
|
@ -171,6 +176,10 @@ int main(void) {
|
|||
if (!backend) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
state.renderer = wlr_renderer_autocreate(backend);
|
||||
state.allocator = wlr_allocator_autocreate(backend, state.renderer);
|
||||
|
||||
wl_signal_add(&backend->events.new_output, &state.new_output);
|
||||
state.new_output.notify = new_output_notify;
|
||||
wl_signal_add(&backend->events.new_input, &state.new_input);
|
||||
|
|
|
@ -8,20 +8,22 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_tablet_pad.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
struct sample_state {
|
||||
struct wl_display *display;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
bool proximity, tap, button;
|
||||
double distance;
|
||||
double pressure;
|
||||
|
@ -237,6 +239,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
sample_output->output = output;
|
||||
sample_output->sample = sample;
|
||||
|
@ -361,11 +366,14 @@ int main(int argc, char *argv[]) {
|
|||
state.new_input.notify = new_input_notify;
|
||||
clock_gettime(CLOCK_MONOTONIC, &state.last_frame);
|
||||
|
||||
state.renderer = wlr_backend_get_renderer(wlr);
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
if (!state.renderer) {
|
||||
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
if (!wlr_backend_start(wlr)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
|
@ -24,6 +24,7 @@
|
|||
struct sample_state {
|
||||
struct wl_display *display;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
struct wlr_texture *cat_texture;
|
||||
struct wl_list touch_points;
|
||||
struct timespec last_frame;
|
||||
|
@ -149,6 +150,9 @@ static void output_remove_notify(struct wl_listener *listener, void *data) {
|
|||
static void new_output_notify(struct wl_listener *listener, void *data) {
|
||||
struct wlr_output *output = data;
|
||||
struct sample_state *sample = wl_container_of(listener, sample, new_output);
|
||||
|
||||
wlr_output_init_render(output, sample->allocator, sample->renderer);
|
||||
|
||||
struct sample_output *sample_output = calloc(1, sizeof(struct sample_output));
|
||||
sample_output->output = output;
|
||||
sample_output->sample = sample;
|
||||
|
@ -255,8 +259,7 @@ int main(int argc, char *argv[]) {
|
|||
state.new_input.notify = new_input_notify;
|
||||
clock_gettime(CLOCK_MONOTONIC, &state.last_frame);
|
||||
|
||||
|
||||
state.renderer = wlr_backend_get_renderer(wlr);
|
||||
state.renderer = wlr_renderer_autocreate(wlr);
|
||||
if (!state.renderer) {
|
||||
wlr_log(WLR_ERROR, "Could not start compositor, OOM");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -269,6 +272,8 @@ int main(int argc, char *argv[]) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
state.allocator = wlr_allocator_autocreate(wlr, state.renderer);
|
||||
|
||||
if (!wlr_backend_start(wlr)) {
|
||||
wlr_log(WLR_ERROR, "Failed to start backend");
|
||||
wlr_backend_destroy(wlr);
|
||||
|
|
|
@ -10,10 +10,4 @@
|
|||
*/
|
||||
uint32_t backend_get_buffer_caps(struct wlr_backend *backend);
|
||||
|
||||
/**
|
||||
* Get the backend's allocator. Automatically creates the allocator if
|
||||
* necessary.
|
||||
*/
|
||||
struct wlr_allocator *backend_get_allocator(struct wlr_backend *backend);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BACKEND_DRM_DRM_H
|
||||
#define BACKEND_DRM_DRM_H
|
||||
|
||||
#include <gbm.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
@ -20,9 +19,7 @@ struct wlr_drm_plane {
|
|||
uint32_t type;
|
||||
uint32_t id;
|
||||
|
||||
/* Local if this isn't a multi-GPU setup, on the parent otherwise. */
|
||||
struct wlr_drm_surface surf;
|
||||
/* Local, only initialized on multi-GPU setups. */
|
||||
/* Only initialized on multi-GPU setups */
|
||||
struct wlr_drm_surface mgpu_surf;
|
||||
|
||||
/* Buffer to be submitted to the kernel on the next page-flip */
|
||||
|
@ -39,6 +36,7 @@ struct wlr_drm_plane {
|
|||
|
||||
struct wlr_drm_crtc {
|
||||
uint32_t id;
|
||||
struct wlr_drm_lease *lease;
|
||||
|
||||
// Atomic modesetting only
|
||||
uint32_t mode_id;
|
||||
|
@ -81,7 +79,9 @@ struct wlr_drm_backend {
|
|||
struct wl_list fbs; // wlr_drm_fb.link
|
||||
struct wl_list outputs;
|
||||
|
||||
struct wlr_drm_renderer renderer;
|
||||
/* Only initialized on multi-GPU setups */
|
||||
struct wlr_drm_renderer mgpu_renderer;
|
||||
|
||||
struct wlr_session *session;
|
||||
|
||||
uint64_t cursor_width, cursor_height;
|
||||
|
@ -89,7 +89,7 @@ struct wlr_drm_backend {
|
|||
struct wlr_drm_format_set mgpu_formats;
|
||||
};
|
||||
|
||||
enum wlr_drm_connector_state {
|
||||
enum wlr_drm_connector_status {
|
||||
// Connector is available but no output is plugged in
|
||||
WLR_DRM_CONN_DISCONNECTED,
|
||||
// An output just has been plugged in and is waiting for a modeset
|
||||
|
@ -103,15 +103,22 @@ struct wlr_drm_mode {
|
|||
drmModeModeInfo drm_mode;
|
||||
};
|
||||
|
||||
struct wlr_drm_connector_state {
|
||||
const struct wlr_output_state *base;
|
||||
bool modeset;
|
||||
bool active;
|
||||
drmModeModeInfo mode;
|
||||
};
|
||||
|
||||
struct wlr_drm_connector {
|
||||
struct wlr_output output; // only valid if state != DISCONNECTED
|
||||
struct wlr_output output; // only valid if status != DISCONNECTED
|
||||
|
||||
struct wlr_drm_backend *backend;
|
||||
char name[24];
|
||||
enum wlr_drm_connector_state state;
|
||||
struct wlr_output_mode *desired_mode;
|
||||
enum wlr_drm_connector_status status;
|
||||
bool desired_enabled;
|
||||
uint32_t id;
|
||||
struct wlr_drm_lease *lease;
|
||||
|
||||
struct wlr_drm_crtc *crtc;
|
||||
uint32_t possible_crtcs;
|
||||
|
@ -123,8 +130,6 @@ struct wlr_drm_connector {
|
|||
int cursor_width, cursor_height;
|
||||
int cursor_hotspot_x, cursor_hotspot_y;
|
||||
|
||||
drmModeCrtc *old_crtc;
|
||||
|
||||
struct wl_list link;
|
||||
|
||||
/* CRTC ID if a page-flip is pending, zero otherwise.
|
||||
|
@ -142,8 +147,9 @@ struct wlr_drm_backend *get_drm_backend_from_backend(
|
|||
bool check_drm_features(struct wlr_drm_backend *drm);
|
||||
bool init_drm_resources(struct wlr_drm_backend *drm);
|
||||
void finish_drm_resources(struct wlr_drm_backend *drm);
|
||||
void restore_drm_outputs(struct wlr_drm_backend *drm);
|
||||
void scan_drm_connectors(struct wlr_drm_backend *state);
|
||||
void scan_drm_connectors(struct wlr_drm_backend *state,
|
||||
struct wlr_device_hotplug_event *event);
|
||||
void scan_drm_leases(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_commit_state(struct wlr_drm_connector *conn,
|
||||
|
@ -152,15 +158,10 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);
|
|||
bool drm_connector_supports_vrr(struct wlr_drm_connector *conn);
|
||||
size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_crtc *crtc);
|
||||
void drm_lease_destroy(struct wlr_drm_lease *lease);
|
||||
|
||||
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane);
|
||||
|
||||
bool drm_connector_state_is_modeset(const struct wlr_output_state *state);
|
||||
bool drm_connector_state_active(struct wlr_drm_connector *conn,
|
||||
const struct wlr_output_state *state);
|
||||
void drm_connector_state_mode(struct wlr_drm_connector *conn,
|
||||
const struct wlr_output_state *state, drmModeModeInfo *mode);
|
||||
|
||||
#define wlr_drm_conn_log(conn, verb, fmt, ...) \
|
||||
wlr_log(verb, "connector %s: " fmt, conn->name, ##__VA_ARGS__)
|
||||
#define wlr_drm_conn_log_errno(conn, verb, fmt, ...) \
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BACKEND_DRM_IFACE_H
|
||||
#define BACKEND_DRM_IFACE_H
|
||||
|
||||
#include <gbm.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <xf86drm.h>
|
||||
|
@ -10,13 +9,14 @@
|
|||
struct wlr_drm_backend;
|
||||
struct wlr_drm_connector;
|
||||
struct wlr_drm_crtc;
|
||||
struct wlr_drm_connector_state;
|
||||
|
||||
// Used to provide atomic or legacy DRM functions
|
||||
struct wlr_drm_interface {
|
||||
// Commit al pending changes on a CRTC.
|
||||
bool (*crtc_commit)(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_connector *conn, const struct wlr_output_state *state,
|
||||
uint32_t flags);
|
||||
// Commit all pending changes on a CRTC.
|
||||
bool (*crtc_commit)(struct wlr_drm_connector *conn,
|
||||
const struct wlr_drm_connector_state *state, uint32_t flags,
|
||||
bool test_only);
|
||||
};
|
||||
|
||||
extern const struct wlr_drm_interface atomic_iface;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef BACKEND_DRM_MONITOR_H
|
||||
#define BACKEND_DRM_MONITOR_H
|
||||
|
||||
#include <wlr/backend/drm.h>
|
||||
|
||||
/**
|
||||
* Helper to create new DRM sub-backends on GPU hotplug.
|
||||
*/
|
||||
struct wlr_drm_backend_monitor {
|
||||
struct wlr_backend *multi;
|
||||
struct wlr_backend *primary_drm;
|
||||
struct wlr_session *session;
|
||||
|
||||
struct wl_listener multi_destroy;
|
||||
struct wl_listener primary_drm_destroy;
|
||||
struct wl_listener session_destroy;
|
||||
struct wl_listener session_add_drm_card;
|
||||
};
|
||||
|
||||
struct wlr_drm_backend_monitor *drm_backend_monitor_create(
|
||||
struct wlr_backend *multi, struct wlr_backend *primary_drm,
|
||||
struct wlr_session *session);
|
||||
|
||||
#endif
|
|
@ -18,6 +18,8 @@ union wlr_drm_connector_props {
|
|||
uint32_t path;
|
||||
uint32_t vrr_capable; // not guaranteed to exist
|
||||
uint32_t subconnector; // not guaranteed to exist
|
||||
uint32_t non_desktop;
|
||||
uint32_t panel_orientation; // not guaranteed to exist
|
||||
|
||||
// atomic-modesetting only
|
||||
|
||||
|
@ -59,8 +61,9 @@ union wlr_drm_plane_props {
|
|||
uint32_t crtc_h;
|
||||
uint32_t fb_id;
|
||||
uint32_t crtc_id;
|
||||
uint32_t fb_damage_clips;
|
||||
};
|
||||
uint32_t props[13];
|
||||
uint32_t props[14];
|
||||
};
|
||||
|
||||
bool get_drm_connector_props(int fd, uint32_t id,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BACKEND_DRM_RENDERER_H
|
||||
#define BACKEND_DRM_RENDERER_H
|
||||
|
||||
#include <gbm.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wlr/backend.h>
|
||||
|
@ -13,7 +12,6 @@ struct wlr_buffer;
|
|||
|
||||
struct wlr_drm_renderer {
|
||||
struct wlr_drm_backend *backend;
|
||||
struct gbm_device *gbm;
|
||||
|
||||
struct wlr_renderer *wlr_rend;
|
||||
struct wlr_allocator *allocator;
|
||||
|
@ -26,17 +24,15 @@ struct wlr_drm_surface {
|
|||
uint32_t height;
|
||||
|
||||
struct wlr_swapchain *swapchain;
|
||||
struct wlr_buffer *back_buffer;
|
||||
};
|
||||
|
||||
struct wlr_drm_fb {
|
||||
struct wlr_buffer *wlr_buf;
|
||||
struct wlr_addon addon;
|
||||
struct wlr_drm_backend *backend;
|
||||
struct wl_list link; // wlr_drm_backend.fbs
|
||||
|
||||
struct gbm_bo *bo;
|
||||
uint32_t id;
|
||||
|
||||
struct wl_listener wlr_buf_destroy;
|
||||
};
|
||||
|
||||
bool init_drm_renderer(struct wlr_drm_backend *drm,
|
||||
|
@ -46,8 +42,6 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer);
|
|||
bool init_drm_surface(struct wlr_drm_surface *surf,
|
||||
struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height,
|
||||
const struct wlr_drm_format *drm_format);
|
||||
bool drm_surface_make_current(struct wlr_drm_surface *surf, int *buffer_age);
|
||||
void drm_surface_unset_current(struct wlr_drm_surface *surf);
|
||||
|
||||
bool drm_fb_import(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm,
|
||||
struct wlr_buffer *buf, const struct wlr_drm_format_set *formats);
|
||||
|
@ -58,15 +52,9 @@ void drm_fb_move(struct wlr_drm_fb **new, struct wlr_drm_fb **old);
|
|||
|
||||
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
|
||||
struct wlr_buffer *buffer);
|
||||
bool drm_surface_render_black_frame(struct wlr_drm_surface *surf);
|
||||
|
||||
struct wlr_drm_format *drm_plane_pick_render_format(
|
||||
struct wlr_drm_plane *plane, struct wlr_drm_renderer *renderer);
|
||||
bool drm_plane_init_surface(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_backend *drm, int32_t width, uint32_t height,
|
||||
bool with_modifiers);
|
||||
void drm_plane_finish_surface(struct wlr_drm_plane *plane);
|
||||
bool drm_plane_lock_surface(struct wlr_drm_plane *plane,
|
||||
struct wlr_drm_backend *drm);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,8 +13,6 @@ void parse_edid(struct wlr_output *restrict output, size_t len,
|
|||
const uint8_t *data);
|
||||
// Returns the string representation of a DRM output type
|
||||
const char *conn_get_name(uint32_t type_id);
|
||||
// Returns the DRM framebuffer id for a gbm_bo
|
||||
uint32_t get_fb_for_bo(struct gbm_bo *bo, bool with_modifiers);
|
||||
|
||||
// Part of match_obj
|
||||
enum {
|
||||
|
|
|
@ -8,14 +8,11 @@
|
|||
|
||||
struct wlr_headless_backend {
|
||||
struct wlr_backend backend;
|
||||
int drm_fd;
|
||||
struct wl_display *display;
|
||||
struct wl_list outputs;
|
||||
size_t last_output_num;
|
||||
struct wl_list input_devices;
|
||||
struct wl_listener display_destroy;
|
||||
struct wlr_renderer *parent_renderer;
|
||||
struct wl_listener parent_renderer_destroy;
|
||||
bool started;
|
||||
};
|
||||
|
||||
|
@ -25,15 +22,13 @@ struct wlr_headless_output {
|
|||
struct wlr_headless_backend *backend;
|
||||
struct wl_list link;
|
||||
|
||||
struct wlr_buffer *front_buffer;
|
||||
|
||||
struct wl_event_source *frame_timer;
|
||||
int frame_delay; // ms
|
||||
};
|
||||
|
||||
struct wlr_headless_input_device {
|
||||
struct wlr_input_device wlr_input_device;
|
||||
|
||||
struct wl_list link;
|
||||
struct wlr_headless_backend *backend;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <wlr/backend/libinput.h>
|
||||
#include <wlr/interfaces/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_list.h>
|
||||
|
||||
struct wlr_libinput_backend {
|
||||
struct wlr_backend backend;
|
||||
|
@ -22,12 +21,12 @@ struct wlr_libinput_backend {
|
|||
struct wl_listener session_destroy;
|
||||
struct wl_listener session_signal;
|
||||
|
||||
struct wlr_list wlr_device_lists; // list of struct wl_list
|
||||
struct wl_array wlr_device_lists; // struct wl_list *
|
||||
};
|
||||
|
||||
struct wlr_libinput_input_device {
|
||||
struct wlr_input_device wlr_input_device;
|
||||
|
||||
struct wl_list link;
|
||||
struct libinput_device *handle;
|
||||
};
|
||||
|
||||
|
@ -67,6 +66,10 @@ void handle_pointer_pinch_update(struct libinput_event *event,
|
|||
struct libinput_device *device);
|
||||
void handle_pointer_pinch_end(struct libinput_event *event,
|
||||
struct libinput_device *device);
|
||||
void handle_pointer_hold_begin(struct libinput_event *event,
|
||||
struct libinput_device *device);
|
||||
void handle_pointer_hold_end(struct libinput_event *event,
|
||||
struct libinput_device *device);
|
||||
|
||||
struct wlr_switch *create_libinput_switch(
|
||||
struct libinput_device *device);
|
||||
|
@ -83,6 +86,8 @@ void handle_touch_motion(struct libinput_event *event,
|
|||
struct libinput_device *device);
|
||||
void handle_touch_cancel(struct libinput_event *event,
|
||||
struct libinput_device *device);
|
||||
void handle_touch_frame(struct libinput_event *event,
|
||||
struct libinput_device *device);
|
||||
|
||||
struct wlr_tablet *create_libinput_tablet(
|
||||
struct libinput_device *device);
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef BACKEND_NOOP_H
|
||||
#define BACKEND_NOOP_H
|
||||
|
||||
#include <wlr/backend/noop.h>
|
||||
#include <wlr/backend/interface.h>
|
||||
|
||||
struct wlr_noop_backend {
|
||||
struct wlr_backend backend;
|
||||
struct wl_display *display;
|
||||
struct wl_list outputs;
|
||||
size_t last_output_num;
|
||||
bool started;
|
||||
|
||||
struct wl_listener display_destroy;
|
||||
};
|
||||
|
||||
struct wlr_noop_output {
|
||||
struct wlr_output wlr_output;
|
||||
|
||||
struct wlr_noop_backend *backend;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wlr_noop_backend *noop_backend_from_backend(
|
||||
struct wlr_backend *wlr_backend);
|
||||
|
||||
#endif
|
|
@ -11,4 +11,7 @@ bool libseat_change_vt(struct wlr_session *base, unsigned vt);
|
|||
|
||||
void session_init(struct wlr_session *session);
|
||||
|
||||
struct wlr_device *session_open_if_kms(struct wlr_session *restrict session,
|
||||
const char *restrict path);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <wlr/backend/wayland.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
|
||||
|
@ -25,6 +24,7 @@ struct wlr_wl_backend {
|
|||
size_t requested_outputs;
|
||||
size_t last_output_num;
|
||||
struct wl_listener local_display_destroy;
|
||||
char *activation_token;
|
||||
|
||||
/* remote state */
|
||||
struct wl_display *remote_display;
|
||||
|
@ -40,9 +40,11 @@ struct wlr_wl_backend {
|
|||
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;
|
||||
clockid_t presentation_clock;
|
||||
struct wlr_drm_format_set shm_formats;
|
||||
struct wlr_drm_format_set linux_dmabuf_v1_formats;
|
||||
struct wl_drm *legacy_drm;
|
||||
struct xdg_activation_v1 *activation_v1;
|
||||
char *drm_render_name;
|
||||
};
|
||||
|
||||
|
@ -85,6 +87,7 @@ struct wlr_wl_output {
|
|||
|
||||
struct wlr_wl_input_device {
|
||||
struct wlr_input_device wlr_input_device;
|
||||
struct wl_list link;
|
||||
uint32_t fingers;
|
||||
|
||||
struct wlr_wl_backend *backend;
|
||||
|
@ -99,6 +102,7 @@ struct wlr_wl_pointer {
|
|||
struct wl_pointer *wl_pointer;
|
||||
struct zwp_pointer_gesture_swipe_v1 *gesture_swipe;
|
||||
struct zwp_pointer_gesture_pinch_v1 *gesture_pinch;
|
||||
struct zwp_pointer_gesture_hold_v1 *gesture_hold;
|
||||
struct zwp_relative_pointer_v1 *relative_pointer;
|
||||
enum wlr_axis_source axis_source;
|
||||
int32_t axis_discrete;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
subdir('wlr')
|
||||
|
||||
exclude_files = ['meson.build', 'config.h.in', 'version.h.in']
|
||||
if not features.get('drm-backend')
|
||||
exclude_files += 'backend/drm.h'
|
||||
endif
|
||||
if not features.get('libinput-backend')
|
||||
exclude_files += 'backend/libinput.h'
|
||||
endif
|
||||
if not features.get('x11-backend')
|
||||
exclude_files += 'backend/x11.h'
|
||||
endif
|
||||
|
@ -12,6 +18,9 @@ endif
|
|||
if not features.get('gles2-renderer')
|
||||
exclude_files += ['render/egl.h', 'render/gles2.h']
|
||||
endif
|
||||
if not features.get('vulkan-renderer')
|
||||
exclude_files += 'render/vulkan.h'
|
||||
endif
|
||||
|
||||
install_subdir('wlr',
|
||||
install_dir: get_option('includedir'),
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef RENDER_ALLOCATOR_ALLOCATOR_H
|
||||
#define RENDER_ALLOCATOR_ALLOCATOR_H
|
||||
|
||||
#include <wlr/render/allocator.h>
|
||||
|
||||
struct wlr_allocator *allocator_autocreate_with_drm_fd(
|
||||
struct wlr_backend *backend, struct wlr_renderer *renderer, int drm_fd);
|
||||
|
||||
#endif
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef RENDER_DRM_DUMB_ALLOCATOR_H
|
||||
#define RENDER_DRM_DUMB_ALLOCATOR_H
|
||||
|
||||
#include "render/allocator.h"
|
||||
#ifndef RENDER_ALLOCATOR_DRM_DUMB_H
|
||||
#define RENDER_ALLOCATOR_DRM_DUMB_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;
|
|
@ -1,9 +1,10 @@
|
|||
#ifndef RENDER_GBM_ALLOCATOR_H
|
||||
#define RENDER_GBM_ALLOCATOR_H
|
||||
#ifndef RENDER_ALLOCATOR_GBM_H
|
||||
#define RENDER_ALLOCATOR_GBM_H
|
||||
|
||||
#include <gbm.h>
|
||||
#include <wlr/render/dmabuf.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "render/allocator.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
|
||||
struct wlr_gbm_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
@ -26,7 +27,7 @@ struct wlr_gbm_allocator {
|
|||
/**
|
||||
* Creates a new GBM allocator from a DRM FD.
|
||||
*
|
||||
* Does not take ownership over the FD.
|
||||
* Takes ownership over the FD.
|
||||
*/
|
||||
struct wlr_allocator *wlr_gbm_allocator_create(int drm_fd);
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef RENDER_SHM_ALLOCATOR_H
|
||||
#define RENDER_SHM_ALLOCATOR_H
|
||||
#ifndef RENDER_ALLOCATOR_SHM_H
|
||||
#define RENDER_ALLOCATOR_SHM_H
|
||||
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "render/allocator.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
|
||||
struct wlr_shm_buffer {
|
||||
struct wlr_buffer base;
|
|
@ -4,6 +4,7 @@
|
|||
#include <wlr/render/drm_format_set.h>
|
||||
|
||||
struct wlr_drm_format *wlr_drm_format_create(uint32_t format);
|
||||
bool wlr_drm_format_has(const struct wlr_drm_format *fmt, uint64_t modifier);
|
||||
bool wlr_drm_format_add(struct wlr_drm_format **fmt_ptr, uint64_t modifier);
|
||||
struct wlr_drm_format *wlr_drm_format_dup(const struct wlr_drm_format *format);
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef RENDER_EGL_H
|
||||
#define RENDER_EGL_H
|
||||
|
||||
#include <wlr/render/egl.h>
|
||||
|
||||
struct wlr_egl_context {
|
||||
EGLDisplay display;
|
||||
EGLContext context;
|
||||
EGLSurface draw_surface;
|
||||
EGLSurface read_surface;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes an EGL context for the given DRM FD.
|
||||
*
|
||||
* Will attempt to load all possibly required API functions.
|
||||
*/
|
||||
struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd);
|
||||
|
||||
/**
|
||||
* Frees all related EGL resources, makes the context not-current and
|
||||
* unbinds a bound wayland display.
|
||||
*/
|
||||
void wlr_egl_destroy(struct wlr_egl *egl);
|
||||
|
||||
/**
|
||||
* Creates an EGL image from the given dmabuf attributes. Check usability
|
||||
* of the dmabuf with wlr_egl_check_import_dmabuf once first.
|
||||
*/
|
||||
EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
|
||||
struct wlr_dmabuf_attributes *attributes, bool *external_only);
|
||||
|
||||
/**
|
||||
* Get DMA-BUF formats suitable for sampling usage.
|
||||
*/
|
||||
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats(
|
||||
struct wlr_egl *egl);
|
||||
/**
|
||||
* Get DMA-BUF formats suitable for rendering usage.
|
||||
*/
|
||||
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats(
|
||||
struct wlr_egl *egl);
|
||||
|
||||
/**
|
||||
* Destroys an EGL image created with the given wlr_egl.
|
||||
*/
|
||||
bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);
|
||||
|
||||
int wlr_egl_dup_drm_fd(struct wlr_egl *egl);
|
||||
|
||||
/**
|
||||
* Save the current EGL context to the structure provided in the argument.
|
||||
*
|
||||
* This includes display, context, draw surface and read surface.
|
||||
*/
|
||||
void wlr_egl_save_context(struct wlr_egl_context *context);
|
||||
|
||||
/**
|
||||
* Restore EGL context that was previously saved using wlr_egl_save_current().
|
||||
*/
|
||||
bool wlr_egl_restore_context(struct wlr_egl_context *context);
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
#include <wlr/render/interface.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
struct wlr_gles2_pixel_format {
|
||||
|
@ -23,7 +24,6 @@ struct wlr_gles2_pixel_format {
|
|||
struct wlr_gles2_tex_shader {
|
||||
GLuint program;
|
||||
GLint proj;
|
||||
GLint invert_y;
|
||||
GLint tex;
|
||||
GLint alpha;
|
||||
GLint pos_attrib;
|
||||
|
@ -39,10 +39,12 @@ struct wlr_gles2_renderer {
|
|||
|
||||
const char *exts_str;
|
||||
struct {
|
||||
bool read_format_bgra_ext;
|
||||
bool debug_khr;
|
||||
bool egl_image_external_oes;
|
||||
bool egl_image_oes;
|
||||
bool EXT_read_format_bgra;
|
||||
bool KHR_debug;
|
||||
bool OES_egl_image_external;
|
||||
bool OES_egl_image;
|
||||
bool EXT_texture_type_2_10_10_10_REV;
|
||||
bool OES_texture_half_float_linear;
|
||||
} exts;
|
||||
|
||||
struct {
|
||||
|
@ -82,7 +84,7 @@ struct wlr_gles2_buffer {
|
|||
GLuint rbo;
|
||||
GLuint fbo;
|
||||
|
||||
struct wl_listener buffer_destroy;
|
||||
struct wlr_addon addon;
|
||||
};
|
||||
|
||||
struct wlr_gles2_texture {
|
||||
|
@ -98,34 +100,31 @@ struct wlr_gles2_texture {
|
|||
|
||||
EGLImageKHR image;
|
||||
|
||||
bool inverted_y;
|
||||
bool has_alpha;
|
||||
|
||||
// Only affects target == GL_TEXTURE_2D
|
||||
uint32_t drm_format; // used to interpret upload data
|
||||
// If imported from a wlr_buffer
|
||||
struct wlr_buffer *buffer;
|
||||
|
||||
struct wl_listener buffer_destroy;
|
||||
struct wlr_addon buffer_addon;
|
||||
};
|
||||
|
||||
|
||||
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
|
||||
const struct wlr_gles2_pixel_format *format);
|
||||
const struct wlr_gles2_pixel_format *get_gles2_format_from_drm(uint32_t fmt);
|
||||
const struct wlr_gles2_pixel_format *get_gles2_format_from_gl(
|
||||
GLint gl_format, GLint gl_type, bool alpha);
|
||||
const uint32_t *get_gles2_shm_formats(size_t *len);
|
||||
const uint32_t *get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer,
|
||||
size_t *len);
|
||||
|
||||
struct wlr_gles2_renderer *gles2_get_renderer(
|
||||
struct wlr_renderer *wlr_renderer);
|
||||
struct wlr_gles2_texture *gles2_get_texture(
|
||||
struct wlr_texture *wlr_texture);
|
||||
|
||||
struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
|
||||
uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height,
|
||||
const void *data);
|
||||
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
|
||||
struct wl_resource *data);
|
||||
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
|
||||
struct wlr_dmabuf_attributes *attribs);
|
||||
struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer,
|
||||
struct wlr_buffer *buffer);
|
||||
void gles2_texture_destroy(struct wlr_gles2_texture *texture);
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
#ifndef RENDER_VULKAN_H
|
||||
#define RENDER_VULKAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/render/interface.h>
|
||||
|
||||
struct wlr_vk_descriptor_pool;
|
||||
|
||||
// Central vulkan state that should only be needed once per compositor.
|
||||
struct wlr_vk_instance {
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT messenger;
|
||||
|
||||
// enabled extensions
|
||||
size_t extension_count;
|
||||
const char **extensions;
|
||||
|
||||
struct {
|
||||
PFN_vkCreateDebugUtilsMessengerEXT createDebugUtilsMessengerEXT;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessengerEXT;
|
||||
} api;
|
||||
};
|
||||
|
||||
// Creates and initializes a vulkan instance.
|
||||
// Will try to enable the given extensions but not fail if they are not
|
||||
// available which can later be checked by the caller.
|
||||
// The debug parameter determines if validation layers are enabled and a
|
||||
// debug messenger created.
|
||||
// `compositor_name` and `compositor_version` are passed to the vulkan driver.
|
||||
struct wlr_vk_instance *vulkan_instance_create(size_t ext_count,
|
||||
const char **exts, bool debug);
|
||||
void vulkan_instance_destroy(struct wlr_vk_instance *ini);
|
||||
|
||||
// Logical vulkan device state.
|
||||
// Ownership can be shared by multiple renderers, reference counted
|
||||
// with `renderers`.
|
||||
struct wlr_vk_device {
|
||||
struct wlr_vk_instance *instance;
|
||||
|
||||
VkPhysicalDevice phdev;
|
||||
VkDevice dev;
|
||||
|
||||
int drm_fd;
|
||||
|
||||
// enabled extensions
|
||||
size_t extension_count;
|
||||
const char **extensions;
|
||||
|
||||
// we only ever need one queue for rendering and transfer commands
|
||||
uint32_t queue_family;
|
||||
VkQueue queue;
|
||||
|
||||
struct {
|
||||
PFN_vkGetMemoryFdPropertiesKHR getMemoryFdPropertiesKHR;
|
||||
} api;
|
||||
|
||||
uint32_t format_prop_count;
|
||||
struct wlr_vk_format_props *format_props;
|
||||
struct wlr_drm_format_set dmabuf_render_formats;
|
||||
struct wlr_drm_format_set dmabuf_texture_formats;
|
||||
|
||||
// supported formats for textures (contains only those formats
|
||||
// that support everything we need for textures)
|
||||
uint32_t shm_format_count;
|
||||
uint32_t *shm_formats; // to implement vulkan_get_shm_texture_formats
|
||||
};
|
||||
|
||||
// Tries to find the VkPhysicalDevice for the given drm fd.
|
||||
// Might find none and return VK_NULL_HANDLE.
|
||||
VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd);
|
||||
|
||||
// Creates a device for the given instance and physical device.
|
||||
// Will try to enable the given extensions but not fail if they are not
|
||||
// available which can later be checked by the caller.
|
||||
struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
||||
VkPhysicalDevice phdev, size_t ext_count, const char **exts);
|
||||
void vulkan_device_destroy(struct wlr_vk_device *dev);
|
||||
|
||||
// Tries to find any memory bit for the given vulkan device that
|
||||
// supports the given flags and is set in req_bits (e.g. if memory
|
||||
// type 2 is ok, (req_bits & (1 << 2)) must not be 0.
|
||||
// Set req_bits to 0xFFFFFFFF to allow all types.
|
||||
int vulkan_find_mem_type(struct wlr_vk_device *device,
|
||||
VkMemoryPropertyFlags flags, uint32_t req_bits);
|
||||
|
||||
struct wlr_vk_format {
|
||||
uint32_t drm_format;
|
||||
VkFormat vk_format;
|
||||
};
|
||||
|
||||
// Returns all known format mappings.
|
||||
// Might not be supported for gpu/usecase.
|
||||
const struct wlr_vk_format *vulkan_get_format_list(size_t *len);
|
||||
const struct wlr_vk_format *vulkan_get_format_from_drm(uint32_t drm_format);
|
||||
|
||||
struct wlr_vk_format_modifier_props {
|
||||
VkDrmFormatModifierPropertiesEXT props;
|
||||
VkExternalMemoryFeatureFlags dmabuf_flags;
|
||||
VkExtent2D max_extent;
|
||||
bool export_imported;
|
||||
};
|
||||
|
||||
struct wlr_vk_format_props {
|
||||
struct wlr_vk_format format;
|
||||
VkExtent2D max_extent; // relevant if not created as dma_buf
|
||||
VkFormatFeatureFlags features; // relevant if not created as dma_buf
|
||||
|
||||
uint32_t render_mod_count;
|
||||
struct wlr_vk_format_modifier_props *render_mods;
|
||||
|
||||
uint32_t texture_mod_count;
|
||||
struct wlr_vk_format_modifier_props *texture_mods;
|
||||
};
|
||||
|
||||
void vulkan_format_props_query(struct wlr_vk_device *dev,
|
||||
const struct wlr_vk_format *format);
|
||||
struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
|
||||
struct wlr_vk_format_props *props, uint64_t mod, bool render);
|
||||
void vulkan_format_props_finish(struct wlr_vk_format_props *props);
|
||||
|
||||
// For each format we want to render, we need a separate renderpass
|
||||
// and therefore also separate pipelines.
|
||||
struct wlr_vk_render_format_setup {
|
||||
struct wl_list link;
|
||||
VkFormat render_format; // used in renderpass
|
||||
VkRenderPass render_pass;
|
||||
|
||||
VkPipeline tex_pipe;
|
||||
VkPipeline quad_pipe;
|
||||
};
|
||||
|
||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
||||
struct wlr_vk_render_buffer {
|
||||
struct wlr_buffer *wlr_buffer;
|
||||
struct wlr_vk_renderer *renderer;
|
||||
struct wlr_vk_render_format_setup *render_setup;
|
||||
struct wl_list link; // wlr_vk_renderer.buffers
|
||||
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
VkFramebuffer framebuffer;
|
||||
uint32_t mem_count;
|
||||
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
||||
bool transitioned;
|
||||
|
||||
struct wl_listener buffer_destroy;
|
||||
};
|
||||
|
||||
// Vulkan wlr_renderer implementation on top of a wlr_vk_device.
|
||||
struct wlr_vk_renderer {
|
||||
struct wlr_renderer wlr_renderer;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_vk_device *dev;
|
||||
|
||||
VkCommandPool command_pool;
|
||||
|
||||
VkShaderModule vert_module;
|
||||
VkShaderModule tex_frag_module;
|
||||
VkShaderModule quad_frag_module;
|
||||
|
||||
VkDescriptorSetLayout ds_layout;
|
||||
VkPipelineLayout pipe_layout;
|
||||
VkSampler sampler;
|
||||
|
||||
VkFence fence;
|
||||
|
||||
struct wlr_vk_render_buffer *current_render_buffer;
|
||||
|
||||
// current frame id. Used in wlr_vk_texture.last_used
|
||||
// Increased every time a frame is ended for the renderer
|
||||
uint32_t frame;
|
||||
VkRect2D scissor; // needed for clearing
|
||||
|
||||
VkCommandBuffer cb;
|
||||
VkPipeline bound_pipe;
|
||||
|
||||
uint32_t render_width;
|
||||
uint32_t render_height;
|
||||
float projection[9];
|
||||
|
||||
size_t last_pool_size;
|
||||
struct wl_list descriptor_pools; // type wlr_vk_descriptor_pool
|
||||
struct wl_list render_format_setups;
|
||||
|
||||
struct wl_list textures; // wlr_gles2_texture.link
|
||||
struct wl_list destroy_textures; // wlr_vk_texture to destroy after frame
|
||||
struct wl_list foreign_textures; // wlr_vk_texture to return to foreign queue
|
||||
|
||||
struct wl_list render_buffers; // wlr_vk_render_buffer
|
||||
|
||||
struct {
|
||||
VkCommandBuffer cb;
|
||||
bool recording;
|
||||
struct wl_list buffers; // type wlr_vk_shared_buffer
|
||||
} stage;
|
||||
};
|
||||
|
||||
// Creates a vulkan renderer for the given device.
|
||||
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
|
||||
|
||||
// stage utility - for uploading/retrieving data
|
||||
// Gets an command buffer in recording state which is guaranteed to be
|
||||
// executed before the next frame.
|
||||
VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
|
||||
|
||||
// Submits the current stage command buffer and waits until it has
|
||||
// finished execution.
|
||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
|
||||
|
||||
// Suballocates a buffer span with the given size that can be mapped
|
||||
// and used as staging buffer. The allocation is implicitly released when the
|
||||
// stage cb has finished execution.
|
||||
struct wlr_vk_buffer_span vulkan_get_stage_span(
|
||||
struct wlr_vk_renderer *renderer, VkDeviceSize size);
|
||||
|
||||
// Tries to allocate a texture descriptor set. Will additionally
|
||||
// return the pool it was allocated from when successful (for freeing it later).
|
||||
struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||
struct wlr_vk_renderer *renderer, VkDescriptorSet *ds);
|
||||
|
||||
// Frees the given descriptor set from the pool its pool.
|
||||
void vulkan_free_ds(struct wlr_vk_renderer *renderer,
|
||||
struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds);
|
||||
struct wlr_vk_format_props *vulkan_format_props_from_drm(
|
||||
struct wlr_vk_device *dev, uint32_t drm_format);
|
||||
struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r);
|
||||
|
||||
// State (e.g. image texture) associated with a surface.
|
||||
struct wlr_vk_texture {
|
||||
struct wlr_texture wlr_texture;
|
||||
struct wlr_vk_renderer *renderer;
|
||||
uint32_t mem_count;
|
||||
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
const struct wlr_vk_format *format;
|
||||
VkDescriptorSet ds;
|
||||
struct wlr_vk_descriptor_pool *ds_pool;
|
||||
uint32_t last_used; // 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
|
||||
struct wl_list foreign_link;
|
||||
struct wl_list destroy_link;
|
||||
struct wl_list link; // wlr_gles2_renderer.textures
|
||||
|
||||
// If imported from a wlr_buffer
|
||||
struct wlr_buffer *buffer;
|
||||
struct wl_listener buffer_destroy;
|
||||
};
|
||||
|
||||
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
|
||||
VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
||||
const struct wlr_dmabuf_attributes *attribs,
|
||||
VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems,
|
||||
bool for_render);
|
||||
struct wlr_texture *vulkan_texture_from_buffer(
|
||||
struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer);
|
||||
void vulkan_texture_destroy(struct wlr_vk_texture *texture);
|
||||
|
||||
struct wlr_vk_descriptor_pool {
|
||||
VkDescriptorPool pool;
|
||||
uint32_t free; // number of textures that can be allocated
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wlr_vk_allocation {
|
||||
VkDeviceSize start;
|
||||
VkDeviceSize size;
|
||||
};
|
||||
|
||||
// List of suballocated staging buffers.
|
||||
// Used to upload to/read from device local images.
|
||||
struct wlr_vk_shared_buffer {
|
||||
struct wl_list link;
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize buf_size;
|
||||
|
||||
size_t allocs_size;
|
||||
size_t allocs_capacity;
|
||||
struct wlr_vk_allocation *allocs;
|
||||
};
|
||||
|
||||
// Suballocated range on a buffer.
|
||||
struct wlr_vk_buffer_span {
|
||||
struct wlr_vk_shared_buffer *buffer;
|
||||
struct wlr_vk_allocation alloc;
|
||||
};
|
||||
|
||||
// util
|
||||
bool vulkan_has_extension(size_t count, const char **exts, const char *find);
|
||||
const char *vulkan_strerror(VkResult err);
|
||||
void vulkan_change_layout(VkCommandBuffer cb, VkImage img,
|
||||
VkImageLayout ol, VkPipelineStageFlags srcs, VkAccessFlags srca,
|
||||
VkImageLayout nl, VkPipelineStageFlags dsts, VkAccessFlags dsta);
|
||||
void vulkan_change_layout_queue(VkCommandBuffer cb, VkImage img,
|
||||
VkImageLayout ol, VkPipelineStageFlags srcs, VkAccessFlags srca,
|
||||
VkImageLayout nl, VkPipelineStageFlags dsts, VkAccessFlags dsta,
|
||||
uint32_t src_family, uint32_t dst_family);
|
||||
|
||||
#define wlr_vk_error(fmt, res, ...) wlr_log(WLR_ERROR, fmt ": %s (%d)", \
|
||||
vulkan_strerror(res), res, ##__VA_ARGS__)
|
||||
|
||||
#endif // RENDER_VULKAN_H
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef RENDER_WLR_TEXTURE_H
|
||||
#define RENDER_WLR_TEXTURE_H
|
||||
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
|
||||
/**
|
||||
* Create a new texture from a buffer.
|
||||
*
|
||||
* Should not be called in a rendering block like renderer_begin()/end() or
|
||||
* between attaching a renderer to an output and committing it.
|
||||
*/
|
||||
struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
|
||||
struct wlr_buffer *buffer);
|
||||
|
||||
#endif
|
|
@ -22,32 +22,51 @@ struct wlr_shm_client_buffer {
|
|||
struct wl_listener release;
|
||||
};
|
||||
|
||||
struct wlr_shm_client_buffer *shm_client_buffer_create(
|
||||
struct wl_resource *resource);
|
||||
|
||||
/**
|
||||
* Buffer capabilities.
|
||||
* A read-only buffer that holds a data pointer.
|
||||
*
|
||||
* These bits indicate the features supported by a wlr_buffer. There is one bit
|
||||
* per function in wlr_buffer_impl.
|
||||
* This is suitable for passing raw pixel data to a function that accepts a
|
||||
* wlr_buffer.
|
||||
*/
|
||||
enum wlr_buffer_cap {
|
||||
WLR_BUFFER_CAP_DATA_PTR = 1 << 0,
|
||||
WLR_BUFFER_CAP_DMABUF = 1 << 1,
|
||||
WLR_BUFFER_CAP_SHM = 1 << 2,
|
||||
struct wlr_readonly_data_buffer {
|
||||
struct wlr_buffer base;
|
||||
|
||||
const void *data;
|
||||
uint32_t format;
|
||||
size_t stride;
|
||||
|
||||
void *saved_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a pointer to a region of memory referring to the buffer's underlying
|
||||
* storage. The format and stride can be used to interpret the memory region
|
||||
* contents.
|
||||
*
|
||||
* The returned pointer should be pointing to a valid memory region for read
|
||||
* and write operations. The returned pointer is only valid up to the next
|
||||
* buffer_end_data_ptr_access call.
|
||||
* Wraps a read-only data pointer into a wlr_buffer. The data pointer may be
|
||||
* accessed until readonly_data_buffer_drop() is called.
|
||||
*/
|
||||
bool buffer_begin_data_ptr_access(struct wlr_buffer *buffer, void **data,
|
||||
uint32_t *format, size_t *stride);
|
||||
void buffer_end_data_ptr_access(struct wlr_buffer *buffer);
|
||||
struct wlr_readonly_data_buffer *readonly_data_buffer_create(uint32_t format,
|
||||
size_t stride, uint32_t width, uint32_t height, const void *data);
|
||||
/**
|
||||
* Drops ownership of the buffer (see wlr_buffer_drop() for more details) and
|
||||
* perform a copy of the data pointer if a consumer still has the buffer locked.
|
||||
*/
|
||||
bool readonly_data_buffer_drop(struct wlr_readonly_data_buffer *buffer);
|
||||
|
||||
struct wlr_dmabuf_buffer {
|
||||
struct wlr_buffer base;
|
||||
struct wlr_dmabuf_attributes dmabuf;
|
||||
bool saved;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps a DMA-BUF into a wlr_buffer. The DMA-BUF may be accessed until
|
||||
* dmabuf_buffer_drop() is called.
|
||||
*/
|
||||
struct wlr_dmabuf_buffer *dmabuf_buffer_create(
|
||||
struct wlr_dmabuf_attributes *dmabuf);
|
||||
/**
|
||||
* Drops ownership of the buffer (see wlr_buffer_drop() for more details) and
|
||||
* takes a reference to the DMA-BUF (by dup'ing its file descriptors) if a
|
||||
* consumer still has the buffer locked.
|
||||
*/
|
||||
bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef TYPES_WLR_OUTPUT_H
|
||||
#define TYPES_WLR_OUTPUT_H
|
||||
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
||||
void output_pending_resolution(struct wlr_output *output, int *width,
|
||||
int *height);
|
||||
|
||||
struct wlr_drm_format *output_pick_format(struct wlr_output *output,
|
||||
const struct wlr_drm_format_set *display_formats, uint32_t format);
|
||||
void output_clear_back_buffer(struct wlr_output *output);
|
||||
bool output_ensure_buffer(struct wlr_output *output);
|
||||
|
||||
#endif
|
|
@ -11,4 +11,10 @@ struct wlr_renderer;
|
|||
struct wlr_surface *surface_create(struct wl_client *client,
|
||||
uint32_t version, uint32_t id, struct wlr_renderer *renderer);
|
||||
|
||||
/**
|
||||
* Create a new subsurface resource with the provided new ID.
|
||||
*/
|
||||
struct wlr_subsurface *subsurface_create(struct wlr_surface *surface,
|
||||
struct wlr_surface *parent, uint32_t version, uint32_t id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,7 +13,6 @@ struct wlr_xdg_positioner_resource {
|
|||
extern const struct wlr_surface_role xdg_toplevel_surface_role;
|
||||
extern const struct wlr_surface_role xdg_popup_surface_role;
|
||||
|
||||
uint32_t schedule_xdg_surface_configure(struct wlr_xdg_surface *surface);
|
||||
struct wlr_xdg_surface *create_xdg_surface(
|
||||
struct wlr_xdg_client *client, struct wlr_surface *surface,
|
||||
uint32_t id);
|
||||
|
@ -41,7 +40,6 @@ void send_xdg_toplevel_configure(struct wlr_xdg_surface *surface,
|
|||
struct wlr_xdg_surface_configure *configure);
|
||||
void handle_xdg_toplevel_ack_configure(struct wlr_xdg_surface *surface,
|
||||
struct wlr_xdg_surface_configure *configure);
|
||||
bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state);
|
||||
void destroy_xdg_toplevel(struct wlr_xdg_surface *surface);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
size_t push_zeroes_to_end(uint32_t arr[], size_t n);
|
||||
|
||||
|
@ -21,4 +22,9 @@ bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target);
|
|||
*/
|
||||
bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target);
|
||||
|
||||
/**
|
||||
* Remove a chunk of memory of the specified size at the specified offset.
|
||||
*/
|
||||
void array_remove_at(struct wl_array *arr, size_t offset, size_t size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
* Globals that are created and destroyed on the fly need special handling to
|
||||
* prevent race conditions with wl_registry. Use this function to destroy them.
|
||||
*/
|
||||
void wlr_global_destroy_safe(struct wl_global *global,
|
||||
struct wl_display *display);
|
||||
void wlr_global_destroy_safe(struct wl_global *global);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#ifndef UTIL_SHM_H
|
||||
#define UTIL_SHM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
int create_shm_file(void);
|
||||
int allocate_shm_file(size_t size);
|
||||
bool allocate_shm_file_pair(size_t size, int *rw_fd, int *ro_fd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,11 +25,6 @@ struct wlr_backend {
|
|||
/** Raised when new outputs are added, passed the wlr_output */
|
||||
struct wl_signal new_output;
|
||||
} events;
|
||||
|
||||
// Private state
|
||||
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -49,10 +44,6 @@ bool wlr_backend_start(struct wlr_backend *backend);
|
|||
* automatically when the wl_display is destroyed.
|
||||
*/
|
||||
void wlr_backend_destroy(struct wlr_backend *backend);
|
||||
/**
|
||||
* Obtains the wlr_renderer reference this backend is using.
|
||||
*/
|
||||
struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend);
|
||||
/**
|
||||
* Obtains the wlr_session reference from this backend if there is any.
|
||||
* Might return NULL for backends that don't use a session.
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
#include <wlr/backend/session.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
||||
struct wlr_drm_backend;
|
||||
|
||||
struct wlr_drm_lease {
|
||||
int fd;
|
||||
uint32_t lessee_id;
|
||||
struct wlr_drm_backend *backend;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a DRM backend using the specified GPU file descriptor (typically from
|
||||
* a device node in /dev/dri).
|
||||
|
@ -33,6 +47,29 @@ bool wlr_output_is_drm(struct wlr_output *output);
|
|||
*/
|
||||
uint32_t wlr_drm_connector_get_id(struct wlr_output *output);
|
||||
|
||||
/**
|
||||
* Tries to open non-master DRM FD. The compositor must not call `drmSetMaster`
|
||||
* on the returned FD.
|
||||
* Returns a valid opened DRM FD, or -1 on error.
|
||||
*/
|
||||
int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend);
|
||||
|
||||
/**
|
||||
* Leases the given outputs to the caller. The outputs must be from the
|
||||
* associated DRM backend.
|
||||
*
|
||||
* Returns NULL on error.
|
||||
*/
|
||||
struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
|
||||
size_t n_outputs, int *lease_fd);
|
||||
|
||||
/**
|
||||
* Terminates and destroys a given lease.
|
||||
*
|
||||
* The outputs will be owned again by the backend.
|
||||
*/
|
||||
void wlr_drm_lease_terminate(struct wlr_drm_lease *lease);
|
||||
|
||||
/**
|
||||
* Add mode to the list of available modes
|
||||
*/
|
||||
|
@ -40,4 +77,15 @@ typedef struct _drmModeModeInfo drmModeModeInfo;
|
|||
struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output,
|
||||
const drmModeModeInfo *mode);
|
||||
|
||||
/**
|
||||
* Get the connector's panel orientation.
|
||||
*
|
||||
* On some devices the panel is mounted in the casing in such a way that the
|
||||
* top side of the panel does not match with the top side of the device. This
|
||||
* function returns the output transform which needs to be applied to compensate
|
||||
* for this.
|
||||
*/
|
||||
enum wl_output_transform wlr_drm_connector_get_panel_orientation(
|
||||
struct wlr_output *output);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
* default.
|
||||
*/
|
||||
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display);
|
||||
/**
|
||||
* Creates a headless backend with an existing renderer.
|
||||
*/
|
||||
struct wlr_backend *wlr_headless_backend_create_with_renderer(
|
||||
struct wl_display *display, struct wlr_renderer *renderer);
|
||||
/**
|
||||
* Create a new headless output backed by an in-memory EGL framebuffer. You can
|
||||
* read pixels from this framebuffer via wlr_renderer_read_pixels but it is
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
struct wlr_backend_impl {
|
||||
bool (*start)(struct wlr_backend *backend);
|
||||
void (*destroy)(struct wlr_backend *backend);
|
||||
struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend);
|
||||
struct wlr_session *(*get_session)(struct wlr_backend *backend);
|
||||
clockid_t (*get_presentation_clock)(struct wlr_backend *backend);
|
||||
int (*get_drm_fd)(struct wlr_backend *backend);
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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_BACKEND_NOOP_H
|
||||
#define WLR_BACKEND_NOOP_H
|
||||
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
||||
/**
|
||||
* Creates a noop backend. Noop backends do not have a framebuffer and are not
|
||||
* capable of rendering anything. They are useful for when there's no real
|
||||
* outputs connected; you can stash your views on a noop output until an output
|
||||
* is connected.
|
||||
*/
|
||||
struct wlr_backend *wlr_noop_backend_create(struct wl_display *display);
|
||||
|
||||
/**
|
||||
* Create a new noop output.
|
||||
*/
|
||||
struct wlr_output *wlr_noop_add_output(struct wlr_backend *backend);
|
||||
|
||||
bool wlr_backend_is_noop(struct wlr_backend *backend);
|
||||
bool wlr_output_is_noop(struct wlr_output *output);
|
||||
|
||||
#endif
|
|
@ -15,7 +15,7 @@ struct wlr_device {
|
|||
struct wl_list link;
|
||||
|
||||
struct {
|
||||
struct wl_signal change;
|
||||
struct wl_signal change; // struct wlr_device_change_event
|
||||
struct wl_signal remove;
|
||||
} events;
|
||||
};
|
||||
|
@ -57,6 +57,23 @@ struct wlr_session_add_event {
|
|||
const char *path;
|
||||
};
|
||||
|
||||
enum wlr_device_change_type {
|
||||
WLR_DEVICE_HOTPLUG = 1,
|
||||
WLR_DEVICE_LEASE,
|
||||
};
|
||||
|
||||
struct wlr_device_hotplug_event {
|
||||
uint32_t connector_id;
|
||||
uint32_t prop_id;
|
||||
};
|
||||
|
||||
struct wlr_device_change_event {
|
||||
enum wlr_device_change_type type;
|
||||
union {
|
||||
struct wlr_device_hotplug_event hotplug;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Opens a session, taking control of the current virtual terminal.
|
||||
* This should not be called if another program is already in control
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#ifndef WLR_CONFIG_H
|
||||
#define WLR_CONFIG_H
|
||||
|
||||
#mesondefine WLR_HAS_DRM_BACKEND
|
||||
#mesondefine WLR_HAS_LIBINPUT_BACKEND
|
||||
#mesondefine WLR_HAS_X11_BACKEND
|
||||
|
||||
#mesondefine WLR_HAS_GLES2_RENDERER
|
||||
|
||||
#mesondefine WLR_HAS_VULKAN_RENDERER
|
||||
|
||||
#mesondefine WLR_HAS_XWAYLAND
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
|
||||
/**
|
||||
|
@ -22,6 +21,7 @@
|
|||
(WLR_OUTPUT_STATE_DAMAGE | \
|
||||
WLR_OUTPUT_STATE_SCALE | \
|
||||
WLR_OUTPUT_STATE_TRANSFORM | \
|
||||
WLR_OUTPUT_STATE_RENDER_FORMAT | \
|
||||
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED)
|
||||
|
||||
/**
|
||||
|
@ -52,19 +52,6 @@ struct wlr_output_impl {
|
|||
* Cleanup backend-specific resources tied to the output.
|
||||
*/
|
||||
void (*destroy)(struct wlr_output *output);
|
||||
/**
|
||||
* Make the output's back-buffer current for the renderer.
|
||||
*
|
||||
* buffer_age must be set to the buffer age in number of frames, or -1 if
|
||||
* unknown.
|
||||
*/
|
||||
bool (*attach_render)(struct wlr_output *output, int *buffer_age);
|
||||
/**
|
||||
* Unset the current renderer's buffer.
|
||||
*
|
||||
* This is the opposite of attach_render.
|
||||
*/
|
||||
void (*rollback_render)(struct wlr_output *output);
|
||||
/**
|
||||
* Check that the pending output state is a valid configuration.
|
||||
*
|
||||
|
@ -84,11 +71,6 @@ struct wlr_output_impl {
|
|||
* Zero can be returned if the output doesn't support gamma LUTs.
|
||||
*/
|
||||
size_t (*get_gamma_size)(struct wlr_output *output);
|
||||
/**
|
||||
* Export the output's current back-buffer as a DMA-BUF.
|
||||
*/
|
||||
bool (*export_dmabuf)(struct wlr_output *output,
|
||||
struct wlr_dmabuf_attributes *attribs);
|
||||
/**
|
||||
* Get the list of formats suitable for the cursor, assuming a buffer with
|
||||
* the specified capabilities.
|
||||
|
@ -104,7 +86,7 @@ struct wlr_output_impl {
|
|||
*/
|
||||
void (*get_cursor_size)(struct wlr_output *output, int *width, int *height);
|
||||
/**
|
||||
* Get the list of DMA-BUF formats suitable for the primary buffer,
|
||||
* Get the list of DRM formats suitable for the primary buffer,
|
||||
* assuming a buffer with the specified capabilities.
|
||||
*
|
||||
* If unimplemented, the primary buffer has no format constraint. If NULL
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
#ifndef RENDER_ALLOCATOR
|
||||
#define RENDER_ALLOCATOR
|
||||
/*
|
||||
* 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_ALLOCATOR_H
|
||||
#define WLR_ALLOCATOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/dmabuf.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
|
||||
struct wlr_allocator;
|
||||
struct wlr_backend;
|
||||
struct wlr_drm_format;
|
||||
struct wlr_renderer;
|
||||
|
||||
struct wlr_allocator_interface {
|
||||
|
@ -16,10 +22,13 @@ struct wlr_allocator_interface {
|
|||
void (*destroy)(struct wlr_allocator *alloc);
|
||||
};
|
||||
|
||||
void wlr_allocator_init(struct wlr_allocator *alloc,
|
||||
const struct wlr_allocator_interface *impl, uint32_t buffer_caps);
|
||||
|
||||
struct wlr_allocator {
|
||||
const struct wlr_allocator_interface *impl;
|
||||
|
||||
// Capabilites of the buffers created with this allocator
|
||||
// Capabilities of the buffers created with this allocator
|
||||
uint32_t buffer_caps;
|
||||
|
||||
struct {
|
||||
|
@ -36,20 +45,26 @@ struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend,
|
|||
* Destroy the allocator.
|
||||
*/
|
||||
void wlr_allocator_destroy(struct wlr_allocator *alloc);
|
||||
|
||||
/**
|
||||
* Allocate a new buffer.
|
||||
*
|
||||
* When the caller is done with it, they must unreference it by calling
|
||||
* wlr_buffer_drop.
|
||||
*
|
||||
* The `format` passed in indicates the format to use and the list of
|
||||
* acceptable modifiers. The order in which modifiers are listed is not
|
||||
* significant.
|
||||
*
|
||||
* When running with legacy drivers which don't support explicit modifiers, the
|
||||
* allocator must recognize two modifiers: INVALID (for implicit tiling and/or
|
||||
* compression) and LINEAR.
|
||||
*
|
||||
* The allocator must return a buffer using one of the modifiers listed. In
|
||||
* particular, allocators must not return a buffer with an implicit modifier
|
||||
* unless the user has allowed it by passing INVALID in the modifier list.
|
||||
*/
|
||||
struct wlr_buffer *wlr_allocator_create_buffer(struct wlr_allocator *alloc,
|
||||
int width, int height, const struct wlr_drm_format *format);
|
||||
|
||||
// For wlr_allocator implementors
|
||||
void wlr_allocator_init(struct wlr_allocator *alloc,
|
||||
const struct wlr_allocator_interface *impl, uint32_t buffer_caps);
|
||||
|
||||
struct wlr_allocator *allocator_autocreate_with_drm_fd(
|
||||
struct wlr_backend *backend, struct wlr_renderer *renderer, int drm_fd);
|
||||
|
||||
#endif
|
|
@ -14,17 +14,27 @@
|
|||
|
||||
#define WLR_DMABUF_MAX_PLANES 4
|
||||
|
||||
enum wlr_dmabuf_attributes_flags {
|
||||
WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0,
|
||||
WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1,
|
||||
WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* A Linux DMA-BUF pixel buffer.
|
||||
*
|
||||
* If the buffer was allocated with explicit modifiers enabled, the `modifier`
|
||||
* field must not be INVALID.
|
||||
*
|
||||
* If the buffer was allocated with explicit modifiers disabled (either because
|
||||
* the driver doesn't support it, or because the user didn't specify a valid
|
||||
* modifier list), the `modifier` field can have two values: INVALID means that
|
||||
* an implicit vendor-defined modifier is in use, LINEAR means that the buffer
|
||||
* is linear. The `modifier` field must not have any other value.
|
||||
*
|
||||
* When importing a DMA-BUF, users must not ignore the modifier unless it's
|
||||
* INVALID or LINEAR. In particular, users must not import a DMA-BUF to a
|
||||
* legacy API which doesn't support specifying an explicit modifier unless the
|
||||
* modifier is set to INVALID or LINEAR.
|
||||
*/
|
||||
struct wlr_dmabuf_attributes {
|
||||
int32_t width, height;
|
||||
uint32_t format;
|
||||
uint32_t flags; // enum wlr_dmabuf_attributes_flags
|
||||
uint64_t modifier;
|
||||
uint32_t format; // FourCC code, see DRM_FORMAT_* in <drm_fourcc.h>
|
||||
uint64_t modifier; // see DRM_FORMAT_MOD_* in <drm_fourcc.h>
|
||||
|
||||
int n_planes;
|
||||
uint32_t offset[WLR_DMABUF_MAX_PLANES];
|
||||
|
|
|
@ -5,19 +5,55 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** A single DRM format, with a set of modifiers attached. */
|
||||
struct wlr_drm_format {
|
||||
// The actual DRM format, from `drm_fourcc.h`
|
||||
uint32_t format;
|
||||
size_t len, cap;
|
||||
// The number of modifiers
|
||||
size_t len;
|
||||
// The capacity of the array; do not use.
|
||||
size_t capacity;
|
||||
// The actual modifiers
|
||||
uint64_t modifiers[];
|
||||
};
|
||||
|
||||
/**
|
||||
* A set of DRM formats and modifiers.
|
||||
*
|
||||
* This is used to describe the supported format + modifier combinations. For
|
||||
* instance, backends will report the set they can display, and renderers will
|
||||
* report the set they can render to. For a more general overview of formats
|
||||
* and modifiers, see:
|
||||
* https://lore.kernel.org/dri-devel/20210905122742.86029-1-daniels@collabora.com/
|
||||
*
|
||||
* For compatibility with legacy drivers which don't support explicit
|
||||
* modifiers, the special modifier DRM_FORMAT_MOD_INVALID is used to indicate
|
||||
* that implicit modifiers are supported. Legacy drivers can also support the
|
||||
* DRM_FORMAT_MOD_LINEAR modifier, which forces the buffer to have a linear
|
||||
* layout.
|
||||
*
|
||||
* Users must not assume that implicit modifiers are supported unless INVALID
|
||||
* is listed in the modifier list.
|
||||
*/
|
||||
struct wlr_drm_format_set {
|
||||
size_t len, cap;
|
||||
// The number of formats
|
||||
size_t len;
|
||||
// The capacity of the array; private to wlroots
|
||||
size_t capacity;
|
||||
// A pointer to an array of `struct wlr_drm_format *` of length `len`.
|
||||
struct wlr_drm_format **formats;
|
||||
};
|
||||
|
||||
/**
|
||||
* Free all of the DRM formats in the set, making the set empty. Does not
|
||||
* free the set itself.
|
||||
*/
|
||||
void wlr_drm_format_set_finish(struct wlr_drm_format_set *set);
|
||||
|
||||
/**
|
||||
* Return a pointer to a member of this `wlr_drm_format_set` of format
|
||||
* `format`, or NULL if none exists.
|
||||
*/
|
||||
const struct wlr_drm_format *wlr_drm_format_set_get(
|
||||
const struct wlr_drm_format_set *set, uint32_t format);
|
||||
|
||||
|
@ -27,4 +63,13 @@ bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set,
|
|||
bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format,
|
||||
uint64_t modifier);
|
||||
|
||||
/**
|
||||
* Intersect two DRM format sets `a` and `b`, storing in the destination set
|
||||
* `dst` the format + modifier pairs which are in both source sets.
|
||||
*
|
||||
* Returns false on failure or when the intersection is empty.
|
||||
*/
|
||||
bool wlr_drm_format_set_intersect(struct wlr_drm_format_set *dst,
|
||||
const struct wlr_drm_format_set *a, const struct wlr_drm_format_set *b);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,13 +29,6 @@
|
|||
#include <wlr/render/dmabuf.h>
|
||||
#include <wlr/render/drm_format_set.h>
|
||||
|
||||
struct wlr_egl_context {
|
||||
EGLDisplay display;
|
||||
EGLContext context;
|
||||
EGLSurface draw_surface;
|
||||
EGLSurface read_surface;
|
||||
};
|
||||
|
||||
struct wlr_egl {
|
||||
EGLDisplay display;
|
||||
EGLContext context;
|
||||
|
@ -44,13 +37,19 @@ struct wlr_egl {
|
|||
|
||||
struct {
|
||||
// Display extensions
|
||||
bool bind_wayland_display_wl;
|
||||
bool image_base_khr;
|
||||
bool image_dmabuf_import_ext;
|
||||
bool image_dmabuf_import_modifiers_ext;
|
||||
bool KHR_image_base;
|
||||
bool EXT_image_dma_buf_import;
|
||||
bool EXT_image_dma_buf_import_modifiers;
|
||||
bool IMG_context_priority;
|
||||
|
||||
// Device extensions
|
||||
bool device_drm_ext;
|
||||
bool EXT_device_drm;
|
||||
bool EXT_device_drm_render_node;
|
||||
|
||||
// Client extensions
|
||||
bool EXT_device_query;
|
||||
bool KHR_platform_gbm;
|
||||
bool EXT_platform_device;
|
||||
} exts;
|
||||
|
||||
struct {
|
||||
|
@ -58,73 +57,21 @@ struct wlr_egl {
|
|||
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
|
||||
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
|
||||
PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;
|
||||
PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL;
|
||||
PFNEGLUNBINDWAYLANDDISPLAYWL eglUnbindWaylandDisplayWL;
|
||||
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT;
|
||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT;
|
||||
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
|
||||
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
|
||||
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
|
||||
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
|
||||
} procs;
|
||||
|
||||
struct wl_display *wl_display;
|
||||
|
||||
bool has_modifiers;
|
||||
struct wlr_drm_format_set dmabuf_texture_formats;
|
||||
struct wlr_drm_format_set dmabuf_render_formats;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes an EGL context for the given platform and remote display.
|
||||
* Will attempt to load all possibly required api functions.
|
||||
*/
|
||||
struct wlr_egl *wlr_egl_create(EGLenum platform, void *remote_display);
|
||||
|
||||
/**
|
||||
* Frees all related EGL resources, makes the context not-current and
|
||||
* unbinds a bound wayland display.
|
||||
*/
|
||||
void wlr_egl_destroy(struct wlr_egl *egl);
|
||||
|
||||
/**
|
||||
* Binds the given display to the EGL instance.
|
||||
* This will allow clients to create EGL surfaces from wayland ones and render
|
||||
* to it.
|
||||
*/
|
||||
bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display);
|
||||
|
||||
/**
|
||||
* Creates an EGL image from the given wl_drm buffer resource.
|
||||
*/
|
||||
EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl,
|
||||
struct wl_resource *data, EGLint *fmt, int *width, int *height,
|
||||
bool *inverted_y);
|
||||
|
||||
/**
|
||||
* Creates an EGL image from the given dmabuf attributes. Check usability
|
||||
* of the dmabuf with wlr_egl_check_import_dmabuf once first.
|
||||
*/
|
||||
EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
|
||||
struct wlr_dmabuf_attributes *attributes, bool *external_only);
|
||||
|
||||
/**
|
||||
* Get DMA-BUF formats suitable for sampling usage.
|
||||
*/
|
||||
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_texture_formats(
|
||||
struct wlr_egl *egl);
|
||||
/**
|
||||
* Get DMA-BUF formats suitable for rendering usage.
|
||||
*/
|
||||
const struct wlr_drm_format_set *wlr_egl_get_dmabuf_render_formats(
|
||||
struct wlr_egl *egl);
|
||||
|
||||
bool wlr_egl_export_image_to_dmabuf(struct wlr_egl *egl, EGLImageKHR image,
|
||||
int32_t width, int32_t height, uint32_t flags,
|
||||
struct wlr_dmabuf_attributes *attribs);
|
||||
|
||||
/**
|
||||
* Destroys an EGL image created with the given wlr_egl.
|
||||
*/
|
||||
bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image);
|
||||
struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
|
||||
EGLContext context);
|
||||
|
||||
/**
|
||||
* Make the EGL context current.
|
||||
|
@ -138,18 +85,4 @@ bool wlr_egl_unset_current(struct wlr_egl *egl);
|
|||
|
||||
bool wlr_egl_is_current(struct wlr_egl *egl);
|
||||
|
||||
/**
|
||||
* Save the current EGL context to the structure provided in the argument.
|
||||
*
|
||||
* This includes display, context, draw surface and read surface.
|
||||
*/
|
||||
void wlr_egl_save_context(struct wlr_egl_context *context);
|
||||
|
||||
/**
|
||||
* Restore EGL context that was previously saved using wlr_egl_save_current().
|
||||
*/
|
||||
bool wlr_egl_restore_context(struct wlr_egl_context *context);
|
||||
|
||||
int wlr_egl_dup_drm_fd(struct wlr_egl *egl);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,6 @@ struct wlr_gles2_texture_attribs {
|
|||
GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */
|
||||
GLuint tex;
|
||||
|
||||
bool inverted_y;
|
||||
bool has_alpha;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/render/dmabuf.h>
|
||||
|
||||
struct wlr_box;
|
||||
struct wlr_fbox;
|
||||
|
||||
struct wlr_renderer_impl {
|
||||
bool (*bind_buffer)(struct wlr_renderer *renderer,
|
||||
struct wlr_buffer *buffer);
|
||||
|
@ -30,12 +32,8 @@ struct wlr_renderer_impl {
|
|||
const float matrix[static 9], float alpha);
|
||||
void (*render_quad_with_matrix)(struct wlr_renderer *renderer,
|
||||
const float color[static 4], const float matrix[static 9]);
|
||||
const uint32_t *(*get_shm_texture_formats)(struct wlr_renderer *renderer,
|
||||
size_t *len);
|
||||
bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer,
|
||||
struct wl_resource *resource);
|
||||
void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer,
|
||||
struct wl_resource *buffer, int *width, int *height);
|
||||
const uint32_t *(*get_shm_texture_formats)(
|
||||
struct wlr_renderer *renderer, size_t *len);
|
||||
const struct wlr_drm_format_set *(*get_dmabuf_texture_formats)(
|
||||
struct wlr_renderer *renderer);
|
||||
const struct wlr_drm_format_set *(*get_render_formats)(
|
||||
|
@ -45,16 +43,7 @@ struct wlr_renderer_impl {
|
|||
uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height,
|
||||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
|
||||
void *data);
|
||||
struct wlr_texture *(*texture_from_pixels)(struct wlr_renderer *renderer,
|
||||
uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height,
|
||||
const void *data);
|
||||
struct wlr_texture *(*texture_from_wl_drm)(struct wlr_renderer *renderer,
|
||||
struct wl_resource *data);
|
||||
struct wlr_texture *(*texture_from_dmabuf)(struct wlr_renderer *renderer,
|
||||
struct wlr_dmabuf_attributes *attribs);
|
||||
void (*destroy)(struct wlr_renderer *renderer);
|
||||
bool (*init_wl_display)(struct wlr_renderer *renderer,
|
||||
struct wl_display *wl_display);
|
||||
int (*get_drm_fd)(struct wlr_renderer *renderer);
|
||||
uint32_t (*get_render_buffer_caps)(struct wlr_renderer *renderer);
|
||||
struct wlr_texture *(*texture_from_buffer)(struct wlr_renderer *renderer,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* 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_RENDER_VULKAN_H
|
||||
#define WLR_RENDER_VULKAN_H
|
||||
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
|
||||
struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd);
|
||||
bool wlr_texture_is_vk(struct wlr_texture *texture);
|
||||
|
||||
#endif
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/types/wlr_box.h>
|
||||
|
||||
enum wlr_renderer_read_pixels_flags {
|
||||
WLR_RENDERER_READ_PIXELS_Y_INVERT = 1,
|
||||
|
@ -22,6 +21,8 @@ enum wlr_renderer_read_pixels_flags {
|
|||
struct wlr_renderer_impl;
|
||||
struct wlr_drm_format_set;
|
||||
struct wlr_buffer;
|
||||
struct wlr_box;
|
||||
struct wlr_fbox;
|
||||
|
||||
struct wlr_renderer {
|
||||
const struct wlr_renderer_impl *impl;
|
||||
|
@ -80,16 +81,6 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r,
|
|||
*/
|
||||
const uint32_t *wlr_renderer_get_shm_texture_formats(
|
||||
struct wlr_renderer *r, size_t *len);
|
||||
/**
|
||||
* Returns true if this wl_buffer is a wl_drm buffer.
|
||||
*/
|
||||
bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer,
|
||||
struct wl_resource *buffer);
|
||||
/**
|
||||
* Gets the width and height of a wl_drm buffer.
|
||||
*/
|
||||
void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer,
|
||||
struct wl_resource *buffer, int *width, int *height);
|
||||
/**
|
||||
* Get the DMA-BUF formats supporting sampling usage. Buffers allocated with
|
||||
* a format from this list may be imported via wlr_texture_from_dmabuf.
|
||||
|
@ -108,13 +99,19 @@ bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt,
|
|||
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data);
|
||||
|
||||
/**
|
||||
* Creates necessary shm and invokes the initialization of the implementation.
|
||||
* Initializes wl_shm, linux-dmabuf and other buffer factory protocols.
|
||||
*
|
||||
* Returns false on failure.
|
||||
*/
|
||||
bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
||||
struct wl_display *wl_display);
|
||||
|
||||
/**
|
||||
* Initializes wl_shm on the provided wl_display.
|
||||
*/
|
||||
bool wlr_renderer_init_wl_shm(struct wlr_renderer *r,
|
||||
struct wl_display *wl_display);
|
||||
|
||||
/**
|
||||
* Obtains the FD of the DRM device used for rendering, or -1 if unavailable.
|
||||
*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue