Compare commits

..

39 commits
main ... 14.0.3

Author SHA1 Message Date
Marius Vlad
d3038814ed build: bump to version 14.0.3 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2026-04-24 10:47:31 +03:00
Leandro Ribeiro
8f12365f13 drm: use output capture task destroy listener for writeback
No behavior changes; this is a follow-up of "drm: handle client buffer
destroyed while writeback scheduled".

That commit protects against clients disconnecting while a writeback job
is scheduled, which could otherwise lead to crashes if the buffer is
destroyed before the wb job completes. However, output capture provides
the same functionality: it listens to the client buffer destroy event to
retire the capture task.

Instead of listening to the wl_buffer destroy event, simply listen to
the capture task destroy event. GL renderer already follows this
pattern, and now DRM aligns with it.

See also:
weston_capture_task_buffer_destroy_handler()
weston_capture_task_add_destroy_listener()

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 04a85ab71c)
2026-04-23 20:51:50 +03:00
Leandro Ribeiro
4c2bbc5180 drm: assert writeback state is freed after capture task retirement
No behavior change, just a refactor to make it more clear that the state
is freed after the capture task is retired.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 7444c29fd2)
2026-04-23 20:51:48 +03:00
Derek Foreman
e4323dc7c9 libweston: Add an output capture task destroy listener
An output task may be destroyed by a client disconnect. This causes
problems for our drm backend's asynchronous capture task handler, which
currently has no way to notice this.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit d2bab8a5ee)
2026-04-23 20:37:43 +03:00
Leandro Ribeiro
641ac3ef82 drm: handle client buffer destroyed while writeback scheduled
Currently when a client buffer gets destroyed, the output capture task
gets destroyed with weston_capture_task_buffer_destroy_handler().

The problem is that we may have a writeback task scheduled, so
wb_state->ct would be pointing to a ct that has already been retired
and destroyed.

In this commit we start handling this case.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 1152c53e58)
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2026-04-23 14:42:06 +03:00
lxylxy123456
65c7cc45b3 clients/window: Fix segfault when dragging with touchscreen
Signed-off-by: lxylxy123456 <lixiaoyi13691419520@gmail.com>
(cherry picked from commit 874bf36c51)
2026-04-23 14:42:06 +03:00
Wang Ruitang
60963b795c libweston: check focus surface before enabling pointer constraint
Check if surface matches before enabling pointer constraint. If not
match, no constraint enabled. Otherwise, assertion would failed in
confined_pointer_grab_pointer_motion() and weston would crash.

This fixes crashes reported in GitLab issues #185 and #670.

Closes: https://gitlab.freedesktop.org/wayland/weston/-/issues/185
Closes: https://gitlab.freedesktop.org/wayland/weston/-/issues/670
Signed-off-by: Ruitang Wang <Ruitang.Wang@amd.com>
(cherry picked from commit c23ea4ba8d)
2026-04-23 14:42:06 +03:00
Pekka Paalanen
d1f9bd3d09 compositor: fix finish_frame presentation feedback crash
This was brought up in issue 1063. The assertion in
weston_presentation_feedback_present_list() will trigger randomly during
repeated suspend/resume testing, presumably while a client is animating
and asking for presentation feedback.

drm_output_start_repaint_loop() has a path where drmWaitVBlank() is able
to pull a good timestamp for the last vblank. This results in a call to
weston_output_finish_frame() with a good timestamp and
WP_PRESENTATION_FEEDBACK_INVALID in the flags.

Previously it was assumed that in such case the presentation feedback
list cannot have any entries. This assumption is false. It is possible
that while the output is in idle state, a client will post an update to
a surface and ask for presentation feedback on it. This should trigger
drm_output_start_repaint_loop() with a non-empty feedback list.

It is unclear why this problem was not seen in the wild much more often.

Start-repaint-loop does not present anything by definition, it only acts
to synchronize the output repaint loop with the (hardware) scanout
cycle. Therefore no feedback must be sent there. As
WP_PRESENTATION_FEEDBACK_INVALID flag indicates no feedback must be
sent, use it to avoid calling
weston_presentation_feedback_present_list().

References: https://gitlab.freedesktop.org/wayland/weston/-/issues/1063
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
(cherry picked from commit d69e816b54)
2026-04-23 14:42:06 +03:00
Derek Foreman
5ea838be63 compositor: Fix output reflowing when mirroring is in use
When we have a mirror, it will be at the same x,y position as the output
it's mirroring. On hot unplug, the current logic results in the mirroring
output being moved to the left by the width of its target output. The
mirror will then be destroyed, and the views can be left dangling outside
of usable space when a hot plug restores the outputs.

Subtly change the reflow logic to only reflow outputs to the right of the
removed output by testing co-ordinates, instead of assuming that every
output in the list is to the right of the previous.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 1a9cf3bfb6)
2026-04-23 14:42:06 +03:00
Leandro Ribeiro
1a9149cc06 drm: avoid dma-buf feedback endless loop
Currently we have the following situation: we add a scanout tranche
because if the client re-allocates with another format/modifier, the
chances of being placed in a DRM/KMS plane is higher.

But then we run out of overlay planes. So we remove the scanout tranche,
because the format/modifier available in the renderer tranche are
optimal for rendering.

Now Weston detects again that the format/modifier is what may be
avoiding the view being place in a plane, re-adding the scanout tranche.
And we have an endless loop.

To avoid this, let's accumulate the reasons why placing the view in a
place failed. So if we detect that we don't have planes available, no
matter the format/modifier, we won't add the scanout tranche.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit d3ead778de)
2025-07-18 11:59:26 -03:00
Leandro Ribeiro
0b5c47edca drm: fix issue with enum being wrongly used
FAILURE_REASONS_ADD_FB_FAILED is defined as (1 << 3), so when we are
accumulating "failure reasons" in a variable we don't need to do the bit
shift again.

This results in an issue, because (1 << FAILURE_REASONS_ADD_FB_FAILED)
results in (1 << (1 << 3)) == (1 << 8).

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 8b83bb5ceb)
2025-07-18 11:59:07 -03:00
Leandro Ribeiro
6445af1ead drm: fix a few dma-buf feedback failure reasons
There are a few points in the code where we are wrongly using
FAILURE_REASONS_ADD_FB_FAILED, probably because we didn't have so many
"failure reasons" previously. This update such cases to use enum's that
make sense.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 3210cec531)
2025-07-18 11:58:48 -03:00
Leandro Ribeiro
8f1a089917 drm: try other planes that may support fences
Do not skip all the planes if a single one of them do not support
fences. The other may do.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit b347af2ce0)
2025-07-18 11:58:27 -03:00
Marius Vlad
015b3b4d4c build: bump to version 14.0.2 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2025-04-25 15:37:41 +03:00
Derek Foreman
51dfd1be3a frontend: Fix crash in output resize handler
The output resized signal sends a struct weston_output as the data, not
a struct weston_head.

Fixes 197c5e0084

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 52204f55ea)
2025-04-25 15:02:09 +03:00
Pekka Paalanen
ef25333fac libweston: fix bitshift in weston_idalloc_get_id()
Fixes the following UBSan error:

../../git/weston/libweston/id-number-allocator.c:140:16: runtime error:
left shift of 1 by 31 places cannot be represented in type 'int'

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
(cherry picked from commit 6773ffa758)
2025-04-17 11:51:04 +03:00
Pekka Paalanen
cb8bb2763a libweston: fix realloc in weston_idalloc
realloc() does not initialize the added memory, it needs to be zeroed
explicitly.

Not zeroing this memory had one severe consequence: if the new
lowest_free_bucket was 0xffffffff, weston_idalloc_get_id() would fail an
assertion.

Otherwise non-zero bits in the added memory would just cause id numbers
to be skipped unnecessarily, which does no harm.

Fixes: https://gitlab.freedesktop.org/wayland/weston/-/issues/1000

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
(cherry picked from commit ed51e9ae43)
2025-04-17 11:50:53 +03:00
Pekka Paalanen
3b340a2f9e libweston: refactor update_lowest_free_bucket()
No functional change here other than asserting that next_num didn't wrap
around. This reorganization helps adding the code
needed to clear the memory added by xrealloc() in the next patch.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
(cherry picked from commit 2733a95962)
2025-04-17 11:50:39 +03:00
Michael Olbrich
f87d119e56 libweston-desktop: don't try to move child surfaces to not existing layer
The parent surface may not be on a layer. In that case, remove all child
surfaces from their current layer as well.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
(cherry picked from commit 6e88a851a4)
2025-04-17 11:50:12 +03:00
kang-sooyeon
1cb63e1f83 libweston/input.c: Fix weston crash with the mouse event
Fix weston crash when user click the mouse continuosly while
the video is playing.
Call weston_view_update_transform before calling
weston_coord_global_to_surface to update view->transform.dirty to 0.

Fixes #985

Tested-by: Sooyeon Kang sooyeon8979@gmail.com
Signed-off-by: Sooyeon Kang sooyeon8979@gmail.com
(cherry picked from commit c77a5d386a)
2025-04-17 11:50:00 +03:00
Marius Vlad
23f254c690 windowed-output-api.h: Provide ARRAY_LENGH() for windowed-output-api
We need this common helper as we don't have access to shared helper, so
just define one in-situ.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 43f7b7b3bb)
2025-04-17 11:49:47 +03:00
Derek Foreman
11f20fa8e4 drm: Fix underlay test
We need to reset the underlay check inside the view evaluation loop,
otherwise once we need an underlay we'll treat every following view as
needing an underlay.

Fixes: 1065d23406 ("backend-drm: Improve plane assignment for underlay platform")
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 8dbb3e17d0)
2025-04-17 11:49:29 +03:00
Marius Vlad
9eb44254a7 compositor: Mark pnode accordingly when buffer type is direct
As we exit early we never have the chance to mark it as is_direct when
the buffer type is direct_display.

This is required as is_direct is never checked in GL attach part we
end up tripping on invalid renderer_private causing it to assert.

Fixes 2db4f17244f, "compositor: re-order paint node placeholder checks"

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 9d841e39e8)
2025-04-17 11:49:16 +03:00
Derek Foreman
8eb0ff8a19 compositor: re-order paint node placeholder checks
Doing these in the wrong order breaks content protection, and breaks
placing direct-display paint nodes on underlays.

Fixes: 827e2276 ("gl-renderer: Draw holes on primary plane for the view on underlay")
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 53189ebb89)
2025-04-17 11:49:03 +03:00
Marius Vlad
af871d82ef gl-renderer: Take direct-display into consideration
The buffer_init function added with commit 83b37c0ac4, "renderers: pull
dmabuf initial setup out of attach", doesn't take into consideration the
the buffer's direct-display property.

Previously, gl_renderer_attach_dmabuf, wasn't being called when dmabuf's
direct-display  was turned on, but with commit 83b37c0ac4 this has been changed.

So with commit 83b37c0ac4, linux_dmabuf_buffer_get_user_data will never
return a valid gb (gl buffer state), causing a crash using
direct-display extension. This adds an explicit check to return early
when this happens.

Fixes: 83b37c0ac4, "renderers: pull dmabuf initial setup out of attach"
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit bf7b2311e7)
2025-04-17 11:48:42 +03:00
Ian Ray
ee92a531da shared: fix binding-modifier none
Fix binding-modifier "none" which was defaulting to Super.

Commit [1] introduced the original support for "none" but the logic was
subsequently lost in f7ba35f5.

[1] 553d1248 ("desktop-shell: Allow binding-modifier weston.ini option to be none")

Fixes: #976

Fixes: f7ba35f5 ("kiosk-shell: Enable debug keybindings")
Signed-off-by: Ian Ray <ian.ray@gehealthcare.com>
(cherry picked from commit fc278fb3cc)
2025-04-17 11:48:30 +03:00
Philipp Zabel
353600b6fc vnc: Allow neatvnc in version 0.9.0
Neat VNC 0.9.0 is backwards compatible.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
(cherry picked from commit b4386289d6)
2025-04-17 11:48:12 +03:00
Derek Foreman
a712e803d2 compositor: Prevent startup crash when hdcp mode is set on display
We can startup with the display already in type1 content protection mode.
When this happens, we call weston_output_dirty_paint_nodes() on a display
that hasn't yet been enabled. The paint node list isn't initialized yet,
so we crash.

We don't actually need to touch the paint nodes here anyway, as
weston_output_damage() ensures a repaint if the ourput is enabled, and
weston_output_dirty_paint_nodes() just forces calculation of things
unrelated to protection, and we'll override most of that in
maybe_replace_paint_node() if necessary when we get there.

Just drop the weston_output_dirty_paint_nodes() call to stop the
crash.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 4f2cc67fde)
2025-04-17 11:47:58 +03:00
Marius Vlad
d70f91d3f1 libweston/desktop: Avoid a potential crash on invalid resource
This checks for a valid resource when getting a xdg_popup. Similar to
the check in get_toplevel.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 80e47a7161)
2025-04-17 11:47:36 +03:00
Marius Vlad
26e03f3891 libweston/desktop: Don't destroy the xdg_surface
Upon xdg_toplevel::destroy we seem to be calling xdg_surface::destroy
destroy handler. Protocol states that we should umap the surface with
client having the posibility to getting another toplevel role for the
same xdg_surface and re-map the window.

This also adds a guard for an unlikely invalid resource.

Fixes: #774

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 8b5bb588df)
2025-04-17 11:47:28 +03:00
Marius Vlad
61f2248de2 build: bump to version 14.0.1 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2024-10-21 16:22:27 +03:00
Marius Vlad
7eaba52a22 libweston/matrix: Fix narrow conversion with C++
Fixes the following C++ narrow conversion:

/include/libweston-14/libweston/matrix.h: In function ‘weston_coord
weston_coord_truncate(weston_coord)’:
/include/libweston-14/libweston/matrix.h:212:39: error: narrowing
conversion of ‘(int)in.weston_coord::x’ from ‘int’ to ‘double’
[-Werror=narrowing] 212 |         return (struct weston_coord){
	(int)in.x, (int)in.y };
      |                                       ^~~~~~~~~
/home/mvlad/install-new/include/libweston-14/libweston/matrix.h:212:50:
error: narrowing conversion of ‘(int)in.weston_coord::y’ from ‘int’ to
‘double’ [-Werror=narrowing] 212 |         return (struct weston_coord){
	(int)in.x, (int)in.y };

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit a501acd291)
2024-10-21 13:41:04 +03:00
Jeri Li
502e4bd31d libweston/desktop: avoid weston crash while xdg_surface ack_configure
checks the resource and sends a protocol error if the client tries to
send a request to an inert object then returns out of the request
handler

Signed-off-by: Jeri Li <jeri.li@mediatek.com>
(cherry picked from commit 04f27f1be2)
2024-10-14 14:26:34 +03:00
Marius Vlad
e056153bf4 desktop-shell: Don't attempt to re-add the view to panel layer
This change fixes a side-effect of weston_view_move_to_layer helper
which would basically unmap the view because the layer entry list is no
longer visible. Only add the view to panel layer the first time.

Fixes: #956

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 217fb30847)
2024-10-11 13:30:52 +03:00
Marius Vlad
6d015b4759 libweston: Move weston_get_backend_type after enum declaration
Fix: #951

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 68bbc4cf51)
2024-10-11 13:30:13 +03:00
Jan Engelhardt
ca3c5b8015 build: insert missing wayland-server-protocol dependency
A new build error sprung up in weston-14 compared to 13.0.0.
Fix it.

FAILED: tests/liblib_lcms_util.a.p/lcms_util.c.o
cc -Itests/liblib_lcms_util.a.p -Itests -I../tests -I. -I.. -Iinclude
-I../include -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall
-Winvalid-pch -Wextra -Wpedantic -std=gnu99 -Wmissing-prototypes
-Wno-unused-parameter -Wno-shift-negative-value
-Wno-missing-field-initializers -Wno-pedantic -Wundef
-fvisibility=hidden -O2 -Wall -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
-fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables
-fstack-clash-protection -Werror=return-type -flto=auto -g -fPIC -MD
-MQ tests/liblib_lcms_util.a.p/lcms_util.c.o -MF
tests/liblib_lcms_util.a.p/lcms_util.c.o.d -o
tests/liblib_lcms_util.a.p/lcms_util.c.o -c ../tests/lcms_util.c
In file included from ../tests/lcms_util.c:35:
../include/libweston/matrix.h:33:10: fatal error:
wayland-server-protocol.h: No such file or directory

   33 | #include <wayland-server-protocol.h>

Signed-off-by: Jan Engelhardt <jengelh@inai.de>
(cherry picked from commit f86ff8c07d)
2024-10-11 13:30:07 +03:00
David Edmundson
1e667cf0c3 libweston: Send seat name before announcing devices
Clients need to know the seat name at the time they create mouse and
keyboard objects. This brings Weston in line with other compositors.

The documentation upstream currently is not super clear. It states name
is explicitly sent on bind, capabilities don't mention being sent on
bind in any way.

Signed-off-by: David Edmundson <davidedmundson@kde.org>
(cherry picked from commit fe64eee3ae)
2024-10-11 13:30:01 +03:00
EatingSumo
efd6789934 libweston/screenshooter: Fix build when __builtin_clz is not available
Fix compilation error when `__builtin_clz` is not available by renaming variable 'u' to 'run'

Signed-off-by: Junyu Long <877730493@qq.com>
(cherry picked from commit 312c8bea66)
2024-10-11 13:29:51 +03:00
Jan Alexander Steffens (heftig)
32f5596178 libweston/noop-renderer: Check shm_buffer for NULL
Copy the check from the pixman renderer.

Fixes: https://gitlab.freedesktop.org/wayland/weston/-/issues/953
Signed-off-by: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
(cherry picked from commit 0e451e8dc3)
2024-10-11 13:28:48 +03:00
379 changed files with 24914 additions and 57853 deletions

View file

@ -1,6 +1,6 @@
# vim: set expandtab shiftwidth=2 tabstop=8 textwidth=0:
.templates_sha: &template_sha 32afe5644697e503af18a736587c8619fa036a72 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
.templates_sha: &template_sha 184ca628f89f3193c249b4e34e45afee2773a833 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
# This file uses the freedesktop ci-templates to build Weston and run our
# tests in CI.
#
@ -43,7 +43,7 @@
variables:
FDO_UPSTREAM_REPO: wayland/weston
FDO_REPO_SUFFIX: "$BUILD_OS-$FDO_DISTRIBUTION_VERSION/$BUILD_ARCH"
FDO_DISTRIBUTION_TAG: '2026-04-01-mesa-26.0.4'
FDO_DISTRIBUTION_TAG: '2024-08-14-00-freerdp3.x'
include:
@ -66,11 +66,6 @@ include:
# we need a default case though, so all the rest still run
- when: on_success
default:
retry:
max: 2
when: runner_system_failure
.merge-rules:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
@ -84,7 +79,7 @@ stages:
- "Pre Base container"
- "Base container"
- "Full build and test"
- "No-GL/Vulkan build and test"
- "No-GL build and test"
- "Other builds"
- pages
@ -93,23 +88,20 @@ stages:
.os-debian-lts:
variables:
BUILD_OS: debian
LLVM_VERSION: 15
USE_DEBIAN_BACKPORTS: y
PACKAGES_SPECIFIC: vulkan-validationlayers-dev
LLVM_VERSION: 11
FREERDP_VERSION: 2
FDO_DISTRIBUTION_VERSION: bookworm
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} PACKAGES_SPECIFIC="${PACKAGES_SPECIFIC}" bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_VERSION: bullseye
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} bash .gitlab-ci/debian-install.sh'
.os-debian:
variables:
BUILD_OS: debian
LLVM_VERSION: 19
LLVM_VERSION: 15
FREERDP_VERSION: 3
USE_DEBIAN_BACKPORTS: y
PACKAGES_SPECIFIC: vulkan-utility-libraries-dev libpolly-19-dev libclang-rt-19-dev python3-standard-imghdr
# If you upgrade from trixie, see the use_tls=0 notes in tests/meson.build.
FDO_DISTRIBUTION_VERSION: trixie
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} PACKAGES_SPECIFIC="${PACKAGES_SPECIFIC}" bash .gitlab-ci/debian-install.sh'
USE_BOOKWORM_BACKPORTS: y
# If you upgrade from bookworm, see the use_tls=0 notes in tests/meson.build.
FDO_DISTRIBUTION_VERSION: bookworm
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} bash .gitlab-ci/debian-install.sh'
# Does not inherit .default-rules as we only want it to run in MR context.
check-commit:
@ -119,6 +111,7 @@ check-commit:
stage: "Merge request checks"
script:
- ci-fairy check-commits --signed-off-by --junit-xml=results.xml
- ci-fairy check-merge-request --require-allow-collaboration --junit-xml=results.xml
variables:
GIT_DEPTH: 100
artifacts:
@ -146,14 +139,12 @@ check-commit:
- .os-debian-lts
variables:
BUILD_ARCH: "armv7"
FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7"
.debian-armv7:
extends:
- .os-debian
variables:
BUILD_ARCH: "armv7"
FDO_DISTRIBUTION_PLATFORM: "linux/arm/v7"
# Armv7 doesn't have freerdp3 in bookworm-backports so we don't build FreeRDP
MESON_DIST_OPTIONS: "-Dbackend-rdp=false"
# Inhibit installation of freerdp-dev
@ -220,6 +211,8 @@ armv7-debian-lts-container_prep:
- .fdo.container-build@debian
tags:
- aarch64
variables:
FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
needs:
- job: base-container-pre
timeout: 30m
@ -232,6 +225,8 @@ armv7-debian-container_prep:
- .fdo.container-build@debian
tags:
- aarch64
variables:
FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
needs:
- job: base-container-pre
timeout: 30m
@ -267,23 +262,17 @@ aarch64-debian-container_prep:
timeout: 15m
variables:
BUILDDIR: $CI_PROJECT_DIR/build-weston-$CI_JOB_NAME
BUILDDIR_WESTINY: $CI_PROJECT_DIR/build-westiny-$CI_JOB_NAME
PREFIX: $CI_PROJECT_DIR/prefix-weston-$CI_JOB_NAME
PREFIX_WESTINY: $CI_PROJECT_DIR/prefix-westiny-$CI_JOB_NAME
before_script:
- export PATH=~/.local/bin:$PATH
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export TESTS_RES_PATH="$BUILDDIR/tests-res.txt"
- export VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation
- mkdir "$BUILDDIR" "$PREFIX"
- mkdir "$BUILDDIR_WESTINY" "$PREFIX_WESTINY"
.build-with-clang:
variables:
CC: clang-$LLVM_VERSION
CC_LD: lld-$LLVM_VERSION
CXX: clang++-$LLVM_VERSION
CXX_LD: lld-$LLVM_VERSION
MESON_TOOLCHAIN_OPTIONS: "$MESON_OPTIONS -Db_lundef=false" # clang+ASan+undef=boom
# Extends the core build templates to also provide for running our testing. We
@ -292,12 +281,18 @@ aarch64-debian-container_prep:
.build-and-test:
extends:
- .default-rules
variables:
SANITIZE: "-Db_sanitize=address"
script:
- "${CI_PROJECT_DIR}/.gitlab-ci/build.sh"
- "${CI_PROJECT_DIR}/.gitlab-ci/test.sh"
- cd "$BUILDDIR"
- meson --prefix="$PREFIX" --wrap-mode=nofallback -Db_sanitize=address ${MESON_OPTIONS} ${MESON_TOOLCHAIN_OPTIONS} ${MESON_DIST_OPTIONS} ..
- ninja -k0 -j${FDO_CI_CONCURRENT:-4}
- ninja install
- test -n "${QEMU_SMP}" || QEMU_SMP=${FDO_CI_CONCURRENT:-4}
- virtme-run --rw --pwd --kimg /weston-virtme/${KERNEL_IMAGE} --kopt quiet --kopt log_buf_len=2M --script-sh ../.gitlab-ci/virtme-scripts/run-weston-tests.sh --qemu-opts -m 4096 -smp ${QEMU_SMP}
- TEST_RES=$(cat $TESTS_RES_PATH)
- rm $TESTS_RES_PATH
- cp -R /weston-virtme ./
- rm weston-virtme/${KERNEL_IMAGE}
- exit $TEST_RES
artifacts:
name: weston-$CI_COMMIT_SHA
when: always
@ -308,14 +303,18 @@ aarch64-debian-container_prep:
- $BUILDDIR/weston-virtme
- $PREFIX
reports:
junit: $BUILDDIR/meson-logs/testlog.junit.xml
junit: $BUILDDIR/meson-logs/testlog-junit.xml
# Same as above, but without running any tests.
.build-no-test:
extends:
- .default-rules
script:
- "${CI_PROJECT_DIR}/.gitlab-ci/build.sh"
- cd "$BUILDDIR"
- meson --prefix="$PREFIX" --wrap-mode=nofallback ${MESON_OPTIONS} ${MESON_DIST_OPTIONS} ..
- ninja -k0 -j${FDO_CI_CONCURRENT:-4}
- ninja install
- ninja clean
artifacts:
name: weston-$CI_COMMIT_SHA
when: always
@ -426,81 +425,67 @@ aarch64-debian-container_prep:
- job: aarch64-debian-container_prep
artifacts: false
# Full build (gcov + perfetto) used for testing under KVM.
# Full build, used for testing under KVM.
.build-options-full:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Db_coverage=true
--force-fallback-for=perfetto
-Dperfetto=true
-Dperfetto:werror=false
-Dwerror=true
-Dtest-skip-is-failure=true
-Ddeprecated-remoting=true
-Ddeprecated-pipewire=true
after_script:
- ninja -C "$BUILDDIR" coverage-html > "$BUILDDIR/meson-logs/ninja-coverage-html.txt"
- ninja -C "$BUILDDIR" coverage-xml
# Full build, (without gcov and perfetto)
.build-options-full-v2:
stage: "Full build and test"
variables:
MESON_OPTIONS: >
-Doptimization=0
-Dwerror=true
-Dtest-skip-is-failure=true
x86_64-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-full
x86_64-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-options-full
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: $BUILDDIR/meson-logs/coverage.xml
x86_64-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-options-full-v2
aarch64-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-full-v2
- .build-options-full
aarch64-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-options-full-v2
- .build-options-full
x86_64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-x86_64
- .build-with-clang
- .build-options-full-v2
- .build-options-full
x86_64-clang-debian-full-build:
extends:
- .test-env-debian-x86_64
- .build-with-clang
- .build-options-full-v2
- .build-options-full
aarch64-clang-debian-lts-full-build:
extends:
- .test-env-debian-lts-aarch64
- .build-with-clang
- .build-options-full-v2
- .build-options-full
aarch64-clang-debian-full-build:
extends:
- .test-env-debian-aarch64
- .build-with-clang
- .build-options-full-v2
- .build-options-full
# Docs should be invariant on all architectures, so we only do it on Debian
# x86-64.
@ -514,88 +499,62 @@ docs-build:
- .build-env-debian-x86_64
- .build-no-test
# Building without gl-renderer and/or vulkan-renderer, to make sure this keeps working.
.build-options-no-gl-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Drenderer-vulkan=false
-Dwerror=true
# Building without gl-renderer, to make sure this keeps working.
.build-options-no-gl:
stage: "No-GL/Vulkan build and test"
stage: "No-GL build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-gl=false
-Dremoting=false
-Dpipewire=false
-Dwerror=true
.build-options-no-vulkan:
stage: "No-GL/Vulkan build and test"
variables:
MESON_OPTIONS: >
-Dsimple-clients=damage,im,shm,touch,dmabuf-v4l
-Drenderer-vulkan=false
-Dwerror=true
x86_64-debian-lts-no-gl-no-vulkan-build:
x86_64-debian-lts-no-gl-build:
extends:
- .test-env-debian-lts-x86_64
- .build-options-no-gl-no-vulkan
x86_64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl-no-vulkan
armv7-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-lts-no-gl-no-vulkan-build:
extends:
- .build-env-debian-lts-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
armv7-clang-debian-no-gl-no-vulkan-build:
extends:
- .build-env-debian-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl-no-vulkan
aarch64-debian-lts-no-gl-no-vulkan-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-no-gl-no-vulkan
aarch64-debian-no-gl-no-vulkan-build:
extends:
- .test-env-debian-aarch64
- .build-options-no-gl-no-vulkan
- .build-options-no-gl
x86_64-debian-no-gl-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-gl
x86_64-debian-no-vulkan-build:
armv7-debian-lts-no-gl-build:
extends:
- .test-env-debian-x86_64
- .build-options-no-vulkan
- .build-env-debian-lts-armv7
- .build-no-test
- .build-options-no-gl
armv7-debian-no-gl-build:
extends:
- .build-env-debian-armv7
- .build-no-test
- .build-options-no-gl
armv7-clang-debian-lts-no-gl-build:
extends:
- .build-env-debian-lts-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl
armv7-clang-debian-no-gl-build:
extends:
- .build-env-debian-armv7
- .build-with-clang
- .build-no-test
- .build-options-no-gl
aarch64-debian-lts-no-gl-build:
extends:
- .test-env-debian-lts-aarch64
- .build-options-no-gl
aarch64-debian-no-gl-build:
extends:
- .test-env-debian-aarch64
- .build-options-no-gl
# Expose docs and coverage reports, so we can show users any changes to these
# inside their merge requests, letting us check them before merge.
@ -607,18 +566,18 @@ x86_64-debian-no-vulkan-build:
docs-and-coverage:
extends:
- .default-rules
- .debian-lts-x86_64
- .debian-x86_64
- .fdo.suffixed-image@debian
stage: pages
needs:
- job: docs-build
artifacts: true
- job: x86_64-debian-lts-full-build
- job: x86_64-debian-full-build
artifacts: true
timeout: 5m
script:
- mv prefix-weston-docs-build/share/doc/weston Documentation
- mv build-weston-x86_64-debian-lts-full-build/meson-logs/coveragereport Test_Coverage
- mv build-weston-x86_64-debian-full-build/meson-logs/coveragereport Test_Coverage
- rm Test_Coverage/gcov.css
- cp doc/style/lcov-style.css Test_Coverage/gcov.css
- cp doc/style/*.png Test_Coverage/

View file

@ -4,8 +4,6 @@
# .gitlab-ci.yml for more information. This script is called from an
# OS-specific build scripts like debian-install.sh.
source "${FDO_CI_BASH_HELPERS}"
set -o xtrace -o errexit
# Set concurrency to an appropriate level for our shared runners, falling back
@ -27,8 +25,7 @@ esac
# Build and install Meson. Generally we want to keep this in sync with what
# we require inside meson.build.
fdo_log_section_start_collapsed install_meson "install_meson"
pip3 install $PIP_ARGS git+https://github.com/mesonbuild/meson.git@1.4.2
pip3 install $PIP_ARGS git+https://github.com/mesonbuild/meson.git@1.0.0
export PATH=$HOME/.local/bin:$PATH
# Our docs are built using Sphinx (top-level organisation and final HTML/CSS
@ -44,22 +41,31 @@ pip3 install $PIP_ARGS sphinxcontrib-qthelp==1.0.3
pip3 install $PIP_ARGS sphinxcontrib-serializinghtml==1.1.5
pip3 install $PIP_ARGS breathe==4.31.0
pip3 install $PIP_ARGS sphinx_rtd_theme==1.0.0
fdo_log_section_end install_meson
# Build a Linux kernel for use in testing. We enable the VKMS module so we can
# predictably test the DRM backend in the absence of real hardware. We lock the
# version here so we see predictable results.
#
# To run this we use virtme-ng, a QEMU wrapper. It is a fork from virtme, whose
# development stalled.
# To run this we use virtme, a QEMU wrapper: https://github.com/amluto/virtme
#
# virtme-ng makes our lives easier by abstracting handling of the console,
# virtme makes our lives easier by abstracting handling of the console,
# filesystem, etc, so we can pretend that the VM we execute in is actually
# just a regular container.
fdo_log_section_start_collapsed install_kernel "install_kernel"
#
# The reason why we are using a fork here is that it adds a patch to have the
# --script-dir command line option. With that we can run scripts that are in a
# certain folder when virtme starts, which is necessary in our use case.
#
# The upstream also has some commands that could help us to reach the same
# results: --script-sh and --script-exec. Unfornutately they are not completely
# implemented yet, so we had some trouble to use them and it was becoming
# hackery.
#
# The fork pulls in this support from the original GitHub PR, rebased on top of
# a newer upstream version which fixes AArch64 support.
if [[ -n "$KERNEL_DEFCONFIG" ]]; then
git clone --depth=1 --branch drm-misc-next-2026-03-20 https://gitlab.freedesktop.org/drm/misc/kernel.git linux
# 6.3 is (still) used as >= 6.5 drm-writeback test will timeout
git clone --depth=1 --branch=v6.3 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux
cd linux
if [[ "${BUILD_ARCH}" = "x86-64" ]]; then
@ -85,8 +91,9 @@ if [[ -n "$KERNEL_DEFCONFIG" ]]; then
./scripts/config \
--enable CONFIG_DRM \
--enable CONFIG_DRM_KMS_HELPER \
--enable CONFIG_DRM_KMS_FB_HELPER \
--enable CONFIG_DRM_VKMS \
--enable CONFIG_UDMABUF
--enable CONFIG_DRM_VGEM
make ARCH=${LINUX_ARCH} oldconfig
make ARCH=${LINUX_ARCH}
@ -101,15 +108,14 @@ if [[ -n "$KERNEL_DEFCONFIG" ]]; then
./setup.py install
cd ..
fi
fdo_log_section_end install_kernel
# Build and install Wayland; keep this version in sync with our dependency
# in meson.build.
fdo_log_section_start_collapsed install_wayland "install_wayland"
git clone --branch 1.22.0 --depth=1 https://gitlab.freedesktop.org/wayland/wayland
cd wayland
git show -s HEAD
meson setup build --wrap-mode=nofallback -Ddocumentation=false
mkdir build
meson build --wrap-mode=nofallback -Ddocumentation=false
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf wayland
@ -117,39 +123,24 @@ rm -rf wayland
# Keep this version in sync with our dependency in meson.build. If you wish to
# raise a MR against custom protocol, please change this reference to clone
# your relevant tree, and make sure you bump $FDO_DISTRIBUTION_TAG.
git clone --branch 1.46 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
git clone --branch 1.33 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
cd wayland-protocols
git show -s HEAD
meson setup build --wrap-mode=nofallback -Dtests=false
meson build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf wayland-protocols
fdo_log_section_end install_wayland
# Build and install our own version of libdrm. Debian 11 (bullseye) provides
# libdrm 2.4.104 which doesn't have the IN_FORMATS iterator api, and Mesa
# depends on 2.4.109 as well.
# Bump to 2.4.118 to include DRM_FORMAT_NV{15,20,30}
fdo_log_section_start_collapsed install_libdrm "install_libdrm"
git clone --branch libdrm-2.4.118 --depth=1 https://gitlab.freedesktop.org/mesa/drm.git
git clone --branch libdrm-2.4.109 --depth=1 https://gitlab.freedesktop.org/mesa/drm.git
cd drm
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
-Dvc4=disabled -Dfreedreno=disabled -Detnaviv=disabled
meson build --wrap-mode=nofallback -Dauto_features=disabled \
-Dvc4=false -Dfreedreno=false -Detnaviv=false
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf drm
fdo_log_section_end install_libdrm
# Build and install Vulkan-Headers with a defined version, mostly because
# the version in Debian 11 (bullseye) is too old to build vulkan-renderer.
fdo_log_section_start_collapsed install_vulkan_headers "install_vulkan_headers"
git clone --branch sdk-1.3.239.0 --depth=1 https://github.com/KhronosGroup/Vulkan-Headers
cd Vulkan-Headers
cmake -G Ninja -B build
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf Vulkan-Headers
fdo_log_section_end install_vulkan_headers
# Build and install our own version of Mesa. Debian provides a perfectly usable
# Mesa, however llvmpipe's rendering behaviour can change subtly over time.
@ -158,87 +149,64 @@ fdo_log_section_end install_vulkan_headers
# features from Mesa then bump this version and $FDO_DISTRIBUTION_TAG, however
# please be prepared for some of the tests to change output, which will need to
# be manually inspected for correctness.
fdo_log_section_start_collapsed install_mesa "install_mesa"
# Needed for Mesa >= 25.3
git clone --branch 12.2.0 --depth=1 https://github.com/KhronosGroup/glslang
cd glslang
cmake -G Ninja -B build
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf glslang
git clone --branch mesa-26.0.4 --depth=1 https://gitlab.freedesktop.org/mesa/mesa.git
git clone --branch 23.0 --depth=1 https://gitlab.freedesktop.org/mesa/mesa.git
cd mesa
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
-Dgallium-drivers=llvmpipe -Dvulkan-drivers=swrast -Dvideo-codecs= \
-Degl=enabled -Dgbm=enabled -Dgles2=enabled -Dllvm=enabled \
-Dshared-glapi=enabled -Dglx=disabled
meson build --wrap-mode=nofallback -Dauto_features=disabled \
-Dgallium-drivers=swrast -Dvulkan-drivers= -Ddri-drivers=
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf mesa
fdo_log_section_end install_mesa
# PipeWire is used for remoting support. Unlike our other dependencies its
# behaviour will be stable, however as a pre-1.0 project its API is not yet
# stable, so again we lock it to a fixed version.
#
# ... the version chosen is 0.3.32 with a small Clang-specific build fix.
fdo_log_section_start_collapsed install_pipewire "install_pipewire"
git clone --single-branch --branch master https://gitlab.freedesktop.org/pipewire/pipewire.git pipewire-src
cd pipewire-src
git checkout -b snapshot bf112940d0bf8f526dd6229a619c1283835b49c2
meson setup build --wrap-mode=nofallback
meson build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf pipewire-src
fdo_log_section_end install_pipewire
# seatd lets us avoid the pain of open-coding TTY assignment within Weston.
# We use this for our tests using the DRM backend.
fdo_log_section_start_collapsed install_seatd "install_seatd"
git clone --depth=1 --branch 0.6.1 https://git.sr.ht/~kennylevinsen/seatd
cd seatd
meson setup build --wrap-mode=nofallback -Dauto_features=disabled \
meson build --wrap-mode=nofallback -Dauto_features=disabled \
-Dlibseat-seatd=enabled -Dlibseat-logind=systemd -Dserver=enabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf seatd
fdo_log_section_end install_seatd
# Build and install aml and neatvnc, which are required for the VNC backend
fdo_log_section_start_collapsed install_aml_neatvnc "install_aml_neatvnc"
git clone --branch v0.3.0 --depth=1 https://github.com/any1/aml.git
cd aml
meson setup build --wrap-mode=nofallback
meson build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf aml
git clone --branch v0.7.0 --depth=1 https://github.com/any1/neatvnc.git
cd neatvnc
meson setup build --wrap-mode=nofallback -Dauto_features=disabled
meson build --wrap-mode=nofallback -Dauto_features=disabled
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf neatvnc
fdo_log_section_end install_aml_neatvnc
# Build and install libdisplay-info, used by drm-backend
fdo_log_section_start_collapsed install_libdisplay-info "install_libdisplay-info"
git clone --branch 0.2.0 --depth=1 https://gitlab.freedesktop.org/emersion/libdisplay-info.git
git clone --branch 0.1.1 --depth=1 https://gitlab.freedesktop.org/emersion/libdisplay-info.git
cd libdisplay-info
meson setup build --wrap-mode=nofallback
meson build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf libdisplay-info
fdo_log_section_end install_libdisplay-info
# Build and install lcms2, which we use to support color-management.
fdo_log_section_start_collapsed install_lcms2 "install_lcms2"
git clone --branch master https://github.com/mm2/Little-CMS.git lcms2
cd lcms2
git checkout -b snapshot lcms2.16
meson setup build --wrap-mode=nofallback
meson build --wrap-mode=nofallback
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf lcms2
fdo_log_section_end install_lcms2

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -xe
source "${FDO_CI_BASH_HELPERS}"
fdo_log_section_start_collapsed build_weston "build_weston"
cd "$BUILDDIR"
meson --prefix="$PREFIX" --wrap-mode=nofallback $SANITIZE ${MESON_OPTIONS} ${MESON_TOOLCHAIN_OPTIONS} ${MESON_DIST_OPTIONS} ..
ninja -k0 -j${FDO_CI_CONCURRENT:-4}
ninja install
if [ "$CI_JOB_NAME" == "x86_64-debian-full-build" ]; then
cd "$BUILDDIR_WESTINY"
export NPREFIX=$CI_PROJECT_DIR/prefix-weston-$CI_JOB_NAME
export PKG_CONFIG_PATH=$NPREFIX/lib/pkgconfig/:$NPREFIX/share/pkgconfig/:$NPREFIX/lib/x86_64-linux-gnu/pkgconfig:$PKG_CONFIG_PATH
meson setup --prefix="$PREFIX_WESTINY" --wrap-mode=nofallback ../westinyplus/
ninja -k0 -j${FDO_CI_CONCURRENT:-4}
ninja install
ninja clean
cd -
fi
fdo_log_section_end build_weston

View file

@ -26,22 +26,14 @@ MESA_DEV_PKGS="
python3-mako
"
# These get temporarily installed for other build dependencies and then
# force-removed.
# cmake is used by Vulkan-Headers
BUILD_DEV_PKGS="
cmake
"
# Needed for running the custom-built mesa
MESA_RUNTIME_PKGS="
libllvm${LLVM_VERSION}
"
if [ x"$USE_DEBIAN_BACKPORTS" = "xy" ] ; then
echo 'deb http://deb.debian.org/debian '${FDO_DISTRIBUTION_VERSION}'-backports main' >> /etc/apt/sources.list
if [ x"$USE_BOOKWORM_BACKPORTS" = "xy" ] ; then
echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list
fi
apt-get update
apt-get -y --no-install-recommends install \
autoconf \
@ -53,7 +45,6 @@ apt-get -y --no-install-recommends install \
graphviz \
gcovr \
git \
glslang-tools \
hwdata \
lcov \
libasound2-dev \
@ -68,7 +59,7 @@ apt-get -y --no-install-recommends install \
libexpat1-dev \
libffi-dev \
libgbm-dev \
libgdk-pixbuf-xlib-2.0-dev \
libgdk-pixbuf2.0-dev \
libgles2-mesa-dev \
libglu1-mesa-dev \
libgstreamer1.0-dev \
@ -77,7 +68,6 @@ apt-get -y --no-install-recommends install \
libjack-jackd2-dev \
libjpeg-dev \
libjpeg-dev \
liblua5.4-dev \
libmtdev-dev \
libpam0g-dev \
libpango1.0-dev \
@ -132,9 +122,7 @@ apt-get -y --no-install-recommends install \
cargo rustc \
iproute2 udev \
$MESA_DEV_PKGS \
$BUILD_DEV_PKGS \
$MESA_RUNTIME_PKGS \
$PACKAGES_SPECIFIC \
$LINUX_DEV_PKGS \
if [ "$FREERDP_VERSION" -ne 0 ] ; then
@ -147,4 +135,4 @@ fi
# And remove packages which are only required for our build dependencies,
# which we don't need bloating the image whilst we build and run Weston.
apt-get -y --autoremove purge $LINUX_DEV_PKGS $MESA_DEV_PKGS $BUILD_DEV_PKGS
apt-get -y --autoremove purge $LINUX_DEV_PKGS $MESA_DEV_PKGS

View file

@ -11,16 +11,3 @@ leak:wl_shm_buffer_begin_access
leak:g_malloc0
leak:sysprof_collector_get
leak:/ld-*.so*
# Add all of perfetto, since it's not easy to clean up after it
leak:perfetto
# lavapipe inexplicably leaks when Vulkan physical devices are enumerated,
# despite us a) not using that device and b) freeing the instance. This is
# apparently a known issue. (Also when ASan creates threads ...)
leak:vkEnumeratePhysicalDevices
leak:asan_thread_start
# glib/pangoft for Trixie update
leak:libpangoft2
leak:libglib

View file

@ -1,13 +0,0 @@
#!/bin/bash
set -xe
source "${FDO_CI_BASH_HELPERS}"
cd "$BUILDDIR"
test -n "${QEMU_SMP}" || QEMU_SMP=${FDO_CI_CONCURRENT:-4}
virtme-run --rw --pwd --kimg /weston-virtme/${KERNEL_IMAGE} --kopt quiet --kopt log_buf_len=2M --script-sh ../.gitlab-ci/virtme-scripts/run-weston-tests.sh --qemu-opts -m 4096 -smp ${QEMU_SMP}
TEST_RES=$(cat $TESTS_RES_PATH)
rm $TESTS_RES_PATH
cp -R /weston-virtme ./
rm weston-virtme/${KERNEL_IMAGE}
exit $TEST_RES

View file

@ -12,7 +12,10 @@ export LIBSEAT_BACKEND=seatd
# devices are loaded is not predictable, so the DRM node that VKMS takes can
# change across each boot. That's why we have this one-liner shell script to get
# the appropriate node for VKMS.
export WESTON_TEST_SUITE_DRM_DEVICE=$(basename /sys/bus/faux/devices/vkms/drm/card*)
export WESTON_TEST_SUITE_DRM_DEVICE=$(basename /sys/devices/platform/vkms/drm/card*)
# To run tests in the CI that exercise the zwp_linux_dmabuf_v1 implementation in
# Weston, we use VGEM to allocate buffers.
export WESTON_TEST_SUITE_ALLOC_DEVICE=$(basename /sys/devices/platform/vgem/drm/card*)
# ninja test depends on meson, and meson itself looks for its modules on folder
# $HOME/.local/lib/pythonX.Y/site-packages (the Python version may differ).
@ -23,11 +26,11 @@ export HOME=/root
export PATH=$HOME/.local/bin:$PATH
export PATH=/usr/local/bin:$PATH
export SEATD_LOGLEVEL=debug
# Terrible hack, per comment in weston-test-runner.c's main(): find Mesa's
# llvmpipe/lavapipe driver module location
export WESTON_CI_LEAK_DL_HANDLES=$(find /usr/local -name swrast_dri.so -print 2>/dev/null || true):
export WESTON_CI_LEAK_DL_HANDLES=$WESTON_CI_LEAK_DL_HANDLES:$(find /usr/local -name libvulkan_lvp.so -print 2>/dev/null || true)
export WESTON_CI_LEAK_DL_HANDLES=$WESTON_CI_LEAK_DL_HANDLES:$(find /usr/local -name libgallium\*.so -print 2>/dev/null || true)
# llvmpipe driver module location
export WESTON_CI_LEAK_DL_HANDLE=$(find /usr/local -name swrast_dri.so -print 2>/dev/null || true)
# run the tests and save the exit status
# we give ourselves a very generous timeout multiplier due to ASan overhead

View file

@ -117,11 +117,11 @@ finish_calibration (struct calibrator *calibrator)
*/
memset(&m, 0, sizeof(m));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
m.M.col[0].el[i] = calibrator->tests[i].clicked_x;
m.M.col[1].el[i] = calibrator->tests[i].clicked_y;
m.M.col[2].el[i] = 1;
m.d[i] = calibrator->tests[i].clicked_x;
m.d[i + 4] = calibrator->tests[i].clicked_y;
m.d[i + 8] = 1;
}
m.M.col[3].el[3] = 1;
m.d[15] = 1;
weston_matrix_invert(&inverse, &m);
@ -129,8 +129,8 @@ finish_calibration (struct calibrator *calibrator)
memset(&y_calib, 0, sizeof(y_calib));
for (i = 0; i < (int)ARRAY_LENGTH(test_ratios); i++) {
x_calib.v.el[i] = calibrator->tests[i].drawn_x;
y_calib.v.el[i] = calibrator->tests[i].drawn_y;
x_calib.f[i] = calibrator->tests[i].drawn_x;
y_calib.f[i] = calibrator->tests[i].drawn_y;
}
/* Multiples into the vector */
@ -138,8 +138,8 @@ finish_calibration (struct calibrator *calibrator)
weston_matrix_transform(&inverse, &y_calib);
printf ("Calibration values: %f %f %f %f %f %f\n",
x_calib.v.el[0], x_calib.v.el[1], x_calib.v.el[2],
y_calib.v.el[0], y_calib.v.el[1], y_calib.v.el[2]);
x_calib.f[0], x_calib.f[1], x_calib.f[2],
y_calib.f[0], y_calib.f[1], y_calib.f[2]);
exit(0);
}

View file

@ -1,610 +0,0 @@
/*
* Copyright (C) 2024 SUSE Software Solutions Germany GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include "color-management-v1-client-protocol.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "window.h"
enum image_description_status {
IMAGE_DESCRIPTION_NOT_CREATED = 0,
IMAGE_DESCRIPTION_READY,
IMAGE_DESCRIPTION_FAILED,
};
struct pixel_color {
uint32_t r;
uint32_t g;
uint32_t b;
uint32_t a;
};
struct color {
struct display *display;
struct window *window;
struct widget *parent_widget;
struct widget *widget;
struct wp_color_manager_v1 *color_manager;
struct wp_color_management_surface_v1 *color_surface;
struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager;
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct pixel_color pixel_color;
bool unmanaged;
enum wp_color_manager_v1_primaries primaries;
enum wp_color_manager_v1_transfer_function transfer_function;
float min_lum;
float max_lum;
float ref_lum;
uint32_t supported_color_features;
uint32_t supported_rendering_intents;
uint32_t supported_primaries_named;
uint32_t supported_tf_named;
};
struct valid_enum {
const char *name;
uint32_t value;
};
static bool opt_help = false;
static uint32_t opt_width = 250;
static uint32_t opt_height = 250;
static const char *opt_r = NULL;
static const char *opt_g = NULL;
static const char *opt_b = NULL;
static const char *opt_a = NULL;
static bool opt_unmanaged = false;
static const char *opt_primaries = NULL;
static const char *opt_transfer_function = NULL;
static const char *opt_min_lum = NULL;
static const char *opt_max_lum = NULL;
static const char *opt_ref_lum = NULL;
static const struct weston_option cli_options[] = {
{ WESTON_OPTION_BOOLEAN, "help", 0, &opt_help },
{ WESTON_OPTION_UNSIGNED_INTEGER, "width", 'w', &opt_width },
{ WESTON_OPTION_UNSIGNED_INTEGER, "height", 'h', &opt_height },
{ WESTON_OPTION_STRING, 0, 'R', &opt_r },
{ WESTON_OPTION_STRING, 0, 'G', &opt_g },
{ WESTON_OPTION_STRING, 0, 'B', &opt_b },
{ WESTON_OPTION_STRING, 0, 'A', &opt_a },
{ WESTON_OPTION_BOOLEAN, "unmanaged", 'u', &opt_unmanaged },
{ WESTON_OPTION_STRING, "primaries", 'p', &opt_primaries },
{ WESTON_OPTION_STRING, "transfer-function", 't', &opt_transfer_function },
{ WESTON_OPTION_STRING, "min-lum", 'm', &opt_min_lum },
{ WESTON_OPTION_STRING, "max-lum", 'M', &opt_max_lum },
{ WESTON_OPTION_STRING, "ref-lum", 'r', &opt_ref_lum },
};
static const struct valid_enum valid_primaries[] = {
{ "srgb", WP_COLOR_MANAGER_V1_PRIMARIES_SRGB },
{ "bt2020", WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 },
};
static const struct valid_enum valid_transfer_functions[] = {
{ "srgb", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB },
{ "pq", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ },
{ "linear", WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR },
};
static bool
validate_color(const char *c, uint32_t *dest, uint32_t fallback)
{
char *end;
double value;
if (!c) {
*dest = fallback;
return true;
}
value = strtod(c, &end);
if (value < 0.0 || value > 1.0 || *end != '\0') {
fprintf(stderr, "Validating color failed, it should be between 0.0 and 1.0\n");
return false;
}
*dest = value * UINT32_MAX;
return true;
}
static bool
validate_option(const struct color *color,
const char *option, uint32_t *dest,
const struct valid_enum *valid_options,
int count, uint32_t fallback)
{
int i;
if (color->unmanaged && option) {
fprintf(stderr, "Option '%s' not valid in unmanaged mode\n", option);
return false;
}
if (!option) {
*dest = fallback;
return true;
}
for (i = 0; i < count; i++) {
if (strcmp(valid_options[i].name, option) == 0) {
*dest = valid_options[i].value;
return true;
}
}
fprintf(stderr, "Validating option '%s' failed, valid options:\n", option);
for (i = 0; i < count; i++)
fprintf(stderr, "'%s' ", valid_options[i].name);
fprintf(stderr, "\n");
return false;
}
static bool
validate_luminance(const struct color *color,
const char *c, float *dest, float fallback)
{
char *end;
float value;
if (color->unmanaged && c) {
fprintf(stderr, "Luminance not valid in unmanaged mode.\n");
return false;
}
if (!c) {
*dest = fallback;
return true;
}
value = strtof(c, &end);
if (value < 0.f || value > 10000.f || *end != '\0') {
fprintf(stderr, "Validating luminance failed, it should be between 0 and 10,000\n");
return false;
}
*dest = value;
return true;
}
static bool
validate_options(struct color *color)
{
color->unmanaged = opt_unmanaged;
return validate_color(opt_r, &color->pixel_color.r, 0) &&
validate_color(opt_g, &color->pixel_color.g, 0) &&
validate_color(opt_b, &color->pixel_color.b, 0) &&
validate_color(opt_a, &color->pixel_color.a, UINT32_MAX) &&
validate_option(color, opt_primaries, &color->primaries,
valid_primaries,
ARRAY_LENGTH(valid_primaries),
WP_COLOR_MANAGER_V1_PRIMARIES_SRGB) &&
validate_option(color, opt_transfer_function, &color->transfer_function,
valid_transfer_functions,
ARRAY_LENGTH(valid_transfer_functions),
WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB) &&
validate_luminance(color, opt_min_lum, &color->min_lum, -1.f) &&
validate_luminance(color, opt_max_lum, &color->max_lum, -1.f) &&
validate_luminance(color, opt_ref_lum, &color->ref_lum, -1.f);
}
static void
usage(const char *program_name, int exit_code)
{
unsigned int i;
fprintf(stderr, "Usage: %s [OPTIONS]\n", program_name);
fprintf(stderr, " --help\n");
fprintf(stderr, " --width or -w\n");
fprintf(stderr, " --height or -h\n");
fprintf(stderr, " -R (0.0 to 1.0)\n");
fprintf(stderr, " -G (0.0 to 1.0)\n");
fprintf(stderr, " -B (0.0 to 1.0)\n");
fprintf(stderr, " -A (0.0 to 1.0)\n");
fprintf(stderr, " Mode of operation may be:\n");
fprintf(stderr, " --unmanaged or -u: do not use color-management\n");
fprintf(stderr, " Or use the following:\n");
fprintf(stderr, " --primaries or -p:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_primaries); i++)
fprintf(stderr, " '%s'", valid_primaries[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --transfer-function or -t:");
fprintf(stderr, "\n ");
for (i = 0; i < ARRAY_LENGTH(valid_transfer_functions); i++)
fprintf(stderr, " '%s'", valid_transfer_functions[i].name);
fprintf(stderr, "\n");
fprintf(stderr, " --min-lum or -m (0.0 to 10000.0)\n");
fprintf(stderr, " --max-lum or -M (0.0 to 10000.0)\n");
fprintf(stderr, " --ref-lum or -r (0.0 to 10000.0)\n");
exit(exit_code);
}
static void
supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t render_intent)
{
struct color *color = data;
color->supported_rendering_intents |= 1 << render_intent;
}
static void
supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t feature)
{
struct color *color = data;
color->supported_color_features |= 1 << feature;
}
static void
supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t tf)
{
struct color *color = data;
color->supported_tf_named |= 1 << tf;
}
static void
supported_primaries_named(void *data,
struct wp_color_manager_v1 *wp_color_manager_v1,
uint32_t primaries)
{
struct color *color = data;
color->supported_primaries_named |= 1 << primaries;
}
static void
done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1)
{
}
static const struct wp_color_manager_v1_listener color_manager_listener = {
supported_intent,
supported_feature,
supported_tf_named,
supported_primaries_named,
done,
};
static void
global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct color *color = data;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
if (strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) {
color->single_pixel_manager =
display_bind(display, name,
&wp_single_pixel_buffer_manager_v1_interface, 1);
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
color->viewporter = display_bind(display, name,
&wp_viewporter_interface, 1);
color->viewport = wp_viewporter_get_viewport(color->viewporter, surface);
}
if (color->unmanaged)
return;
if (strcmp(interface, wp_color_manager_v1_interface.name) == 0) {
color->color_manager = display_bind(display, name,
&wp_color_manager_v1_interface, 1);
color->color_surface = wp_color_manager_v1_get_surface(color->color_manager,
surface);
wp_color_manager_v1_add_listener(color->color_manager,
&color_manager_listener, color);
}
}
static bool
check_color_requirements(struct color *color)
{
if (!color->color_manager) {
fprintf(stderr, "The compositor doesn't expose %s\n",
wp_color_manager_v1_interface.name);
return false;
}
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC))) {
fprintf(stderr, "The color manager doesn't support the parametric creator\n");
return false;
}
if (!(color->supported_primaries_named & (1 << color->primaries))) {
fprintf(stderr, "The color manager doesn't support the primaries name\n");
return false;
}
if (!(color->supported_tf_named & (1 << color->transfer_function))) {
fprintf(stderr, "The color manager doesn't support the transfer function\n");
return false;
}
if (!(color->supported_rendering_intents & (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL))) {
fprintf(stderr, "The color manager doesn't support perceptual render intent\n");
return false;
}
if (color->min_lum != -1.f || color->max_lum != -1.f || color->ref_lum != -1.f) {
if (!(color->supported_color_features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES))) {
fprintf(stderr, "The color manager doesn't support setting luminances\n");
return false;
}
if (color->min_lum == -1.f || color->max_lum == -1.f || color->ref_lum == -1.f) {
fprintf(stderr, "To set the luminances it is required min-lum, max-lum and ref-lum\n");
return false;
}
}
return true;
}
static void
color_destroy(struct color *color)
{
if (color->color_surface)
wp_color_management_surface_v1_destroy(color->color_surface);
if (color->color_manager)
wp_color_manager_v1_destroy(color->color_manager);
if (color->single_pixel_manager)
wp_single_pixel_buffer_manager_v1_destroy(color->single_pixel_manager);
if (color->viewport)
wp_viewport_destroy(color->viewport);
if (color->viewporter)
wp_viewporter_destroy(color->viewporter);
if (color->widget)
widget_destroy(color->widget);
if (color->parent_widget)
widget_destroy(color->parent_widget);
if (color->window)
window_destroy(color->window);
if (color->display)
display_destroy(color->display);
free(color);
}
static void
resize_handler(struct widget *parent_widget, int32_t width, int32_t height, void *data)
{
struct color *color = data;
struct rectangle allocation;
struct wl_surface *surface = widget_get_wl_surface(color->widget);
struct wl_subsurface *subsurface = widget_get_wl_subsurface(color->widget);
widget_get_allocation(parent_widget, &allocation);
wl_subsurface_set_position(subsurface, allocation.x, allocation.y);
wp_viewport_set_destination(color->viewport, width, height);
wl_surface_commit(surface);
}
static void
set_empty_input_region(struct color *color, struct widget *widget)
{
struct wl_region *region;
struct wl_compositor *compositor;
struct wl_surface *surface = widget_get_wl_surface(widget);
compositor = display_get_compositor(color->display);
region = wl_compositor_create_region(compositor);
wl_surface_set_input_region(surface, region);
wl_region_destroy(region);
}
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void
set_single_pixel(struct color *color, struct widget *widget)
{
struct wl_surface *surface = widget_get_wl_surface(widget);
struct wl_buffer *buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(color->single_pixel_manager,
color->pixel_color.r,
color->pixel_color.g,
color->pixel_color.b,
color->pixel_color.a);
wl_buffer_add_listener(buffer, &buffer_listener, NULL);
wl_surface_attach(surface, buffer, 0, 0);
}
static void
image_description_failed(void *data,
struct wp_image_description_v1 *wp_image_description_v1,
uint32_t cause, const char *msg)
{
enum image_description_status *image_desc_status = data;
fprintf(stderr, "Failed to create image description: %u - %s\n",
cause, msg);
*image_desc_status = IMAGE_DESCRIPTION_FAILED;
}
static void
image_description_ready(void *data, struct wp_image_description_v1 *wp_image_description_v1,
uint32_t identity)
{
enum image_description_status *image_desc_status = data;
*image_desc_status = IMAGE_DESCRIPTION_READY;
}
static const struct wp_image_description_v1_listener image_description_listener = {
image_description_failed,
image_description_ready,
};
static struct wp_image_description_v1 *
create_image_description(struct color *color, uint32_t primaries_named, uint32_t tf_named)
{
struct wp_image_description_creator_params_v1 *params_creator;
struct wp_image_description_v1 *image_description;
enum image_description_status image_desc_status = IMAGE_DESCRIPTION_NOT_CREATED;
int ret = 0;
params_creator = wp_color_manager_v1_create_parametric_creator(color->color_manager);
wp_image_description_creator_params_v1_set_primaries_named(params_creator, primaries_named);
wp_image_description_creator_params_v1_set_tf_named(params_creator, tf_named);
if (color->min_lum != -1 && color->max_lum != -1 && color->ref_lum != -1)
wp_image_description_creator_params_v1_set_luminances(params_creator,
color->min_lum * 10000,
color->max_lum,
color->ref_lum);
image_description = wp_image_description_creator_params_v1_create(params_creator);
wp_image_description_v1_add_listener(image_description,
&image_description_listener,
&image_desc_status);
while (ret != -1 && image_desc_status == IMAGE_DESCRIPTION_NOT_CREATED)
ret = wl_display_dispatch(display_get_display(color->display));
if (ret == -1) {
wp_image_description_v1_destroy(image_description);
fprintf(stderr, "Error when creating the image description: %s\n", strerror(errno));
return NULL;
}
if (image_desc_status == IMAGE_DESCRIPTION_FAILED) {
wp_image_description_v1_destroy(image_description);
return NULL;
}
assert(image_desc_status == IMAGE_DESCRIPTION_READY);
return image_description;
}
static bool
set_image_description(struct color *color, struct widget *widget)
{
struct wp_image_description_v1 *image_description;
image_description =
create_image_description(color,
color->primaries,
color->transfer_function);
if (!image_description)
return false;
wp_color_management_surface_v1_set_image_description(
color->color_surface,
image_description,
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
wp_image_description_v1_destroy(image_description);
return true;
}
int
main(int argc, char *argv[])
{
struct color *color;
if (parse_options(cli_options, ARRAY_LENGTH(cli_options), &argc, argv) > 1)
usage(argv[0], EXIT_FAILURE);
if (opt_help)
usage(argv[0], EXIT_SUCCESS);
color = xzalloc(sizeof *color);
if (!validate_options(color)) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->display = display_create(&argc, argv);
if (!color->display) {
color_destroy(color);
exit(EXIT_FAILURE);
}
color->window = window_create(color->display);
color->parent_widget = window_frame_create(color->window, color);
color->widget = window_add_subsurface(color->window, color, SUBSURFACE_SYNCHRONIZED);
display_set_user_data(color->display, color);
display_set_global_handler(color->display, global_handler);
wl_display_roundtrip(display_get_display(color->display));
if (!color->unmanaged && !check_color_requirements(color)) {
color_destroy(color);
exit(EXIT_SUCCESS);
}
window_unset_shadow(color->window);
window_set_title(color->window, "Color");
window_set_appid(color->window, "org.freedesktop.weston.color");
/* The first resize call sets the min size,
* setting 0, 0 sets a default size */
window_schedule_resize(color->window, 0, 0);
window_schedule_resize(color->window, opt_width, opt_height);
widget_set_resize_handler(color->parent_widget, resize_handler);
widget_set_use_cairo(color->widget, 0);
set_empty_input_region(color, color->widget);
set_single_pixel(color, color->widget);
if (color->unmanaged || set_image_description(color, color->widget))
display_run(color->display);
color_destroy(color);
return 0;
}

View file

@ -53,7 +53,6 @@
#include "window.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "weston-desktop-shell-client-protocol.h"
@ -778,148 +777,95 @@ panel_add_launcher(struct panel *panel, const char *icon, const char *path, cons
enum {
BACKGROUND_SCALE,
BACKGROUND_SCALE_CROP,
BACKGROUND_SCALE_FIT,
BACKGROUND_TILE,
BACKGROUND_CENTERED
};
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
wl_buffer_destroy(buffer);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static void
background_draw(struct widget *widget, void *data)
{
struct background *background = data;
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
if (!background->image && background->color) {
struct display *display = window_get_display(background->window);
struct wp_single_pixel_buffer_manager_v1 *sp_manager;
struct wl_surface *wl_surface;
struct wl_buffer *wl_buffer;
uint32_t r8, g8, b8;
uint32_t r32, g32, b32;
surface = window_get_surface(background->window);
/* Single pixel buffer must use scale 1 */
window_set_buffer_scale(background->window, 1);
cr = widget_cairo_create(background->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
sp_manager = display_get_single_pixel_buffer_manager(display);
assert(sp_manager);
wl_surface = widget_get_wl_surface(background->widget);
assert(wl_surface);
widget_get_allocation(widget, &allocation);
image = NULL;
if (background->image)
image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
r8 = (background->color >> 16) & 0xff;
g8 = (background->color >> 8) & 0xff;
b8 = (background->color >> 0) & 0xff;
r32 = r8 << 24 | r8 << 16 | r8 << 8 | r8;
g32 = g8 << 24 | g8 << 16 | g8 << 8 | g8;
b32 = b8 << 24 | b8 << 16 | b8 << 8 | b8;
wl_buffer =
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(sp_manager,
r32,
g32,
b32,
0xffffffff);
assert(wl_buffer);
wl_surface_attach(wl_surface, wl_buffer, 0, 0);
wl_buffer_add_listener(wl_buffer, &buffer_listener, NULL);
widget_surface_flush(widget);
} else {
cairo_surface_t *surface, *image;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
cairo_t *cr;
double im_w, im_h;
double sx, sy, s;
double tx, ty;
struct rectangle allocation;
surface = window_get_surface(background->window);
cr = widget_cairo_create(background->widget);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
if (background->color == 0)
cairo_set_source_rgba(cr, 0.0, 0.0, 0.2, 1.0);
else
set_hex_color(cr, background->color);
cairo_paint(cr);
widget_get_allocation(widget, &allocation);
image = NULL;
if (background->image)
image = load_cairo_surface(background->image);
else if (background->color == 0) {
char *name = file_name_with_datadir("pattern.png");
image = load_cairo_surface(name);
free(name);
}
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
pattern = cairo_pattern_create_for_surface(image);
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
case BACKGROUND_SCALE_FIT:
if (background->type == BACKGROUND_SCALE_CROP)
s = (sx < sy) ? sx : sy;
else
s = (sx > sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
image = load_cairo_surface(name);
free(name);
}
if (image && background->type != -1) {
im_w = cairo_image_surface_get_width(image);
im_h = cairo_image_surface_get_height(image);
sx = im_w / allocation.width;
sy = im_h / allocation.height;
pattern = cairo_pattern_create_for_surface(image);
switch (background->type) {
case BACKGROUND_SCALE:
cairo_matrix_init_scale(&matrix, sx, sy);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_SCALE_CROP:
s = (sx < sy) ? sx : sy;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
break;
case BACKGROUND_TILE:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
case BACKGROUND_CENTERED:
s = (sx < sy) ? sx : sy;
if (s < 1.0)
s = 1.0;
/* align center */
tx = (im_w - s * allocation.width) * 0.5;
ty = (im_h - s * allocation.height) * 0.5;
cairo_matrix_init_translate(&matrix, tx, ty);
cairo_matrix_scale(&matrix, s, s);
cairo_pattern_set_matrix(pattern, &matrix);
break;
}
cairo_set_source(cr, pattern);
cairo_pattern_destroy (pattern);
cairo_surface_destroy(image);
cairo_mask(cr, pattern);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
background->painted = 1;
check_desktop_ready(background->window);
}
@ -946,7 +892,6 @@ background_configure(void *data,
}
if (!background->image && background->color) {
widget_set_use_cairo(background->widget, 0);
widget_set_viewport_destination(background->widget, width, height);
width = 1;
height = 1;
@ -1246,10 +1191,6 @@ background_create(struct desktop *desktop, struct output *output)
weston_config_section_get_color(s, "background-color",
&background->color, 0x00000000);
/* Backgrounds must be fully opaque. */
if (background->color != 0)
background->color |= 0xFF000000;
weston_config_section_get_string(s, "background-type",
&type, "tile");
if (type == NULL) {
@ -1261,8 +1202,6 @@ background_create(struct desktop *desktop, struct output *output)
background->type = BACKGROUND_SCALE;
} else if (strcmp(type, "scale-crop") == 0) {
background->type = BACKGROUND_SCALE_CROP;
} else if (strcmp(type, "scale-fit") == 0) {
background->type = BACKGROUND_SCALE_FIT;
} else if (strcmp(type, "tile") == 0) {
background->type = BACKGROUND_TILE;
} else if (strcmp(type, "centered") == 0) {
@ -1382,11 +1321,10 @@ output_handle_scale(void *data,
int32_t scale)
{
struct output *output = data;
struct background *background = output->background;
if (output->panel)
window_set_buffer_scale(output->panel->window, scale);
if (background && !background->color)
if (output->background)
window_set_buffer_scale(output->background->window, scale);
}

View file

@ -515,7 +515,7 @@ create_drag_source(struct dnd *dnd,
dnd_drag->drag_surface =
wl_compositor_create_surface(compositor);
if (dnd->self_only || display_get_data_device_manager_version(display) <
if (display_get_data_device_manager_version(display) <
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
/* Data sources version < 3 will not get action
* nor dnd_finished events, as we can't honor
@ -546,11 +546,11 @@ create_drag_source(struct dnd *dnd,
flower_mime_type);
wl_data_source_offer(dnd_drag->data_source,
text_mime_type);
}
if (display_get_data_device_manager_version(display) >=
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
wl_data_source_set_actions(dnd_drag->data_source, actions);
}
if (display_get_data_device_manager_version(display) >=
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION) {
wl_data_source_set_actions(dnd_drag->data_source, actions);
}
wl_data_device_start_drag(input_get_data_device(input),

View file

@ -346,7 +346,6 @@ usage(int error_code)
fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
" -w <width>\tSet window width to <width>\n"
" -h <height>\tSet window height to <height>\n"
" -f\t\tMap window as fullscreen\n"
" --help\tShow this help text\n\n");
exit(error_code);
@ -395,8 +394,6 @@ int main(int argc, char *argv[])
usage(EXIT_FAILURE);
fullscreen.height = atol(argv[i]);
} else if (strcmp(argv[i], "-f") == 0) {
fullscreen.fullscreen = 1;
} else if (strcmp(argv[i], "--help") == 0)
usage(EXIT_SUCCESS);
else
@ -437,8 +434,6 @@ int main(int argc, char *argv[])
window_set_fullscreen_handler(fullscreen.window, fullscreen_handler);
window_set_user_data(fullscreen.window, &fullscreen);
if (fullscreen.fullscreen)
window_set_fullscreen(fullscreen.window, fullscreen.fullscreen);
/* Hack to set minimum allocation so we can shrink later */
window_schedule_resize(fullscreen.window,
1, 1);

View file

@ -143,8 +143,6 @@ hmi_homescreen_launcher {
uint32_t workspace_id;
char *icon;
char *path;
char **argv;
struct wl_list link;
};
@ -310,10 +308,12 @@ launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
struct hmi_homescreen_launcher *launcher = NULL;
wl_list_for_each(launcher, launcher_list, link) {
char *argv[] = { NULL };
if (surfaceId != launcher->icon_surface_id)
continue;
execute_process(launcher->path, launcher->argv);
execute_process(launcher->path, argv);
return 1;
}
@ -1065,32 +1065,6 @@ create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
free(launchers);
}
static char **
parse_command(char *str)
{
char **argv;
char *saveptr;
char *token;
int i;
int count = 1;
for (i = 1; str[i]; i++)
if (str[i] == ' ' && str[i-1] != ' ')
count++;
argv = xcalloc(count + 1, sizeof(char*));
i = 0;
token = strtok_r(str, " ", &saveptr);
while (token != NULL) {
argv[i++] = token;
token = strtok_r(NULL, " ", &saveptr);
}
return argv;
}
/**
* Internal method to read out weston.ini to get configuration
*/
@ -1203,7 +1177,6 @@ hmi_homescreen_setting_create(void)
while (weston_config_next_section(config, &section, &name)) {
struct hmi_homescreen_launcher *launcher;
char *command;
if (strcmp(name, "ivi-launcher") != 0)
continue;
@ -1213,18 +1186,8 @@ hmi_homescreen_setting_create(void)
weston_config_section_get_string(section, "icon",
&launcher->icon, NULL);
weston_config_section_get_string(section, "command",
&command, NULL);
if (command == NULL) {
weston_config_section_get_string(section, "path",
&launcher->path, NULL);
launcher->argv = NULL;
} else {
launcher->argv = parse_command(command);
launcher->path = launcher->argv[0];
}
weston_config_section_get_string(section, "path",
&launcher->path, NULL);
weston_config_section_get_uint(section, "workspace-id",
&launcher->workspace_id, 0);
weston_config_section_get_uint(section, "icon-id",

View file

@ -14,8 +14,6 @@ srcs_toytoolkit = [
relative_pointer_unstable_v1_protocol_c,
pointer_constraints_unstable_v1_client_protocol_h,
pointer_constraints_unstable_v1_protocol_c,
single_pixel_buffer_v1_client_protocol_h,
single_pixel_buffer_v1_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
ivi_application_client_protocol_h,
@ -42,7 +40,10 @@ dep_toytoolkit = declare_dependency(
link_with: lib_toytoolkit,
dependencies: deps_toytoolkit,
)
dep_gbm = dependency('gbm', required: false, version: '>= 21.3')
dep_gbm = dependency('gbm', required: false, version: '>= 21.1.1')
if dep_gbm.found() and dep_gbm.version().version_compare('>= 21.3')
config_h.set('HAVE_GBM_BO_CREATE_WITH_MODIFIERS2', '1')
endif
simple_clients_enabled = get_option('simple-clients')
simple_build_all = simple_clients_enabled.contains('all')
@ -160,21 +161,6 @@ simple_clients = [
],
'dep_objs': [ dep_wayland_client, dep_libshared ]
},
{
'name': 'timing',
'sources': [
'simple-timing.c',
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
commit_timing_v1_client_protocol_h,
commit_timing_v1_protocol_c,
fifo_v1_client_protocol_h,
fifo_v1_protocol_c,
presentation_time_client_protocol_h,
presentation_time_protocol_c,
],
'dep_objs': [ dep_wayland_client, dep_libshared ]
},
{
'name': 'touch',
'sources': [
@ -186,89 +172,6 @@ simple_clients = [
},
]
if dep_vulkan.found() and prog_glslang.found()
srcs_simple_vulkan_shaders = [
'simple_vulkan_vertex_shader.vert',
'simple_vulkan_fragment_shader.frag',
]
simple_vulkan_shaders = []
foreach s : srcs_simple_vulkan_shaders
simple_vulkan_shaders += custom_target(s + '.spv.h',
command: [ prog_glslang, '@INPUT@', '--quiet', '--variable-name', '@BASENAME@', '-V', '-x', '-o', '@OUTPUT@' ],
input: s,
output: '@BASENAME@.spv.h',
)
endforeach
simple_clients += {
'name': 'vulkan',
'sources': [
'simple-vulkan.c',
simple_vulkan_shaders,
fractional_scale_v1_client_protocol_h,
fractional_scale_v1_protocol_c,
tearing_control_v1_client_protocol_h,
tearing_control_v1_protocol_c,
viewporter_client_protocol_h,
viewporter_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
],
'dep_objs': [
dep_vulkan,
dep_libm,
dep_libshared,
dep_matrix_c,
dep_wayland_client,
],
'deps': [ 'vulkan', 'wayland-cursor' ],
'options': [ 'renderer-gl' ]
}
srcs_simple_dmabuf_vulkan_shaders = [
'simple_dmabuf_vulkan_vertex_shader.vert',
'simple_dmabuf_vulkan_fragment_shader.frag',
]
simple_dmabuf_vulkan_shaders = []
foreach s : srcs_simple_dmabuf_vulkan_shaders
simple_dmabuf_vulkan_shaders += custom_target(s + '.spv.h',
command: [ prog_glslang, '@INPUT@', '--quiet', '--variable-name', '@BASENAME@', '-V', '-x', '-o', '@OUTPUT@' ],
input: s,
output: '@BASENAME@.spv.h',
)
endforeach
simple_clients += {
'name': 'dmabuf-vulkan',
'sources': [
'simple-dmabuf-vulkan.c',
simple_dmabuf_vulkan_shaders,
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
linux_explicit_synchronization_unstable_v1_client_protocol_h,
linux_explicit_synchronization_unstable_v1_protocol_c,
xdg_shell_client_protocol_h,
xdg_shell_protocol_c,
weston_direct_display_client_protocol_h,
weston_direct_display_protocol_c,
],
'dep_objs': [
dep_vulkan,
dep_libdrm_headers,
dep_libm,
dep_libdrm,
dep_libshared,
dep_matrix_c,
dep_wayland_client,
dep_libweston_private, # for pixel-formats.h
],
'deps': [ 'vulkan', 'wayland-cursor', 'gbm' ],
'options': [ 'renderer-gl' ]
}
endif
foreach t : simple_clients
if simple_build_all or simple_clients_enabled.contains(t.get('name'))
t_name = 'weston-simple-' + t.get('name')
@ -366,15 +269,6 @@ demo_clients = [
'basename': 'cliptest',
'dep_objs': [ dep_vertex_clipping, dep_matrix_c ]
},
{
'basename': 'color',
'add_sources': [
color_management_v1_client_protocol_h,
color_management_v1_protocol_c,
single_pixel_buffer_v1_client_protocol_h,
single_pixel_buffer_v1_protocol_c,
],
},
{
'basename': 'constraints',
'add_sources': [
@ -497,7 +391,7 @@ if get_option('shell-desktop')
env_modmap += 'weston-desktop-shell=@0@;'.format(exe_shell_desktop.full_path())
endif
if get_option('shell-desktop') or get_option('shell-kiosk') or get_option('shell-ivi')
if get_option('shell-desktop') or get_option('shell-fullscreen') or get_option('shell-kiosk') or get_option('shell-ivi')
exe_shooter = executable(
'weston-screenshooter',
'screenshot.c',
@ -505,7 +399,6 @@ if get_option('shell-desktop') or get_option('shell-kiosk') or get_option('shell
weston_output_capture_protocol_c,
include_directories: common_inc,
dependencies: [
dep_client_buffer,
dep_toytoolkit,
dep_libweston_private, # for pixel-formats.h
dep_pixman,

View file

@ -775,7 +775,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, wp_presentation_interface.name) == 0) {
d->presentation =
wl_registry_bind(registry,
name, &wp_presentation_interface, 2);
name, &wp_presentation_interface, 1);
wp_presentation_add_listener(d->presentation,
&presentation_listener, d);
}

View file

@ -24,44 +24,33 @@
#include "config.h"
#include <assert.h>
#include <cairo.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <pixman.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <wayland-client.h>
#include <limits.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <pixman.h>
#include <cairo.h>
#include <assert.h>
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "pixel-formats.h"
#include "shared/client-buffer-util.h"
#include "shared/file-util.h"
#include "shared/os-compatibility.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
#include <wayland-client.h>
#include "weston-output-capture-client-protocol.h"
#include "shared/os-compatibility.h"
#include "shared/xalloc.h"
#include "shared/file-util.h"
#include "pixel-formats.h"
struct screenshooter_app {
struct wl_display *display;
struct wl_registry *registry;
struct wl_shm *shm;
struct zwp_linux_dmabuf_v1 *dmabuf;
struct weston_capture_v1 *capture_factory;
bool verbose;
const struct pixel_format_info *requested_format;
enum weston_capture_v1_source src_type;
enum client_buffer_type buffer_type;
struct wl_list output_list; /* struct screenshooter_output::link */
bool retry;
@ -70,14 +59,14 @@ struct screenshooter_app {
};
struct screenshooter_buffer {
struct client_buffer *buf;
size_t len;
void *data;
struct wl_buffer *wl_buffer;
pixman_image_t *image;
enum weston_capture_v1_source src_type;
};
struct screenshooter_output {
struct screenshooter_app *app;
uint32_t name;
struct wl_list link; /* struct screenshooter_app::output_list */
struct wl_output *wl_output;
@ -87,8 +76,7 @@ struct screenshooter_output {
int buffer_width;
int buffer_height;
struct wl_array formats;
bool formats_done;
const struct pixel_format_info *fmt;
struct screenshooter_buffer *buffer;
};
@ -105,6 +93,10 @@ screenshot_create_shm_buffer(struct screenshooter_app *app,
const struct pixel_format_info *fmt)
{
struct screenshooter_buffer *buffer;
struct wl_shm_pool *pool;
int fd;
size_t bytes_pp;
size_t stride;
assert(width > 0);
assert(height > 0);
@ -113,60 +105,54 @@ screenshot_create_shm_buffer(struct screenshooter_app *app,
buffer = xzalloc(sizeof *buffer);
buffer->buf = client_buffer_util_create_shm_buffer(app->shm,
fmt,
width,
height);
bytes_pp = fmt->bpp / 8;
stride = width * bytes_pp;
buffer->len = stride * height;
assert(width == stride / bytes_pp);
assert(height == buffer->len / stride);
fd = os_create_anonymous_file(buffer->len);
if (fd < 0) {
fprintf(stderr, "creating a buffer file for %zd B failed: %s\n",
buffer->len, strerror(errno));
free(buffer);
return NULL;
}
buffer->data = mmap(NULL, buffer->len, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (buffer->data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
free(buffer);
return NULL;
}
pool = wl_shm_create_pool(app->shm, fd, buffer->len);
close(fd);
buffer->wl_buffer =
wl_shm_pool_create_buffer(pool, 0, width, height, stride,
pixel_format_get_shm_format(fmt));
wl_shm_pool_destroy(pool);
buffer->image = pixman_image_create_bits(fmt->pixman_format,
width, height,
buffer->buf->data,
buffer->buf->strides[0]);
buffer->data, stride);
abort_oom_if_null(buffer->image);
return buffer;
}
static struct screenshooter_buffer *
screenshot_create_udmabuf(struct screenshooter_app *app,
int width, int height,
const struct pixel_format_info *fmt)
{
struct screenshooter_buffer* buffer = NULL;
assert(width > 0);
assert(height > 0);
assert(fmt);
buffer = xzalloc(sizeof *buffer);
buffer->buf = client_buffer_util_create_dmabuf_buffer(app->display,
app->dmabuf,
fmt,
width,
height);
if (fmt->pixman_format) {
buffer->image = pixman_image_create_bits(fmt->pixman_format,
width, height,
buffer->buf->data,
buffer->buf->strides[0]);
abort_oom_if_null(buffer->image);
}
return buffer;
}
static void
screenshooter_buffer_destroy(struct screenshooter_buffer *buffer)
{
if (!buffer)
return;
if (buffer->image)
pixman_image_unref(buffer->image);
client_buffer_util_destroy_buffer(buffer->buf);
pixman_image_unref(buffer->image);
munmap(buffer->data, buffer->len);
wl_buffer_destroy(buffer->wl_buffer);
free(buffer);
}
@ -176,37 +162,10 @@ capture_source_handle_format(void *data,
uint32_t drm_format)
{
struct screenshooter_output *output = data;
uint32_t *fmt;
assert(output->source == proxy);
if (output->formats_done) {
wl_array_release(&output->formats);
wl_array_init(&output->formats);
output->formats_done = false;
}
fmt = wl_array_add(&output->formats, sizeof(uint32_t));
assert(fmt);
*fmt = drm_format;
if (output->app->verbose) {
const struct pixel_format_info *fmt_info;
fmt_info = pixel_format_get_info(drm_format);
assert(fmt_info);
printf("Got format %s / 0x%x\n", fmt_info->drm_format_name,
drm_format);
}
}
static void
capture_source_handle_formats_done(void *data,
struct weston_capture_source_v1 *proxy)
{
struct screenshooter_output *output = data;
output->formats_done = true;
output->fmt = pixel_format_get_info(drm_format);
}
static void
@ -221,9 +180,6 @@ capture_source_handle_size(void *data,
output->buffer_width = width;
output->buffer_height = height;
if (output->app->verbose)
printf("Got size %dx%d\n", width, height);
}
static void
@ -253,9 +209,7 @@ capture_source_handle_failed(void *data,
struct screenshooter_output *output = data;
output->app->waitcount--;
/* We don't set app.failed here because there could be other
* outputs we still want to capture!
*/
output->app->failed = true;
if (msg)
fprintf(stderr, "Output capture error: %s\n", msg);
@ -263,7 +217,6 @@ capture_source_handle_failed(void *data,
static const struct weston_capture_source_v1_listener capture_source_handlers = {
.format = capture_source_handle_format,
.formats_done = capture_source_handle_formats_done,
.size = capture_source_handle_size,
.complete = capture_source_handle_complete,
.retry = capture_source_handle_retry,
@ -278,20 +231,17 @@ create_output(struct screenshooter_app *app, uint32_t output_name, uint32_t vers
version = MIN(version, 4);
output = xzalloc(sizeof *output);
output->app = app;
output->name = output_name;
output->wl_output = wl_registry_bind(app->registry, output_name,
&wl_output_interface, version);
abort_oom_if_null(output->wl_output);
output->source = weston_capture_v1_create(app->capture_factory,
output->wl_output,
app->src_type);
WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER);
abort_oom_if_null(output->source);
weston_capture_source_v1_add_listener(output->source,
&capture_source_handlers, output);
wl_array_init(&output->formats);
wl_list_insert(&app->output_list, &output->link);
}
@ -300,8 +250,6 @@ destroy_output(struct screenshooter_output *output)
{
weston_capture_source_v1_destroy(output->source);
wl_array_release(&output->formats);
if (wl_output_get_version(output->wl_output) >= WL_OUTPUT_RELEASE_SINCE_VERSION)
wl_output_release(output->wl_output);
else
@ -329,13 +277,7 @@ handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, weston_capture_v1_interface.name) == 0) {
app->capture_factory = wl_registry_bind(registry, name,
&weston_capture_v1_interface,
2);
} else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
if (version < 3)
return;
app->dmabuf = wl_registry_bind(registry, name,
&zwp_linux_dmabuf_v1_interface,
3);
1);
}
}
@ -353,46 +295,15 @@ static const struct wl_registry_listener registry_listener = {
static void
screenshooter_output_capture(struct screenshooter_output *output)
{
const struct pixel_format_info *fmt_info = NULL;
uint32_t *fmt;
screenshooter_buffer_destroy(output->buffer);
wl_array_for_each(fmt, &output->formats) {
fmt_info = pixel_format_get_info(*fmt);
assert(fmt_info);
if (fmt_info == output->app->requested_format ||
output->app->requested_format == NULL)
break;
fmt_info = NULL;
}
if (!fmt_info) {
fprintf(stderr, "No supported format found\n");
exit(1);
}
if (output->app->verbose)
printf("Creating buffer with format %s / 0x%x and size %ux%u\n",
fmt_info->drm_format_name, fmt_info->format,
output->buffer_width, output->buffer_height);
if (output->app->buffer_type == CLIENT_BUFFER_TYPE_SHM) {
output->buffer = screenshot_create_shm_buffer(output->app,
output->buffer_width,
output->buffer_height,
fmt_info);
} else if (output->app->buffer_type == CLIENT_BUFFER_TYPE_DMABUF) {
output->buffer = screenshot_create_udmabuf(output->app,
output->buffer_width,
output->buffer_height,
fmt_info);
}
output->buffer = screenshot_create_shm_buffer(output->app,
output->buffer_width,
output->buffer_height,
output->fmt);
abort_oom_if_null(output->buffer);
weston_capture_source_v1_capture(output->source,
output->buffer->buf->wl_buffer);
output->buffer->wl_buffer);
output->app->waitcount++;
}
@ -412,8 +323,6 @@ screenshot_write_png(const struct buffer_size *buff_size,
abort_oom_if_null(shot);
wl_list_for_each(output, output_list, link) {
client_buffer_util_maybe_sync_dmabuf_start(output->buffer->buf);
pixman_image_composite32(PIXMAN_OP_SRC,
output->buffer->image, /* src */
NULL, /* mask */
@ -422,8 +331,6 @@ screenshot_write_png(const struct buffer_size *buff_size,
0, 0, /* mask x,y */
output->offset_x, output->offset_y, /* dst x,y */
output->buffer_width, output->buffer_height);
client_buffer_util_maybe_sync_dmabuf_end(output->buffer->buf);
}
surface = cairo_image_surface_create_for_data((void *)pixman_image_get_data(shot),
@ -442,59 +349,6 @@ screenshot_write_png(const struct buffer_size *buff_size,
pixman_image_unref(shot);
}
static void
screenshot_write_yuv(const struct buffer_size *buff_size,
struct wl_list *output_list)
{
struct screenshooter_output *output;
int i = 0;
wl_list_for_each(output, output_list, link) {
struct screenshooter_buffer *buffer = output->buffer;
char filepath[PATH_MAX];
char filepath_prefix[100];
int write_offset = 0;
FILE *fp;
sprintf(filepath_prefix, "wayland-screenshot-output-%d-", i++);
fp = file_create_dated(getenv("XDG_PICTURES_DIR"),
filepath_prefix, ".yuv", filepath,
sizeof(filepath));
if (!fp) {
fprintf(stderr, "Writing yuv file for output %d failed\n", i);
return;
}
client_buffer_util_maybe_sync_dmabuf_start(buffer->buf);
for (unsigned int j = 0; j < pixel_format_get_plane_count(buffer->buf->fmt); j++) {
int plane_height =
buffer->buf->height / pixel_format_hsub(buffer->buf->fmt, j);
for (int k = 0; k < plane_height; k++) {
size_t lines_written;
lines_written = fwrite(buffer->buf->data + write_offset,
buffer->buf->bytes_per_line[j],
1, fp);
if (lines_written != 1) {
fprintf(stderr,
"Writing yuv file for output %d " \
"failed during write(): %s\n",
i, strerror(errno));
return;
}
write_offset += buffer->buf->strides[j];
}
}
fclose (fp);
client_buffer_util_maybe_sync_dmabuf_end(buffer->buf);
}
}
static int
screenshot_set_buffer_size(struct buffer_size *buff_size,
struct wl_list *output_list)
@ -528,177 +382,41 @@ screenshot_set_buffer_size(struct buffer_size *buff_size,
return 0;
}
static bool
received_formats_for_all_outputs(struct screenshooter_app *app)
{
struct screenshooter_output *output;
wl_list_for_each(output, &app->output_list, link) {
if (!output->formats_done)
return false;
}
return true;
}
static bool
all_output_formats_are_yuv(struct wl_list *output_list)
{
struct screenshooter_output *output;
int color_model = -1;
wl_list_for_each(output, output_list, link) {
if (color_model == -1) {
color_model = output->buffer->buf->fmt->color_model;
continue;
}
if ((int)output->buffer->buf->fmt->color_model != color_model) {
fprintf(stderr, "Mixing of RGB and YUV output formats not supported\n");
exit(1);
}
}
assert(color_model == (int)COLOR_MODEL_RGB ||
color_model == (int)COLOR_MODEL_YUV);
return color_model == COLOR_MODEL_YUV;
}
static void
print_usage_and_exit(void)
{
printf("usage flags:\n"
"\t'-h,--help'"
"\n\t\tprint this help output\n"
"\t'-v,--verbose'"
"\n\t\tprint additional output\n"
"\t'-f,--format=<>'"
"\n\t\tthe DRM format name to use without the DRM_FORMAT_ prefix, e.g. RGBA8888 or NV12\n"
"\n\t\tIn case of YCbCr formats like NV12, instead of a single .png, the output will consist of raw .yuv files for each output."
"\n\t\tThese files do not contain any metadata, however that can be added by converting to .y4m with a command like:"
"\n\t\tffmpeg -s 1024x768 -r 1 -pix_fmt yuv420p -i ~/wayland-screenshot-output-0-2025-08-01_15-58-24.yuv -c:v copy screenshot.y4m\n"
"\n\t\tNote that this may not work for all YCbCr pixel formats.\n"
"\t'-s,--source-type=<>'"
"\n\t\tframebuffer to use framebuffer source (default), "
"\n\t\twriteback to use writeback source\n"
"\t'-b,--buffer-type=<>'"
"\n\t\tshm to use a SHM buffer (default), "
"\n\t\tdmabuf to use a DMA buffer\n");
exit(0);
}
static const struct weston_enum_map source_types [] = {
{ "framebuffer", WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER },
{ "writeback", WESTON_CAPTURE_V1_SOURCE_WRITEBACK },
};
static const struct weston_enum_map buffer_types [] = {
{ "shm", CLIENT_BUFFER_TYPE_SHM },
{ "dmabuf", CLIENT_BUFFER_TYPE_DMABUF },
};
int
main(int argc, char *argv[])
{
struct wl_display *display;
struct screenshooter_output *output;
struct screenshooter_output *tmp_output;
struct buffer_size buff_size = {};
struct screenshooter_app app = {};
int c, option_index;
app.src_type = WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER;
app.buffer_type = CLIENT_BUFFER_TYPE_SHM;
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{"format", required_argument, NULL, 'f'},
{"source-type", required_argument, NULL, 's'},
{"buffer-type", required_argument, NULL, 'b'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "hvf:s:b:",
long_options, &option_index)) != -1) {
const struct weston_enum_map *entry;
switch(c) {
case 'v':
app.verbose = true;
break;
case 'f':
app.requested_format = pixel_format_get_info_by_drm_name(optarg);
if (!app.requested_format) {
fprintf(stderr, "Unknown format %s\n", optarg);
return -1;
}
break;
case 's':
entry = weston_enum_map_find_name(source_types,
optarg);
if (!entry)
print_usage_and_exit();
app.src_type = entry->value;
break;
case 'b':
entry = weston_enum_map_find_name(buffer_types,
optarg);
if (!entry)
print_usage_and_exit();
app.buffer_type = entry->value;
break;
default:
print_usage_and_exit();
}
}
wl_list_init(&app.output_list);
app.display = wl_display_connect(NULL);
if (app.display == NULL) {
display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display: %s\n",
strerror(errno));
return -1;
}
app.registry = wl_display_get_registry(app.display);
app.registry = wl_display_get_registry(display);
wl_registry_add_listener(app.registry, &registry_listener, &app);
/* Process wl_registry advertisements */
wl_display_roundtrip(app.display);
wl_display_roundtrip(display);
if (!app.shm) {
fprintf(stderr, "Error: display does not support wl_shm\n");
return -1;
}
if (!app.capture_factory) {
fprintf(stderr, "Error: display does not support weston_capture_v1\n");
return -1;
}
if(app.buffer_type == CLIENT_BUFFER_TYPE_SHM && !app.shm) {
fprintf(stderr, "Error: display does not support wl_shm\n");
return -1;
}
if (app.buffer_type == CLIENT_BUFFER_TYPE_DMABUF && !app.dmabuf) {
fprintf(stderr, "Error: Compositor does not support zwp_linux_dmabuf_v1\n");
return -1;
}
if (app.verbose) {
printf("Taking screenshot with %s source %s buffer\n",
(app.src_type == WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER) ? "framebuffer" : "writeback",
(app.buffer_type == CLIENT_BUFFER_TYPE_SHM) ? "shm" : "dma");
}
/* Process initial events for wl_output and weston_capture_source_v1 */
wl_display_roundtrip(app.display);
while (!received_formats_for_all_outputs(&app)) {
if (app.verbose)
printf("Waiting for compositor to send capture source data\n");
if (wl_display_dispatch(app.display) < 0) {
fprintf(stderr, "Error: connection terminated\n");
return -1;
}
}
wl_display_roundtrip(display);
do {
app.retry = false;
@ -707,7 +425,7 @@ main(int argc, char *argv[])
screenshooter_output_capture(output);
while (app.waitcount > 0 && !app.failed) {
if (wl_display_dispatch(app.display) < 0)
if (wl_display_dispatch(display) < 0)
app.failed = true;
assert(app.waitcount >= 0);
}
@ -716,11 +434,7 @@ main(int argc, char *argv[])
if (!app.failed) {
if (screenshot_set_buffer_size(&buff_size, &app.output_list) < 0)
return -1;
if (all_output_formats_are_yuv(&app.output_list))
screenshot_write_yuv(&buff_size, &app.output_list);
else
screenshot_write_png(&buff_size, &app.output_list);
screenshot_write_png(&buff_size, &app.output_list);
} else {
fprintf(stderr, "Error: screenshot or protocol failure\n");
}
@ -730,10 +444,8 @@ main(int argc, char *argv[])
weston_capture_v1_destroy(app.capture_factory);
wl_shm_destroy(app.shm);
if (app.dmabuf)
zwp_linux_dmabuf_v1_destroy(app.dmabuf);
wl_registry_destroy(app.registry);
wl_display_disconnect(app.display);
wl_display_disconnect(display);
return 0;
}

View file

@ -340,6 +340,7 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
buffer->release_fence_fd = -1;
if (display->modifiers_count > 0) {
#ifdef HAVE_GBM_BO_CREATE_WITH_MODIFIERS2
buffer->bo = gbm_bo_create_with_modifiers2(display->gbm.device,
buffer->width,
buffer->height,
@ -347,6 +348,14 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
display->modifiers,
display->modifiers_count,
GBM_BO_USE_RENDERING);
#else
buffer->bo = gbm_bo_create_with_modifiers(display->gbm.device,
buffer->width,
buffer->height,
buffer->format,
display->modifiers,
display->modifiers_count);
#endif
if (buffer->bo)
buffer->modifier = gbm_bo_get_modifier(buffer->bo);
}
@ -806,7 +815,7 @@ render(struct window *window, struct buffer *buffer)
glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.M.colmaj);
(GLfloat *) reflection.d);
glClearColor(0.0,0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
@ -855,7 +864,7 @@ render_mandelbrot(struct window *window, struct buffer *buffer)
glUniform1f(window->gl.offset_uniform, offset);
glUniformMatrix4fv(window->gl.reflection_uniform, 1, GL_FALSE,
(GLfloat *) reflection.M.colmaj);
(GLfloat *) reflection.d);
glClearColor(0.6, 0.6, 0.6, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
@ -1101,12 +1110,6 @@ destroy_display(struct display *display)
free(display->modifiers);
if (display->direct_display)
weston_direct_display_v1_destroy(display->direct_display);
if (display->explicit_sync)
zwp_linux_explicit_synchronization_v1_destroy(display->explicit_sync);
if (display->dmabuf)
zwp_linux_dmabuf_v1_destroy(display->dmabuf);

View file

@ -547,11 +547,18 @@ create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
buf->format = format;
if (count_modifiers > 0) {
#ifdef HAVE_GBM_BO_CREATE_WITH_MODIFIERS2
buf->bo = gbm_bo_create_with_modifiers2(display->gbm_device,
buf->width, buf->height,
format, modifiers,
count_modifiers,
bo_flags);
#else
buf->bo = gbm_bo_create_with_modifiers(display->gbm_device,
buf->width, buf->height,
format, modifiers,
count_modifiers);
#endif
if (buf->bo)
buf->modifier = gbm_bo_get_modifier(buf->bo);
}

File diff suppressed because it is too large Load diff

View file

@ -564,6 +564,7 @@ init_gl(struct window *window)
glBindAttribLocation(program, window->gl.pos, "pos");
glBindAttribLocation(program, window->gl.col, "color");
glLinkProgram(program);
window->gl.rotation_uniform =
glGetUniformLocation(program, "rotation");
@ -939,10 +940,10 @@ redraw(struct window *window)
angle = ((time - window->initial_frame_time) / speed_div)
% 360 * M_PI / 180.0;
}
rotation.M.col[0].el[0] = cos(angle);
rotation.M.col[0].el[2] = sin(angle);
rotation.M.col[2].el[0] = -sin(angle);
rotation.M.col[2].el[2] = cos(angle);
rotation.d[0] = cos(angle);
rotation.d[2] = sin(angle);
rotation.d[8] = -sin(angle);
rotation.d[10] = cos(angle);
switch (window->buffer_transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
@ -981,7 +982,7 @@ redraw(struct window *window)
glViewport(0, 0, window->buffer_size.width, window->buffer_size.height);
glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
(GLfloat *) rotation.M.colmaj);
(GLfloat *) rotation.d);
if (window->opaque || window->fullscreen)
glClearColor(0.0, 0.0, 0.0, 1);
@ -1473,10 +1474,15 @@ main(int argc, char **argv)
create_surface(&window);
/* we already have wait_for_configure set after create_surface() */
while (running && ret != -1 && window.wait_for_configure)
while (running && ret != -1 && window.wait_for_configure) {
ret = wl_display_dispatch(display.display);
init_gl(&window);
/* wait until xdg_surface::configure acks the new dimensions */
if (window.wait_for_configure)
continue;
init_gl(&window);
}
display.cursor_surface =
wl_compositor_create_surface(display.compositor);
@ -1524,9 +1530,6 @@ out_no_xdg_shell:
if (display.compositor)
wl_compositor_destroy(display.compositor);
if (display.tearing_manager)
wp_tearing_control_manager_v1_destroy(display.tearing_manager);
if (display.viewporter)
wp_viewporter_destroy(display.viewporter);

View file

@ -397,7 +397,7 @@ simple_im_key_handler(struct simple_im *keyboard,
if (keyboard->compose_state == state_compose) {
uint32_t i = 0;
const struct compose_seq *cs;
struct compose_seq *cs;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
return;

View file

@ -34,7 +34,6 @@
#include <sys/mman.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <linux/input.h>
@ -43,20 +42,8 @@
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define FMT(fmt, bpp, r, g, b, a) { WL_SHM_FORMAT_ ## fmt, #fmt, bpp, { r, g, b, a } }
#define MAX_BUFFER_ALLOC 2
struct window;
struct format {
uint32_t code;
const char *string;
int bpp;
uint64_t color[4];
};
struct display {
struct wl_display *display;
struct wl_registry *registry;
@ -65,10 +52,7 @@ struct display {
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_shm *shm;
const struct format *format;
bool paint_format;
bool has_format;
struct window *window;
bool has_xrgb;
};
struct buffer {
@ -97,68 +81,6 @@ struct window {
bool needs_update_buffer;
};
static const struct format shm_formats[] = {
/* 8 bpp formats */
FMT(R8, 8, 0x00, 0x55, 0xaa, 0xff ),
/* 16 bpp formats */
FMT(R16, 16, 0x0000, 0x5555, 0xaaaa, 0xffff ),
FMT(GR88, 16, 0x00ff, 0xff00, 0x0000, 0xffff ),
FMT(RG88, 16, 0xff00, 0x00ff, 0x0000, 0xffff ),
FMT(RGB565, 16, 0xf800, 0x07e0, 0x001f, 0xffff ),
FMT(BGR565, 16, 0x001f, 0x07e0, 0xf800, 0xffff ),
FMT(XRGB4444, 16, 0xff00, 0xf0f0, 0xf00f, 0x7777 ),
FMT(ARGB4444, 16, 0xff00, 0xf0f0, 0xf00f, 0x7777 ),
FMT(XBGR4444, 16, 0xf00f, 0xf0f0, 0xff00, 0x7777 ),
FMT(ABGR4444, 16, 0xf00f, 0xf0f0, 0xff00, 0x7777 ),
FMT(RGBX4444, 16, 0xf00f, 0x0f0f, 0x00ff, 0x7777 ),
FMT(RGBA4444, 16, 0xf00f, 0x0f0f, 0x00ff, 0x7777 ),
FMT(BGRX4444, 16, 0x00ff, 0x0f0f, 0xf00f, 0x7777 ),
FMT(BGRA4444, 16, 0x00ff, 0x0f0f, 0xf00f, 0x7777 ),
FMT(XRGB1555, 16, 0xfc00, 0x83e1, 0x801f, 0x0000 ),
FMT(ARGB1555, 16, 0xfc00, 0x83e1, 0x801f, 0x0000 ),
FMT(XBGR1555, 16, 0x801f, 0x83e1, 0xfc00, 0x0000 ),
FMT(ABGR1555, 16, 0x801f, 0x83e1, 0xfc00, 0x0000 ),
FMT(RGBX5551, 16, 0xf801, 0x07c1, 0x003f, 0x0000 ),
FMT(RGBA5551, 16, 0xf801, 0x07c1, 0x003f, 0x0000 ),
FMT(BGRX5551, 16, 0x003f, 0x07c1, 0xf801, 0x0000 ),
FMT(BGRA5551, 16, 0x003f, 0x07c1, 0xf801, 0x0000 ),
/* 24 bpp formats */
FMT(RGB888, 24, 0xff0000, 0x00ff00, 0x0000ff, 0xffffff ),
FMT(BGR888, 24, 0x0000ff, 0x00ff00, 0xff0000, 0xffffff ),
/* 32 bpp formats */
FMT(GR1616, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0xffffffff ),
FMT(RG1616, 32, 0xffff0000, 0x0000ffff, 0x00000000, 0xffffffff ),
FMT(XRGB8888, 32, 0xffff0000, 0xff00ff00, 0xff0000ff, 0x7f7f7f7f ),
FMT(ARGB8888, 32, 0xffff0000, 0xff00ff00, 0xff0000ff, 0x7f7f7f7f ),
FMT(XBGR8888, 32, 0xff0000ff, 0xff00ff00, 0xffff0000, 0x7f7f7f7f ),
FMT(ABGR8888, 32, 0xff0000ff, 0xff00ff00, 0xffff0000, 0x7f7f7f7f ),
FMT(RGBX8888, 32, 0xff0000ff, 0x00ff00ff, 0x0000ffff, 0x7f7f7f7f ),
FMT(RGBA8888, 32, 0xff0000ff, 0x00ff00ff, 0x0000ffff, 0x7f7f7f7f ),
FMT(BGRX8888, 32, 0x0000ffff, 0x00ff00ff, 0xff0000ff, 0x7f7f7f7f ),
FMT(BGRA8888, 32, 0x0000ffff, 0x00ff00ff, 0xff0000ff, 0x7f7f7f7f ),
FMT(XRGB2101010, 32, 0xfff00000, 0xc00ffc00, 0xc00003ff, 0x5ff7fdff ),
FMT(ARGB2101010, 32, 0xfff00000, 0xc00ffc00, 0xc00003ff, 0x5ff7fdff ),
FMT(XBGR2101010, 32, 0xc00003ff, 0xc00ffc00, 0xfff00000, 0x5ff7fdff ),
FMT(ABGR2101010, 32, 0xc00003ff, 0xc00ffc00, 0xfff00000, 0x5ff7fdff ),
FMT(RGBX1010102, 32, 0xffc00003, 0x003ff003, 0x00000fff, 0x7fdff7fd ),
FMT(RGBA1010102, 32, 0xffc00003, 0x003ff003, 0x00000fff, 0x7fdff7fd ),
FMT(BGRX1010102, 32, 0x00000fff, 0x003ff003, 0xffc00003, 0x7fdff7fd ),
FMT(BGRA1010102, 32, 0x00000fff, 0x003ff003, 0xffc00003, 0x7fdff7fd ),
/* 64 bpp formats */
FMT(XRGB16161616, 64, 0xffffffff00000000, 0xffff0000ffff0000, 0xffff00000000ffff, 0x7fff7fff7fff7fff ),
FMT(ARGB16161616, 64, 0xffffffff00000000, 0xffff0000ffff0000, 0xffff00000000ffff, 0x7fff7fff7fff7fff ),
FMT(XBGR16161616, 64, 0xffff00000000ffff, 0xffff0000ffff0000, 0xffffffff00000000, 0x7fff7fff7fff7fff ),
FMT(ABGR16161616, 64, 0xffff00000000ffff, 0xffff0000ffff0000, 0xffffffff00000000, 0x7fff7fff7fff7fff ),
FMT(XRGB16161616F, 64, 0x3c003c0000000000, 0x3c0000003c000000, 0x3c00000000003c00, 0x3800380038003800 ),
FMT(ARGB16161616F, 64, 0x3c003c0000000000, 0x3c0000003c000000, 0x3c00000000003c00, 0x3800380038003800 ),
FMT(XBGR16161616F, 64, 0x3c00000000003c00, 0x3c0000003c000000, 0x3c003c0000000000, 0x3800380038003800 ),
FMT(ABGR16161616F, 64, 0x3c00000000003c00, 0x3c0000003c000000, 0x3c003c0000000000, 0x3800380038003800 ),
};
static int running = 1;
static void
@ -229,8 +151,7 @@ static const struct wl_buffer_listener buffer_listener = {
};
static int
create_shm_buffer(struct window *window, struct buffer *buffer,
const struct format *format)
create_shm_buffer(struct window *window, struct buffer *buffer, uint32_t format)
{
struct wl_shm_pool *pool;
int fd, size, stride;
@ -240,7 +161,7 @@ create_shm_buffer(struct window *window, struct buffer *buffer,
width = window->width;
height = window->height;
stride = width * (format->bpp / 8);
stride = width * 4;
size = stride * height;
display = window->display;
@ -261,7 +182,7 @@ create_shm_buffer(struct window *window, struct buffer *buffer,
pool = wl_shm_create_pool(display->shm, fd, size);
buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height,
stride, format->code);
stride, format);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool);
close(fd);
@ -298,16 +219,8 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
struct display *d = data;
if (key == KEY_F11 && state) {
if (d->window->fullscreen)
xdg_toplevel_unset_fullscreen(d->window->xdg_toplevel);
else
xdg_toplevel_set_fullscreen(d->window->xdg_toplevel, NULL);
} else if (key == KEY_ESC && state) {
if (key == KEY_ESC && state)
running = 0;
}
}
static void
@ -503,16 +416,14 @@ window_next_buffer(struct window *window)
return NULL;
if (!buffer->buffer) {
ret = create_shm_buffer(window, buffer,
window->display->format);
ret = create_shm_buffer(window, buffer, WL_SHM_FORMAT_XRGB8888);
if (ret < 0)
return NULL;
/* paint the padding */
memset(buffer->shm_data, 0xff,
window->width * window->height *
(window->display->format->bpp / 8));
window->width * window->height * 4);
}
return buffer;
@ -564,122 +475,6 @@ paint_pixels(void *image, int padding, int width, int height, uint32_t time)
}
}
static void
paint_format(void *image, const struct format *format, int width, int height)
{
uint64_t *img64 = (uint64_t*) image;
uint32_t *img32 = (uint32_t*) image;
uint16_t *img16 = (uint16_t*) image;
uint8_t *img8 = (uint8_t*) image;
uint64_t color;
int i, j;
#define GET_COLOR(y) \
(y < (1 * (height / 4))) ? format->color[0] : \
(y < (2 * (height / 4))) ? format->color[1] : \
(y < (3 * (height / 4))) ? format->color[2] : \
format->color[3]
switch (format->code) {
case WL_SHM_FORMAT_R8:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img8[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_R16:
case WL_SHM_FORMAT_GR88:
case WL_SHM_FORMAT_RG88:
case WL_SHM_FORMAT_RGB565:
case WL_SHM_FORMAT_BGR565:
case WL_SHM_FORMAT_XRGB4444:
case WL_SHM_FORMAT_ARGB4444:
case WL_SHM_FORMAT_XBGR4444:
case WL_SHM_FORMAT_ABGR4444:
case WL_SHM_FORMAT_RGBX4444:
case WL_SHM_FORMAT_RGBA4444:
case WL_SHM_FORMAT_BGRX4444:
case WL_SHM_FORMAT_BGRA4444:
case WL_SHM_FORMAT_XRGB1555:
case WL_SHM_FORMAT_ARGB1555:
case WL_SHM_FORMAT_XBGR1555:
case WL_SHM_FORMAT_ABGR1555:
case WL_SHM_FORMAT_RGBX5551:
case WL_SHM_FORMAT_RGBA5551:
case WL_SHM_FORMAT_BGRX5551:
case WL_SHM_FORMAT_BGRA5551:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img16[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_RGB888:
case WL_SHM_FORMAT_BGR888:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++) {
img8[(i * width + j) * 3 + 0] =
(color >> 0) & 0xff;
img8[(i * width + j) * 3 + 1] =
(color >> 8) & 0xff;
img8[(i * width + j) * 3 + 2] =
(color >> 16) & 0xff;
}
}
break;
case WL_SHM_FORMAT_GR1616:
case WL_SHM_FORMAT_RG1616:
case WL_SHM_FORMAT_XRGB8888:
case WL_SHM_FORMAT_ARGB8888:
case WL_SHM_FORMAT_XBGR8888:
case WL_SHM_FORMAT_ABGR8888:
case WL_SHM_FORMAT_RGBX8888:
case WL_SHM_FORMAT_RGBA8888:
case WL_SHM_FORMAT_BGRX8888:
case WL_SHM_FORMAT_BGRA8888:
case WL_SHM_FORMAT_XRGB2101010:
case WL_SHM_FORMAT_ARGB2101010:
case WL_SHM_FORMAT_XBGR2101010:
case WL_SHM_FORMAT_ABGR2101010:
case WL_SHM_FORMAT_RGBX1010102:
case WL_SHM_FORMAT_RGBA1010102:
case WL_SHM_FORMAT_BGRX1010102:
case WL_SHM_FORMAT_BGRA1010102:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img32[i * width + j] = color;
}
break;
case WL_SHM_FORMAT_XRGB16161616:
case WL_SHM_FORMAT_ARGB16161616:
case WL_SHM_FORMAT_XBGR16161616:
case WL_SHM_FORMAT_ABGR16161616:
case WL_SHM_FORMAT_XRGB16161616F:
case WL_SHM_FORMAT_ARGB16161616F:
case WL_SHM_FORMAT_XBGR16161616F:
case WL_SHM_FORMAT_ABGR16161616F:
for (i = 0; i < height; i++) {
color = GET_COLOR(i);
for (j = 0; j < width; j++)
img64[i * width + j] = color;
}
break;
default:
assert(0);
break;
};
#undef GET_COLOR
}
static const struct wl_callback_listener frame_listener;
static void
@ -698,12 +493,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
abort();
}
if (window->display->paint_format)
paint_format(buffer->shm_data, window->display->format,
window->width, window->height);
else
paint_pixels(buffer->shm_data, 20, window->width,
window->height, time);
paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface,
@ -727,8 +517,8 @@ shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{
struct display *d = data;
if (format == d->format->code)
d->has_format = true;
if (format == WL_SHM_FORMAT_XRGB8888)
d->has_xrgb = true;
}
struct wl_shm_listener shm_listener = {
@ -782,7 +572,7 @@ static const struct wl_registry_listener registry_listener = {
};
static struct display *
create_display(const struct format *format, bool paint_format)
create_display(void)
{
struct display *display;
@ -794,9 +584,7 @@ create_display(const struct format *format, bool paint_format)
display->display = wl_display_connect(NULL);
assert(display->display);
display->format = format;
display->paint_format = paint_format;
display->has_format= false;
display->has_xrgb = false;
display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry,
&registry_listener, display);
@ -848,9 +636,8 @@ create_display(const struct format *format, bool paint_format)
* technique.
*/
if (!display->has_format) {
fprintf(stderr, "Format '%s' not supported by compositor.\n",
format->string);
if (!display->has_xrgb) {
fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
exit(1);
}
@ -881,86 +668,19 @@ signal_int(int signum)
running = 0;
}
static void
usage(const char *program)
{
fprintf(stdout,
"Usage: %s [OPTIONS]\n"
"\n"
"Draw pixels into shared memory buffers using wl_shm\n"
"\n"
"Options:\n"
" -h, --help Show this help\n"
" -F, --format <format> Test format (see list below)\n"
"\n"
"RGB formats:\n"
" - 8 bpp: r8.\n"
"\n"
" - 16 bpp: r16, gr88, rg88, rgb565, bgr565, xrgb4444, argb4444, xbgr4444,\n"
" abgr4444, rgbx4444, rgba4444, bgrx4444, bgra4444, xrgb1555,\n"
" argb1555, xbgr1555, abgr1555, rgbx5551, rgba5551, bgrx5551,\n"
" bgra5551.\n"
"\n"
" - 24 bpp: rgb888, bgr888.\n"
"\n"
" - 32 bpp: gr1616, rg1616, xrgb8888, argb8888, xbgr8888, abgr8888, rgbx8888,\n"
" rgba8888, bgrx8888, bgra8888, xrgb2101010, argb2101010, xbgr2101010,\n"
" abgr2101010, rgbx1010102, rgba1010102, bgrx1010102, bgra1010102.\n"
"\n"
" - 64 bpp: xrgb16161616, argb16161616, xbgr16161616, abgr16161616,\n"
" xrgb16161616f, argb16161616f, xbgr16161616f, abgr16161616f.\n",
program);
}
int
main(int argc, char **argv)
{
struct sigaction sigint;
struct display *display;
struct window *window;
const struct format *format = NULL;
bool paint_format = false;
const char *value;
int ret = 0, i, j;
int ret = 0;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-h") ||
!strcmp(argv[i], "--help")) {
usage(argv[0]);
return 0;
} else if (!strcmp(argv[i], "-F") ||
!strcmp(argv[i], "--format")) {
value = ++i == argc ? "" : argv[i];
for (j = 0; j < (int) ARRAY_SIZE(shm_formats); j++) {
if (!strcasecmp(shm_formats[j].string, value)) {
format = &shm_formats[j];
paint_format = true;
break;
}
}
if (!format) {
fprintf(stderr, "Format '%s' not supported by "
"client.\n", value);
return 1;
}
} else {
fprintf(stderr, "Invalid argument: '%s'\n", argv[i - 1]);
return 1;
}
}
if (!format)
for (i = 0; i < (int) ARRAY_SIZE(shm_formats); i++)
if (shm_formats[i].code == WL_SHM_FORMAT_XRGB8888)
format = &shm_formats[i];
assert(format);
display = create_display(format, paint_format);
window = create_window(display, 256, 256);
display = create_display();
window = create_window(display, 250, 250);
if (!window)
return 1;
display->window = window;
sigint.sa_handler = signal_int;
sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND;

View file

@ -1,880 +0,0 @@
/*
* Copyright © 2011 Benjamin Franzke
* Copyright © 2010 Intel Corporation
* Copyright © 2025 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "shared/os-compatibility.h"
#include "shared/timespec-util.h"
#include "shared/xalloc.h"
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h"
#include "commit-timing-v1-client-protocol.h"
#include "fifo-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define MAX_BUFFER_ALLOC 1000
struct display {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct xdg_wm_base *wm_base;
struct wl_seat *seat;
struct wl_keyboard *keyboard;
struct wl_shm *shm;
struct wp_commit_timing_manager_v1 *commit_timing_manager;
struct wp_fifo_manager_v1 *fifo_manager;
struct wp_presentation *presentation;
bool have_clock_id;
clockid_t presentation_clock_id;
int64_t first_frame_time;
int64_t refresh_nsec;
};
struct buffer {
struct window *window;
struct wl_buffer *buffer;
void *shm_data;
int busy;
int width, height;
size_t size; /* width * 4 * height */
struct wl_list buffer_link; /** window::buffer_list */
};
struct window {
struct display *display;
int width, height;
int init_width, init_height;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_list buffer_list;
struct wp_fifo_v1 *fifo;
struct wp_commit_timer_v1 *commit_timer;
bool wait_for_configure;
bool maximized;
bool fullscreen;
bool needs_update_buffer;
};
struct feedback {
struct wp_presentation_feedback *fb;
struct window *window;
int64_t target_time;
bool final;
};
static int running = 1;
static void
draw_for_time(void *data, int64_t time, bool wait_fifo);
static void
finish_run(struct window *window);
static struct buffer *
alloc_buffer(struct window *window, int width, int height)
{
struct buffer *buffer = calloc(1, sizeof(*buffer));
buffer->width = width;
buffer->height = height;
wl_list_insert(&window->buffer_list, &buffer->buffer_link);
return buffer;
}
static void
destroy_buffer(struct buffer *buffer)
{
if (buffer->buffer)
wl_buffer_destroy(buffer->buffer);
munmap(buffer->shm_data, buffer->size);
wl_list_remove(&buffer->buffer_link);
free(buffer);
}
static struct buffer *
pick_free_buffer(struct window *window)
{
struct buffer *b;
struct buffer *buffer = NULL;
wl_list_for_each(b, &window->buffer_list, buffer_link) {
if (!b->busy) {
buffer = b;
break;
}
}
return buffer;
}
static void
prune_old_released_buffers(struct window *window)
{
struct buffer *b, *b_next;
wl_list_for_each_safe(b, b_next,
&window->buffer_list, buffer_link) {
if (!b->busy && (b->width != window->width ||
b->height != window->height))
destroy_buffer(b);
}
}
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
struct buffer *mybuf = data;
mybuf->busy = 0;
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static int
create_shm_buffer(struct window *window, struct buffer *buffer)
{
struct wl_shm_pool *pool;
int fd, size, stride;
void *data;
int width, height;
struct display *display;
width = window->width;
height = window->height;
stride = width * 4;
size = stride * height;
display = window->display;
fd = os_create_anonymous_file(size);
if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %s\n",
size, strerror(errno));
return -1;
}
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
close(fd);
return -1;
}
pool = wl_shm_create_pool(display->shm, fd, size);
buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height,
stride,
WL_SHM_FORMAT_XRGB8888);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool);
close(fd);
buffer->size = size;
buffer->shm_data = data;
return 0;
}
static void
keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
uint32_t format, int fd, uint32_t size)
{
/* Just so we dont leak the keymap fd */
close(fd);
}
static void
keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys)
{
}
static void
keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
}
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state)
{
if (key == KEY_ESC && state)
running = 0;
}
static void
keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched, uint32_t mods_locked,
uint32_t group)
{
}
static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_keymap,
keyboard_handle_enter,
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
};
static void
seat_handle_capabilities(void *data, struct wl_seat *seat,
enum wl_seat_capability caps)
{
struct display *d = data;
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !d->keyboard) {
d->keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(d->keyboard, &keyboard_listener, d);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && d->keyboard) {
wl_keyboard_destroy(d->keyboard);
d->keyboard = NULL;
}
}
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
static void
handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
struct window *window = data;
xdg_surface_ack_configure(surface, serial);
if (window->wait_for_configure) {
draw_for_time(window, 0, false);
window->wait_for_configure = false;
}
}
static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_surface_configure,
};
static void
handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
struct window *window = data;
uint32_t *p;
window->fullscreen = false;
window->maximized = false;
wl_array_for_each(p, states) {
uint32_t state = *p;
switch (state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
window->fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
window->maximized = true;
break;
}
}
if (width > 0 && height > 0) {
if (!window->fullscreen && !window->maximized) {
window->init_width = width;
window->init_height = height;
}
window->width = width;
window->height = height;
} else if (!window->fullscreen && !window->maximized) {
window->width = window->init_width;
window->height = window->init_height;
}
window->needs_update_buffer = true;
}
static void
handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
running = 0;
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_xdg_toplevel_configure,
handle_xdg_toplevel_close,
};
static struct window *
create_window(struct display *display, int width, int height)
{
struct window *window;
int i;
window = zalloc(sizeof *window);
if (!window)
return NULL;
window->display = display;
window->width = width;
window->height = height;
window->init_width = width;
window->init_height = height;
window->surface = wl_compositor_create_surface(display->compositor);
window->fifo = wp_fifo_manager_v1_get_fifo(display->fifo_manager,
window->surface);
window->commit_timer = wp_commit_timing_manager_v1_get_timer(display->commit_timing_manager,
window->surface);
window->needs_update_buffer = false;
wl_list_init(&window->buffer_list);
assert(display->wm_base);
window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface);
assert(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window);
window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface);
assert(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "simple-timing");
xdg_toplevel_set_app_id(window->xdg_toplevel,
"org.freedesktop.weston.simple-timing");
wl_surface_commit(window->surface);
window->wait_for_configure = true;
for (i = 0; i < MAX_BUFFER_ALLOC; i++)
alloc_buffer(window, window->width, window->height);
return window;
}
static void
destroy_window(struct window *window)
{
struct buffer *buffer, *buffer_next;
wl_list_for_each_safe(buffer, buffer_next,
&window->buffer_list, buffer_link)
destroy_buffer(buffer);
if (window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface);
if (window->fifo)
wp_fifo_v1_destroy(window->fifo);
if (window->commit_timer)
wp_commit_timer_v1_destroy(window->commit_timer);
free(window);
}
static struct buffer *
window_next_buffer(struct window *window)
{
struct buffer *buffer = NULL;
int ret = 0;
if (window->needs_update_buffer) {
int i;
for (i = 0; i < MAX_BUFFER_ALLOC; i++)
alloc_buffer(window, window->width, window->height);
window->needs_update_buffer = false;
}
buffer = pick_free_buffer(window);
if (!buffer)
return NULL;
if (!buffer->buffer) {
ret = create_shm_buffer(window, buffer);
if (ret < 0)
return NULL;
/* paint the padding */
memset(buffer->shm_data, 0xff,
window->width * window->height * 4);
}
return buffer;
}
static void
paint_pixels(void *image, int width, int height, uint32_t time)
{
const int halfh = height / 2;
const int halfw = width / 2;
int ir, or;
uint32_t *pixel = image;
int y;
/* squared radii thresholds */
or = (halfw < halfh ? halfw : halfh) - 8;
ir = or - 32;
or *= or;
ir *= ir;
for (y = 0; y < height; y++) {
int x;
int y2 = (y - halfh) * (y - halfh);
for (x = 0; x < width; x++) {
uint32_t v;
/* squared distance from center */
int r2 = (x - halfw) * (x - halfw) + y2;
if (r2 < ir)
v = (r2 / 32 + time / 64) * 0x0080401;
else if (r2 < or)
v = (y + time / 32) * 0x0080401;
else
v = (x + time / 16) * 0x0080401;
v &= 0x00ffffff;
/* cross if compositor uses X from XRGB as alpha */
if (abs(x - y) > 6 && abs(x + y - height) > 6)
v |= 0xff000000;
*pixel++ = v;
}
}
}
static void
queue_some_frames(struct window *window)
{
struct display *display = window->display;
int64_t target_nsec;
int i;
assert(display->first_frame_time);
/* Round off error will cause us problems if we don't
* reduce this a bit, because we could end up rounding
* to either side of a refresh.
*/
target_nsec = display->first_frame_time - 100000;
for (i = 0; i < 60; i++) {
target_nsec += display->refresh_nsec * 2;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 30; i++) {
target_nsec += display->refresh_nsec * 4;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 10; i++) {
target_nsec += display->refresh_nsec * 10;
draw_for_time(window, target_nsec, false);
}
for (i = 0; i < 10; i++) {
target_nsec += display->refresh_nsec * 100;
draw_for_time(window, target_nsec, false);
}
finish_run(window);
}
static void
feedback_sync_output(void *data,
struct wp_presentation_feedback *presentation_feedback,
struct wl_output *output)
{
/* Just don't care */
}
static void
feedback_presented(void *data,
struct wp_presentation_feedback *presentation_feedback,
uint32_t tv_sec_hi,
uint32_t tv_sec_lo,
uint32_t tv_nsec,
uint32_t refresh_nsec,
uint32_t seq_hi,
uint32_t seq_lo,
uint32_t flags)
{
struct feedback *feedback = data;
struct window *window = feedback->window;
struct display *display = window->display;
struct timespec pres_ts = {
.tv_sec = ((int64_t)tv_sec_hi << 32) + tv_sec_lo,
.tv_nsec = tv_nsec,
};
int64_t ntime = timespec_to_nsec(&pres_ts);
double delay;
if (feedback->final) {
running = 0;
goto out;
}
if (!feedback->target_time) {
display->first_frame_time = ntime;
display->refresh_nsec = refresh_nsec;
queue_some_frames(window);
goto out;
}
delay = (ntime - feedback->target_time) / 1000000.0;
printf("%fms away from intended time\n", delay);
if (fabs(delay) > display->refresh_nsec / 1000000)
printf("Warning: we missed the intended target display cycle.\n");
out:
wp_presentation_feedback_destroy(feedback->fb);
free(feedback);
}
static void
feedback_discarded(void *data,
struct wp_presentation_feedback *presentation_feedback)
{
struct feedback *feedback = data;
printf("Warning: a frame was discarded\n");
if (feedback->final)
running = 0;
wp_presentation_feedback_destroy(feedback->fb);
free(feedback);
}
static const struct wp_presentation_feedback_listener feedback_listener = {
feedback_sync_output,
feedback_presented,
feedback_discarded,
};
static void
finish_run(struct window *window)
{
struct display *display = window->display;
struct feedback *feedback;
struct buffer *buffer;
feedback = xzalloc(sizeof *feedback);
feedback->window = window;
feedback->final = true;
feedback->target_time = 0;
buffer = window_next_buffer(window);
assert(buffer);
paint_pixels(buffer->shm_data, window->width,
window->height, 1);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
feedback->fb = wp_presentation_feedback(display->presentation,
window->surface);
wp_presentation_feedback_add_listener(feedback->fb,
&feedback_listener, feedback);
wp_fifo_v1_wait_barrier(window->fifo);
wl_surface_commit(window->surface);
}
static void
draw_for_time(void *data, int64_t time, bool wait_fifo)
{
struct window *window = data;
struct display *display = window->display;
struct buffer *buffer;
struct feedback *feedback;
assert(display->have_clock_id);
prune_old_released_buffers(window);
buffer = window_next_buffer(window);
assert(buffer);
paint_pixels(buffer->shm_data, window->width,
window->height, time / 1000000);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
wl_surface_damage(window->surface, 0, 0, window->width, window->height);
feedback = xzalloc(sizeof *feedback);
feedback->window = window;
feedback->fb = wp_presentation_feedback(display->presentation,
window->surface);
wp_presentation_feedback_add_listener(feedback->fb,
&feedback_listener, feedback);
feedback->target_time = time;
if (time) {
struct timespec target;
timespec_from_nsec(&target, time);
wp_commit_timer_v1_set_timestamp(window->commit_timer,
(int64_t)target.tv_sec >> 32,
target.tv_sec,
target.tv_nsec);
}
wp_fifo_v1_set_barrier(window->fifo);
wl_surface_commit(window->surface);
buffer->busy = 1;
}
static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
{
xdg_wm_base_pong(shell, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping,
};
static void
presentation_handle_clock_id(void *data,
struct wp_presentation *wp_presentation,
uint32_t clock_id)
{
struct display *display = data;
display->presentation_clock_id = clock_id;
display->have_clock_id = true;
}
static const struct wp_presentation_listener presentation_listener = {
presentation_handle_clock_id,
};
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
{
struct display *d = data;
if (strcmp(interface, "wl_compositor") == 0) {
d->compositor =
wl_registry_bind(registry,
id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
d->wm_base = wl_registry_bind(registry,
id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat = wl_registry_bind(registry, id,
&wl_seat_interface, 1);
wl_seat_add_listener(d->seat, &seat_listener, d);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1);
} else if (strcmp(interface, wp_commit_timing_manager_v1_interface.name) == 0) {
d->commit_timing_manager = wl_registry_bind(registry, id,
&wp_commit_timing_manager_v1_interface,
1);
} else if (strcmp(interface, wp_fifo_manager_v1_interface.name) == 0) {
d->fifo_manager = wl_registry_bind(registry, id,
&wp_fifo_manager_v1_interface,
1);
} else if (strcmp(interface, wp_presentation_interface.name) == 0) {
d->presentation = wl_registry_bind(registry, id,
&wp_presentation_interface,
2);
wp_presentation_add_listener(d->presentation,
&presentation_listener, d);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
static struct display *
create_display(void)
{
struct display *display;
display = xzalloc(sizeof *display);
display->display = wl_display_connect(NULL);
assert(display->display);
display->registry = wl_display_get_registry(display->display);
wl_registry_add_listener(display->registry,
&registry_listener, display);
wl_display_roundtrip(display->display);
if (display->shm == NULL) {
fprintf(stderr, "No wl_shm global\n");
exit(1);
}
wl_display_roundtrip(display->display);
return display;
}
static void
destroy_display(struct display *display)
{
if (display->shm)
wl_shm_destroy(display->shm);
if (display->wm_base)
xdg_wm_base_destroy(display->wm_base);
if (display->compositor)
wl_compositor_destroy(display->compositor);
if (display->presentation)
wp_presentation_destroy(display->presentation);
if (display->fifo_manager)
wp_fifo_manager_v1_destroy(display->fifo_manager);
if (display->commit_timing_manager)
wp_commit_timing_manager_v1_destroy(display->commit_timing_manager);
if (display->keyboard)
wl_keyboard_destroy(display->keyboard);
if (display->seat)
wl_seat_destroy(display->seat);
wl_registry_destroy(display->registry);
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
}
static void
signal_int(int signum)
{
running = 0;
}
static void
usage(const char *program)
{
fprintf(stdout,
"Usage: %s [OPTIONS]\n"
"\n"
"Schedule frames in the future with commit-timing\n"
"\n"
"Options:\n"
" -h, --help Show this help\n"
"\n",
program);
}
int
main(int argc, char **argv)
{
struct sigaction sigint;
struct display *display;
struct window *window;
int ret = 0, i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-h") ||
!strcmp(argv[i], "--help")) {
usage(argv[0]);
return 0;
} else {
fprintf(stderr, "Invalid argument: '%s'\n", argv[i - 1]);
return 1;
}
}
display = create_display();
window = create_window(display, 256, 256);
if (!window)
return 1;
sigint.sa_handler = signal_int;
sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
while (running && ret != -1)
ret = wl_display_dispatch(display->display);
fprintf(stderr, "simple-timing exiting\n");
destroy_window(window);
destroy_display(display);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
#version 450 core
layout(location = 0) in vec4 v_color;
layout(location = 0) out vec4 f_color;
void main() {
f_color = v_color;
}

View file

@ -1,17 +0,0 @@
#version 450 core
layout(std140, set = 0, binding = 0) uniform block {
uniform mat4 reflection;
uniform float offset;
};
layout(location = 0) in vec4 pos;
layout(location = 1) in vec4 color;
layout(location = 0) out vec4 v_color;
void main()
{
gl_Position = reflection * (pos + vec4(offset, offset, 0.0, 0.0));
v_color = color;
}

View file

@ -1,9 +0,0 @@
#version 450 core
layout(location = 0) in vec4 vVaryingColor;
layout(location = 0) out vec4 f_color;
void main()
{
f_color = vVaryingColor;
}

View file

@ -1,16 +0,0 @@
#version 450 core
layout(std140, set = 0, binding = 0) uniform block {
uniform mat4 rotation;
};
layout(location = 0) in vec4 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 0) out vec4 vVaryingColor;
void main()
{
gl_Position = rotation * in_position;
vVaryingColor = vec4(in_color.rgba);
}

View file

@ -58,7 +58,6 @@ static char *option_term;
static char *option_shell;
static struct wl_list terminal_list;
struct sigaction oldact;
static struct terminal *
terminal_create(struct display *display);
@ -3101,9 +3100,6 @@ terminal_run(struct terminal *terminal, const char *path)
close(pipes[0]);
setenv("TERM", option_term, 1);
setenv("COLORTERM", option_term, 1);
sigaction(SIGPIPE, &oldact, NULL);
if (execl(path, path, NULL)) {
printf("exec failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
@ -3181,10 +3177,8 @@ int main(int argc, char *argv[])
* socket whose reading end has been closed */
sigpipe.sa_handler = SIG_IGN;
sigemptyset(&sigpipe.sa_mask);
sigemptyset(&oldact.sa_mask);
sigpipe.sa_flags = 0;
sigaction(SIGPIPE, &sigpipe, &oldact);
sigaction(SIGPIPE, &sigpipe, NULL);
d = display_create(&argc, argv);
if (d == NULL) {

View file

@ -330,9 +330,9 @@ compute_calibration(struct calibrator *cal, float *result)
*/
weston_matrix_init(&m);
for (i = 0; i < 3; i++) {
m.M.col[0].el[i] = cal->samples[i].touched.x;
m.M.col[1].el[i] = cal->samples[i].touched.y;
m.M.col[2].el[i] = 1.0f;
m.d[i + 0] = cal->samples[i].touched.x;
m.d[i + 4] = cal->samples[i].touched.y;
m.d[i + 8] = 1.0f;
}
m.type = WESTON_MATRIX_TRANSFORM_OTHER;
@ -342,20 +342,20 @@ compute_calibration(struct calibrator *cal, float *result)
}
for (i = 0; i < 3; i++) {
x_calib.v.el[i] = cal->samples[i].drawn_cal.x;
y_calib.v.el[i] = cal->samples[i].drawn_cal.y;
x_calib.f[i] = cal->samples[i].drawn_cal.x;
y_calib.f[i] = cal->samples[i].drawn_cal.y;
}
x_calib.v.el[3] = 0.0f;
y_calib.v.el[3] = 0.0f;
x_calib.f[3] = 0.0f;
y_calib.f[3] = 0.0f;
/* Multiples into the vector */
weston_matrix_transform(&inverse, &x_calib);
weston_matrix_transform(&inverse, &y_calib);
for (i = 0; i < 3; i++)
result[i] = x_calib.v.el[i];
result[i] = x_calib.f[i];
for (i = 0; i < 3; i++)
result[i + 3] = y_calib.v.el[i];
result[i + 3] = y_calib.f[i];
return 0;
}

View file

@ -44,7 +44,9 @@
#include <xkbcommon/xkbcommon.h>
#ifdef HAVE_XKBCOMMON_COMPOSE
#include <xkbcommon/xkbcommon-compose.h>
#endif
#include <wayland-cursor.h>
#include <linux/input.h>
@ -55,7 +57,6 @@
#include <libweston/zalloc.h>
#include "xdg-shell-client-protocol.h"
#include "color-management-v1-client-protocol.h"
#include "single-pixel-buffer-v1-client-protocol.h"
#include "text-cursor-position-client-protocol.h"
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
@ -90,11 +91,10 @@ struct display {
struct wl_data_device_manager *data_device_manager;
struct text_cursor_position *text_cursor_position;
struct xdg_wm_base *xdg_shell;
struct wp_color_manager_v1 *color_manager;
struct xx_color_manager_v4 *color_manager;
struct zwp_tablet_manager_v2 *tablet_manager;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager;
uint32_t serial;
uint32_t color_manager_features;
@ -217,7 +217,7 @@ struct surface {
struct wl_callback *frame_cb;
uint32_t last_time;
struct wp_color_management_surface_v1 *cm_surface;
struct xx_color_management_surface_v4 *cm_surface;
struct rectangle allocation;
struct rectangle server_allocation;
@ -400,8 +400,10 @@ struct input {
struct {
struct xkb_keymap *keymap;
struct xkb_state *state;
#ifdef HAVE_XKBCOMMON_COMPOSE
struct xkb_compose_table *compose_table;
struct xkb_compose_state *compose_state;
#endif
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
xkb_mod_mask_t shift_mask;
@ -478,7 +480,7 @@ struct shm_pool {
};
struct cm_image_description {
struct wp_image_description_v1 *image_desc;
struct xx_image_description_v4 *image_desc;
enum cm_image_desc_status {
CM_IMAGE_DESC_NOT_CREATED = 0,
CM_IMAGE_DESC_READY,
@ -491,27 +493,27 @@ render_intent_info_table[] = {
{
.intent = RENDER_INTENT_PERCEPTUAL,
.desc = "Perceptual",
.protocol_intent = WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL,
.protocol_intent = XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL,
},
{
.intent = RENDER_INTENT_RELATIVE,
.desc = "Media-relative colorimetric",
.protocol_intent = WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE,
.protocol_intent = XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE,
},
{
.intent = RENDER_INTENT_RELATIVE_BPC,
.desc = "Media-relative colorimetric + black point compensation",
.protocol_intent = WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC,
.protocol_intent = XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC,
},
{
.intent = RENDER_INTENT_SATURATION,
.desc = "Saturation",
.protocol_intent = WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION,
.protocol_intent = XX_COLOR_MANAGER_V4_RENDER_INTENT_SATURATION,
},
{
.intent = RENDER_INTENT_ABSOLUTE,
.desc = "ICC-absolute colorimetric",
.protocol_intent = WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE,
.protocol_intent = XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE,
},
};
@ -566,7 +568,7 @@ debug_print(void *proxy, int line, const char *func, const char *fmt, ...)
#endif
static void
cm_image_desc_ready(void *data, struct wp_image_description_v1 *wp_image_description_v1,
cm_image_desc_ready(void *data, struct xx_image_description_v4 *xx_image_description_v4,
uint32_t identity)
{
struct cm_image_description *cm_image_desc = data;
@ -575,7 +577,7 @@ cm_image_desc_ready(void *data, struct wp_image_description_v1 *wp_image_descrip
}
static void
cm_image_desc_failed(void *data, struct wp_image_description_v1 *wp_image_description_v1,
cm_image_desc_failed(void *data, struct xx_image_description_v4 *xx_image_description_v4,
uint32_t cause, const char *msg)
{
struct cm_image_description *cm_image_desc = data;
@ -586,7 +588,7 @@ cm_image_desc_failed(void *data, struct wp_image_description_v1 *wp_image_descri
cm_image_desc->status = CM_IMAGE_DESC_FAILED;
}
static const struct wp_image_description_v1_listener cm_image_desc_listener = {
static const struct xx_image_description_v4_listener cm_image_desc_listener = {
.ready = cm_image_desc_ready,
.failed = cm_image_desc_failed,
};
@ -608,10 +610,10 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
uint32_t length, uint32_t offset,
enum render_intent intent, char **err_msg)
{
struct wp_image_description_creator_icc_v1 *icc_creator;
struct xx_image_description_creator_icc_v4 *icc_creator;
struct display *display = widget->window->display;
struct surface *surface = widget->surface;
struct wp_color_manager_v1 *color_manager_wrapper;
struct xx_color_manager_v4 *color_manager_wrapper;
struct wl_event_queue *queue;
struct cm_image_description cm_image_desc;
const struct render_intent_info *intent_info;
@ -621,11 +623,11 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
str_printf(err_msg,
"%s extension not supported by the Wayland " \
"compositor, ignoring image color profile.",
wp_color_manager_v1_interface.name);
xx_color_manager_v4_interface.name);
return false;
}
if (!((display->color_manager_features >> WP_COLOR_MANAGER_V1_FEATURE_ICC_V2_V4) & 1)) {
if (!((display->color_manager_features >> XX_COLOR_MANAGER_V4_FEATURE_ICC_V2_V4) & 1)) {
str_printf(err_msg,
"Wayland compositor does not support creating image " \
"descriptions from ICC files, ignoring color profile.");
@ -648,15 +650,15 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
wl_proxy_set_queue((struct wl_proxy *)color_manager_wrapper, queue);
/* Create ICC image description creator and set the ICC file. */
icc_creator = wp_color_manager_v1_create_icc_creator(color_manager_wrapper);
icc_creator = xx_color_manager_v4_new_icc_creator(color_manager_wrapper);
wl_proxy_wrapper_destroy(color_manager_wrapper);
wp_image_description_creator_icc_v1_set_icc_file(icc_creator,
xx_image_description_creator_icc_v4_set_icc_file(icc_creator,
icc_fd, offset, length);
/* Create the image description. It will also destroy the ICC creator. */
cm_image_desc.status = CM_IMAGE_DESC_NOT_CREATED;
cm_image_desc.image_desc = wp_image_description_creator_icc_v1_create(icc_creator);
wp_image_description_v1_add_listener(cm_image_desc.image_desc,
cm_image_desc.image_desc = xx_image_description_creator_icc_v4_create(icc_creator);
xx_image_description_v4_add_listener(cm_image_desc.image_desc,
&cm_image_desc_listener, &cm_image_desc);
/* Wait until compositor creates the image description or gracefully
@ -664,7 +666,7 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
while (ret != -1 && cm_image_desc.status == CM_IMAGE_DESC_NOT_CREATED)
ret = wl_display_dispatch_queue(display->display, queue);
if (ret == -1) {
wp_image_description_v1_destroy(cm_image_desc.image_desc);
xx_image_description_v4_destroy(cm_image_desc.image_desc);
wl_event_queue_destroy(queue);
str_printf(err_msg,
"Disconnected from the Wayland compositor, " \
@ -675,7 +677,7 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
/* Gracefully failed to create image description. Error already printed
* in the handler. */
if (cm_image_desc.status == CM_IMAGE_DESC_FAILED) {
wp_image_description_v1_destroy(cm_image_desc.image_desc);
xx_image_description_v4_destroy(cm_image_desc.image_desc);
wl_event_queue_destroy(queue);
str_printf(err_msg,
"Image description creation gracefully failed.");
@ -685,14 +687,14 @@ widget_set_image_description_icc(struct widget *widget, int icc_fd,
if (!surface->cm_surface)
surface->cm_surface =
wp_color_manager_v1_get_surface(display->color_manager,
xx_color_manager_v4_get_surface(display->color_manager,
surface->surface);
wp_color_management_surface_v1_set_image_description(surface->cm_surface,
xx_color_management_surface_v4_set_image_description(surface->cm_surface,
cm_image_desc.image_desc,
intent_info->protocol_intent);
wp_image_description_v1_destroy(cm_image_desc.image_desc);
xx_image_description_v4_destroy(cm_image_desc.image_desc);
wl_event_queue_destroy(queue);
return true;
@ -1449,35 +1451,6 @@ surface_flush(struct surface *surface)
surface->cairo_surface = NULL;
}
void
widget_surface_flush(struct widget *widget)
{
struct surface *surface = widget->surface;
if (surface->opaque_region) {
wl_surface_set_opaque_region(surface->surface,
surface->opaque_region);
wl_region_destroy(surface->opaque_region);
surface->opaque_region = NULL;
}
if (surface->input_region) {
wl_surface_set_input_region(surface->surface,
surface->input_region);
wl_region_destroy(surface->input_region);
surface->input_region = NULL;
}
if (surface->viewport) {
wp_viewport_set_destination(surface->viewport,
widget->viewport_dest_width,
widget->viewport_dest_height);
}
wl_surface_damage(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(surface->surface);
}
int
window_has_focus(struct window *window)
{
@ -1605,7 +1578,7 @@ surface_destroy(struct surface *surface)
wp_viewport_destroy(surface->viewport);
if (surface->cm_surface)
wp_color_management_surface_v1_destroy(surface->cm_surface);
xx_color_management_surface_v4_destroy(surface->cm_surface);
wl_surface_destroy(surface->surface);
@ -1873,9 +1846,8 @@ widget_cairo_update_transform(struct widget *widget, cairo_t *cr)
surface->allocation.width,
surface->allocation.height,
surface->buffer_scale);
cairo_matrix_init(&m, matrix.M.col[0].x, matrix.M.col[0].y,
matrix.M.col[1].x, matrix.M.col[1].y,
matrix.M.col[3].x, matrix.M.col[3].y);
cairo_matrix_init(&m, matrix.d[0], matrix.d[1], matrix.d[4],
matrix.d[5], matrix.d[12], matrix.d[13]);
cairo_transform(cr, &m);
}
@ -3130,8 +3102,10 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
struct input *input = data;
struct xkb_keymap *keymap;
struct xkb_state *state;
#ifdef HAVE_XKBCOMMON_COMPOSE
struct xkb_compose_table *compose_table;
struct xkb_compose_state *compose_state;
#endif
char *locale;
char *map_str;
@ -3179,6 +3153,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
locale = "C";
/* Set up XKB compose table */
#ifdef HAVE_XKBCOMMON_COMPOSE
compose_table =
xkb_compose_table_new_from_locale(input->display->xkb_context,
locale,
@ -3202,6 +3177,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
fprintf(stderr, "could not create XKB compose table for locale '%s'. "
"Disabiling compose\n", locale);
}
#endif
xkb_keymap_unref(input->xkb.keymap);
xkb_state_unref(input->xkb.state);
@ -3252,6 +3228,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
static xkb_keysym_t
process_key_press(xkb_keysym_t sym, struct input *input)
{
#ifdef HAVE_XKBCOMMON_COMPOSE
if (!input->xkb.compose_state)
return sym;
if (sym == XKB_KEY_NoSymbol)
@ -3272,6 +3249,9 @@ process_key_press(xkb_keysym_t sym, struct input *input)
default:
return sym;
}
#else
return sym;
#endif
}
static void
@ -4392,8 +4372,8 @@ undo_resize(struct window *window)
}
}
static void
window_configure_resize(struct window *window, int width, int height)
void
window_schedule_resize(struct window *window, int width, int height)
{
/* We should probably get these numbers from the theme. */
const int min_width = 200, min_height = 200;
@ -4420,12 +4400,6 @@ window_configure_resize(struct window *window, int width, int height)
window->pending_allocation.height = window->min_allocation.height;
window->resize_needed = 1;
}
void
window_schedule_resize(struct window *window, int width, int height)
{
window_configure_resize(window, width, height);
window_schedule_redraw(window);
}
@ -4514,14 +4488,6 @@ xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel,
}
}
/* If the window is being mapped fullscreen,
* save the last pending allocation */
if (window->fullscreen &&
(window->saved_allocation.width == 0 ||
window->saved_allocation.height == 0)) {
window->saved_allocation = window->pending_allocation;
}
if (window->frame) {
if (window->maximized) {
frame_set_flag(window->frame->frame, FRAME_FLAG_MAXIMIZED);
@ -4542,14 +4508,14 @@ xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *xdg_toplevel,
* on the shadow margin to get the difference. */
int margin = window_get_shadow_margin(window);
window_configure_resize(window,
width + margin * 2,
height + margin * 2);
window_schedule_resize(window,
width + margin * 2,
height + margin * 2);
} else if (window->saved_allocation.width > 0 &&
window->saved_allocation.height > 0) {
window_configure_resize(window,
window->saved_allocation.width,
window->saved_allocation.height);
window_schedule_resize(window,
window->saved_allocation.width,
window->saved_allocation.height);
}
}
@ -4971,20 +4937,6 @@ window_set_locked_pointer_motion_handler(struct window *window,
window->locked_pointer_motion_handler = handler;
}
void
window_set_shadow(struct window *window)
{
if (window->frame)
frame_unset_flag(window->frame->frame, FRAME_FLAG_NO_SHADOW);
}
void
window_unset_shadow(struct window *window)
{
if (window->frame)
frame_set_flag(window->frame->frame, FRAME_FLAG_NO_SHADOW);
}
void
window_set_title(struct window *window, const char *title)
{
@ -5946,19 +5898,6 @@ display_destroy_output(struct display *d, uint32_t id)
wl_list_for_each(output, &d->output_list, link) {
if (output->server_output_id == id) {
struct window *window;
/* If a window was on a destroyed output, we need to
* make sure the output doesn't linger on the window's
* output list.
* surface_leave does nothing if the output isn't on
* the list, so we can call it for all windows to remove
* this output.
*/
wl_list_for_each(window, &d->window_list, link) {
surface_leave(window, NULL, output->output);
}
output_destroy(output);
break;
}
@ -6732,7 +6671,7 @@ display_bind_tablets(struct display *d, uint32_t id)
}
static void
cm_supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
cm_supported_intent(void *data, struct xx_color_manager_v4 *xx_color_manager_v4,
uint32_t render_intent)
{
struct display *d = data;
@ -6741,7 +6680,7 @@ cm_supported_intent(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
}
static void
cm_supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
cm_supported_feature(void *data, struct xx_color_manager_v4 *xx_color_manager_v4,
uint32_t feature)
{
struct display *d = data;
@ -6750,31 +6689,24 @@ cm_supported_feature(void *data, struct wp_color_manager_v1 *wp_color_manager_v1
}
static void
cm_supported_tf_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
cm_supported_tf_named(void *data, struct xx_color_manager_v4 *xx_color_manager_v4,
uint32_t tf_code)
{
/* unused in this file */
}
static void
cm_supported_primaries_named(void *data, struct wp_color_manager_v1 *wp_color_manager_v1,
cm_supported_primaries_named(void *data, struct xx_color_manager_v4 *xx_color_manager_v4,
uint32_t primaries_code)
{
/* unused in this file */
}
static void
cm_done(void *data, struct wp_color_manager_v1 *wp_color_manager_v1)
{
/* unused in this file */
}
static const struct wp_color_manager_v1_listener cm_listener = {
static const struct xx_color_manager_v4_listener cm_listener = {
.supported_intent = cm_supported_intent,
.supported_feature = cm_supported_feature,
.supported_tf_named = cm_supported_tf_named,
.supported_primaries_named = cm_supported_primaries_named,
.done = cm_done,
};
static void
@ -6845,17 +6777,12 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
&wp_viewporter_interface, 1);
} else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) {
display_bind_tablets(d, id);
} else if (strcmp(interface, "wp_color_manager_v1") == 0) {
} else if (strcmp(interface, "xx_color_manager_v4") == 0) {
d->color_manager =
wl_registry_bind(registry, id,
&wp_color_manager_v1_interface, 1);
wp_color_manager_v1_add_listener(d->color_manager,
&xx_color_manager_v4_interface, 1);
xx_color_manager_v4_add_listener(d->color_manager,
&cm_listener, d);
} else if (strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) {
d->single_pixel_buffer_manager =
wl_registry_bind(registry, id,
&wp_single_pixel_buffer_manager_v1_interface,
1);
}
if (d->global_handler)
@ -7078,10 +7005,7 @@ display_destroy(struct display *display)
xdg_wm_base_destroy(display->xdg_shell);
if (display->color_manager)
wp_color_manager_v1_destroy(display->color_manager);
if (display->single_pixel_buffer_manager)
wp_single_pixel_buffer_manager_v1_destroy(display->single_pixel_buffer_manager);
xx_color_manager_v4_destroy(display->color_manager);
if (display->shm)
wl_shm_destroy(display->shm);
@ -7147,12 +7071,6 @@ display_get_compositor(struct display *display)
return display->compositor;
}
struct wp_single_pixel_buffer_manager_v1 *
display_get_single_pixel_buffer_manager(struct display *display)
{
return display->single_pixel_buffer_manager;
}
uint32_t
display_get_serial(struct display *display)
{

View file

@ -76,9 +76,6 @@ display_has_subcompositor(struct display *display);
struct wl_compositor *
display_get_compositor(struct display *display);
struct wp_single_pixel_buffer_manager_v1 *
display_get_single_pixel_buffer_manager(struct display *display);
struct output *
display_get_output(struct display *display);
@ -533,12 +530,6 @@ void
window_set_locked_pointer_motion_handler(
struct window *window, window_locked_pointer_motion_handler_t handler);
void
window_set_shadow(struct window *window);
void
window_unset_shadow(struct window *window);
void
window_set_title(struct window *window, const char *title);
@ -613,9 +604,6 @@ widget_cairo_create(struct widget *widget);
struct wl_surface *
widget_get_wl_surface(struct widget *widget);
void
widget_surface_flush(struct widget *widget);
uint32_t
widget_get_last_time(struct widget *widget);

View file

@ -1,29 +0,0 @@
prog_gcovr = find_program('gcovr', required: false, disabler: true)
# Configure the build:
# $ meson configure -Db_sanitize=none -Db_coverage=true -Dwerror=true
#
# Ensure there are no stale .gcno or .gcda files around:
# $ meson setup --wipe ~/git/weston
#
# Run the test suite:
# $ meson compile
# $ meson test
#
# Generate the reports:
# $ meson compile gcovr-report
run_target(
'gcovr-report',
command: [
prog_gcovr,
'--root', '@SOURCE_ROOT@',
'--cobertura', meson.current_build_dir() / 'cobertura.xml',
'--html', meson.current_build_dir() / 'index.html',
'--html-nested',
'--html-theme', 'github.green',
'--html-title', 'Weston test suite coverage',
'--print-summary',
meson.project_build_root(),
],
)

View file

@ -33,7 +33,6 @@ home.png
icon_ivi_clickdot.png
icon_ivi_flower.png
icon_ivi_simple-egl.png
icon_ivi_simple-egl-vertical.png
icon_ivi_simple-shm.png
icon_ivi_smoke.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -9,7 +9,6 @@ install_data(
'icon_ivi_clickdot.png',
'icon_ivi_flower.png',
'icon_ivi_simple-egl.png',
'icon_ivi_simple-egl-vertical.png',
'icon_ivi_simple-shm.png',
'icon_ivi_smoke.png',
'icon_terminal.png',

View file

@ -180,6 +180,12 @@ update_input_panels(struct wl_listener *listener, void *data)
memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t));
}
static int
input_panel_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "input panel");
}
static void
input_panel_committed(struct weston_surface *surface,
struct weston_coord_surface new_origin)
@ -208,7 +214,7 @@ destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
wl_list_remove(&input_panel_surface->link);
input_panel_surface->surface->committed = NULL;
weston_surface_set_label(input_panel_surface->surface, NULL);
weston_surface_set_label_func(input_panel_surface->surface, NULL);
weston_view_destroy(input_panel_surface->view);
free(input_panel_surface);
@ -250,7 +256,7 @@ create_input_panel_surface(struct desktop_shell *shell,
surface->committed = input_panel_committed;
surface->committed_private = input_panel_surface;
weston_surface_set_label_static(surface, "input panel");
weston_surface_set_label_func(surface, input_panel_get_label);
input_panel_surface->shell = shell;

View file

@ -42,14 +42,174 @@
#include <libweston/config-parser.h>
#include "shared/helpers.h"
#include "shared/timespec-util.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
#include <libweston/shell-utils.h>
#include <libweston/desktop.h>
#define DEFAULT_NUM_WORKSPACES 1
#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
struct focus_state {
struct desktop_shell *shell;
struct weston_seat *seat;
struct workspace *ws;
struct weston_surface *keyboard_focus;
struct wl_list link;
struct wl_listener seat_destroy_listener;
struct wl_listener surface_destroy_listener;
};
/*
* Surface stacking and ordering.
*
* This is handled using several linked lists of surfaces, organised into
* layers. The layers are ordered, and each of the surfaces in one layer are
* above all of the surfaces in the layer below. The set of layers is static and
* in the following order (top-most first):
* Lock layer (only ever displayed on its own)
* Cursor layer
* Input panel layer
* Fullscreen layer
* Panel layer
* Workspace layers
* Background layer
*
* The list of layers may be manipulated to remove whole layers of surfaces from
* display. For example, when locking the screen, all layers except the lock
* layer are removed.
*
* A surfaces layer is modified on configuring the surface, in
* set_surface_type() (which is only called when the surfaces type change is
* _committed_). If a surfaces type changes (e.g. when making a window
* fullscreen) its layer changes too.
*
* In order to allow popup and transient surfaces to be correctly stacked above
* their parent surfaces, each surface tracks both its parent surface, and a
* linked list of its children. When a surfaces layer is updated, so are the
* layers of its children. Note that child surfaces are *not* the same as
* subsurfaces child/parent surfaces are purely for maintaining stacking
* order.
*
* The children_link list of siblings of a surface (i.e. those surfaces which
* have the same parent) only contains weston_surfaces which have a
* shell_surface. Stacking is not implemented for non-shell_surface
* weston_surfaces. This means that the following implication does *not* hold:
* (shsurf->parent != NULL) !wl_list_is_empty(shsurf->children_link)
*/
struct shell_surface {
struct wl_signal destroy_signal;
struct weston_desktop_surface *desktop_surface;
struct weston_view *view;
struct weston_surface *wsurface_anim_fade;
struct weston_view *wview_anim_fade;
int32_t last_width, last_height;
struct desktop_shell *shell;
struct wl_list children_list;
struct wl_list children_link;
struct weston_coord_global saved_pos;
bool saved_position_valid;
bool saved_rotation_valid;
int unresponsive, grabbed;
uint32_t resize_edges;
uint32_t orientation;
struct {
struct weston_transform transform;
struct weston_matrix rotation;
} rotation;
struct {
struct weston_curtain *black_view;
} fullscreen;
struct weston_output *fullscreen_output;
struct weston_output *output;
struct wl_listener output_destroy_listener;
struct surface_state {
bool fullscreen;
bool maximized;
bool lowered;
} state;
struct {
bool is_set;
struct weston_coord_global pos;
} xwayland;
int focus_count;
bool destroying;
struct wl_list link; /** desktop_shell::shsurf_list */
};
struct shell_grab {
struct weston_pointer_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
};
struct shell_touch_grab {
struct weston_touch_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
struct weston_touch *touch;
};
struct shell_tablet_tool_grab {
struct weston_tablet_tool_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
struct weston_tablet_tool *tool;
};
struct weston_move_grab {
struct shell_grab base;
struct weston_coord_global delta;
bool client_initiated;
};
struct weston_touch_move_grab {
struct shell_touch_grab base;
int active;
struct weston_coord_global delta;
};
struct weston_tablet_tool_move_grab {
struct shell_tablet_tool_grab base;
wl_fixed_t dx, dy;
};
struct rotate_grab {
struct shell_grab base;
struct weston_matrix rotation;
struct {
float x;
float y;
} center;
};
struct shell_seat {
struct weston_seat *seat;
struct wl_listener seat_destroy_listener;
struct weston_surface *focused_surface;
struct wl_listener caps_changed_listener;
struct wl_listener pointer_focus_listener;
struct wl_listener keyboard_focus_listener;
struct wl_listener tablet_tool_added_listener;
struct wl_list link; /** shell::seat_list */
};
struct tablet_tool_listener {
struct wl_listener base;
struct wl_listener removed_listener;
};
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@ -75,6 +235,20 @@ shell_surface_update_child_surface_layers(struct shell_surface *shsurf);
static void
get_maximized_size(struct shell_surface *shsurf, int32_t *width, int32_t *height);
static struct shell_output *
find_shell_output_from_weston_output(struct desktop_shell *shell,
struct weston_output *output)
{
struct shell_output *shell_output;
wl_list_for_each(shell_output, &shell->output_list, link) {
if (shell_output->output == output)
return shell_output;
}
return NULL;
}
static bool
shsurf_is_max_or_fullscreen(struct shell_surface *shsurf)
{
@ -95,8 +269,8 @@ set_shsurf_size_maximized_or_fullscreen(struct shell_surface *shsurf,
if (fullscreen_requested) {
if (shsurf->output) {
width = shsurf->output->output->width;
height = shsurf->output->output->height;
width = shsurf->output->width;
height = shsurf->output->height;
}
} else if (max_requested) {
/* take the panels into considerations */
@ -163,8 +337,6 @@ desktop_shell_destroy_surface(struct shell_surface *shsurf)
shsurf->output_destroy_listener.notify = NULL;
}
wl_list_remove(&shsurf->surface_label_update.link);
free(shsurf);
}
@ -197,18 +369,21 @@ shell_grab_start(struct shell_grab *grab,
void
get_output_work_area(struct desktop_shell *shell,
struct shell_output *sh_output,
struct weston_output *output,
pixman_rectangle32_t *area)
{
struct weston_output *output;
struct shell_output *sh_output;
area->x = 0;
area->y = 0;
area->width = 0;
area->height = 0;
if (!sh_output)
if (!output)
return;
output = sh_output->output;
sh_output = find_shell_output_from_weston_output(shell, output);
assert(sh_output);
area->x = output->pos.c.x;
area->y = output->pos.c.y;
@ -348,7 +523,6 @@ shell_configuration(struct desktop_shell *shell)
struct weston_config *config;
char *s, *client;
bool allow_zap;
bool disallow_output_changed_move;
config = wet_get_config(shell->compositor);
section = weston_config_get_section(config, "shell", NULL, NULL);
@ -361,11 +535,6 @@ shell_configuration(struct desktop_shell *shell)
"allow-zap", &allow_zap, true);
shell->allow_zap = allow_zap;
weston_config_section_get_bool(section,
"disallow-output-changed-move",
&disallow_output_changed_move, false);
shell->disallow_output_changed_move = disallow_output_changed_move;
shell->binding_modifier = weston_config_get_binding_modifier(config, MODIFIER_SUPER);
weston_config_section_get_string(section, "animation", &s, "none");
@ -398,6 +567,13 @@ shell_configuration(struct desktop_shell *shell)
return true;
}
static int
focus_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "focus highlight effect for output %s",
(surface->output ? surface->output->name : "NULL"));
}
/* no-op func for checking focus surface */
static void
focus_surface_committed(struct weston_surface *es,
@ -421,6 +597,7 @@ create_focus_surface(struct weston_compositor *ec,
.pos = output->pos,
.width = output->width, .height = output->height,
.surface_committed = focus_surface_committed,
.get_label = focus_surface_get_label,
.surface_private = NULL,
.capture_input = false,
};
@ -430,11 +607,8 @@ create_focus_surface(struct weston_compositor *ec,
return NULL;
curtain_params.surface_private = fsurf;
str_printf(&curtain_params.label, "focus highlight effect for output %s",
output->name);
fsurf->curtain = weston_shell_utils_curtain_create(ec, &curtain_params);
weston_view_set_output(fsurf->curtain->view, output);
return fsurf;
@ -887,12 +1061,7 @@ constrain_position(struct weston_move_grab *move)
if (shsurf->shell->panel_position ==
WESTON_DESKTOP_SHELL_PANEL_POSITION_TOP) {
struct shell_output *shoutput = NULL;
if (surface->output)
shoutput = weston_output_get_shell_private(surface->output);
get_output_work_area(shsurf->shell, shoutput, &area);
get_output_work_area(shsurf->shell, surface->output, &area);
geometry =
weston_desktop_surface_get_geometry(shsurf->desktop_surface);
@ -1533,26 +1702,15 @@ shell_surface_set_output(struct shell_surface *shsurf,
{
struct weston_surface *es =
weston_desktop_surface_get_surface(shsurf->desktop_surface);
struct shell_output *shoutput = NULL;
if (output)
shoutput = weston_output_get_shell_private(output);
/* get the default output, if the client set it as NULL
check whether the output is available */
if (shoutput)
shsurf->output = shoutput;
if (output)
shsurf->output = output;
else if (es->output)
shsurf->output = weston_output_get_shell_private(es->output);
else {
struct shell_output *shoutput = NULL;
struct weston_output *w_output;
w_output = weston_shell_utils_get_default_output(es->compositor);
if (w_output)
shoutput = weston_output_get_shell_private(w_output);
shsurf->output = shoutput;
}
shsurf->output = es->output;
else
shsurf->output = weston_shell_utils_get_default_output(es->compositor);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
@ -1563,7 +1721,7 @@ shell_surface_set_output(struct shell_surface *shsurf,
return;
shsurf->output_destroy_listener.notify = notify_output_destroy;
wl_signal_add(&shsurf->output->output->destroy_signal,
wl_signal_add(&shsurf->output->destroy_signal,
&shsurf->output_destroy_listener);
}
@ -1654,6 +1812,34 @@ shell_surface_get_shell(struct shell_surface *shsurf)
return shsurf->shell;
}
static int
black_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
{
struct weston_view *fs_view = surface->committed_private;
struct weston_surface *fs_surface = fs_view->surface;
int n;
int rem;
int ret;
n = snprintf(buf, len, "black background surface for ");
if (n < 0)
return n;
rem = (int)len - n;
if (rem < 0)
rem = 0;
if (fs_surface->get_label)
ret = fs_surface->get_label(fs_surface, buf + n, rem);
else
ret = snprintf(buf + n, rem, "<unknown>");
if (ret < 0)
return n;
return n + ret;
}
static void
black_surface_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
@ -1681,18 +1867,13 @@ shell_set_view_fullscreen(struct shell_surface *shsurf)
struct weston_surface *surface =
weston_desktop_surface_get_surface(shsurf->desktop_surface);
struct weston_compositor *ec = surface->compositor;
struct weston_output *output = NULL;
if (!shsurf->fullscreen_output)
return;
output = shsurf->fullscreen_output->output;
struct weston_output *output = shsurf->fullscreen_output;
struct weston_curtain_params curtain_params = {
.r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0,
.pos = output->pos,
.width = output->width, .height = output->height,
.surface_committed = black_surface_committed,
.get_label = black_surface_get_label,
.surface_private = shsurf->view,
.capture_input = true,
};
@ -1701,16 +1882,14 @@ shell_set_view_fullscreen(struct shell_surface *shsurf)
weston_view_move_to_layer(shsurf->view,
&shsurf->shell->fullscreen_layer.view_list);
weston_shell_utils_center_on_output(shsurf->view, output);
weston_shell_utils_center_on_output(shsurf->view, shsurf->fullscreen_output);
if (!shsurf->fullscreen.black_view) {
str_printf(&curtain_params.label, "black background surface for %s",
surface->label);
shsurf->fullscreen.black_view =
weston_shell_utils_curtain_create(ec, &curtain_params);
}
weston_view_set_output(shsurf->fullscreen.black_view->view,
output);
shsurf->fullscreen_output);
weston_view_move_to_layer(shsurf->fullscreen.black_view->view,
&shsurf->view->layer_link);
@ -1876,8 +2055,8 @@ fade_out_done(struct weston_view_animation *animation, void *data)
if (weston_view_is_mapped(shsurf->wview_anim_fade)) {
weston_view_move_to_layer(shsurf->wview_anim_fade, NULL);
wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
}
wl_event_loop_add_idle(loop, fade_out_done_idle_cb, shsurf);
}
struct shell_surface *
@ -1891,18 +2070,6 @@ get_shell_surface(struct weston_surface *surface)
return NULL;
}
static void
desktop_surface_update_label(struct wl_listener *listener, void *data)
{
struct weston_desktop_surface *desktop_surface = data;
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
char *label;
label = weston_desktop_surface_make_label(desktop_surface);
weston_surface_set_label(surface, label);
}
/*
* libweston-desktop
*/
@ -1919,7 +2086,6 @@ desktop_surface_added(struct weston_desktop_surface *desktop_surface,
struct shell_surface *shsurf;
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
char *label;
view = weston_desktop_surface_create_view(desktop_surface);
if (!view)
@ -1934,6 +2100,8 @@ desktop_surface_added(struct weston_desktop_surface *desktop_surface,
return;
}
weston_surface_set_label_func(surface, weston_shell_utils_surface_get_label);
shsurf->shell = (struct desktop_shell *) shell;
shsurf->unresponsive = 0;
shsurf->saved_position_valid = false;
@ -1961,14 +2129,6 @@ desktop_surface_added(struct weston_desktop_surface *desktop_surface,
wl_list_insert(&shsurf->shell->shsurf_list, &shsurf->link);
weston_desktop_surface_set_user_data(desktop_surface, shsurf);
label = weston_desktop_surface_make_label(desktop_surface);
weston_surface_set_label(surface, label);
/* client-controllable from xdg-shell */
shsurf->surface_label_update.notify = desktop_surface_update_label;
weston_desktop_surface_add_metadata_listener(desktop_surface,
&shsurf->surface_label_update);
}
static void
@ -2001,9 +2161,7 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
shsurf->fullscreen.black_view = NULL;
}
wl_list_remove(&shsurf->surface_label_update.link);
wl_list_init(&shsurf->surface_label_update.link);
weston_surface_set_label_func(surface, NULL);
weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
shsurf->desktop_surface = NULL;
@ -2111,13 +2269,8 @@ map(struct desktop_shell *shell, struct shell_surface *shsurf)
shell_surface_update_layer(shsurf);
if (shsurf->state.maximized) {
struct weston_output *w_output = NULL;
if (shsurf->output)
w_output = shsurf->output->output;
surface->output = w_output;
weston_view_set_output(shsurf->view, w_output);
surface->output = shsurf->output;
weston_view_set_output(shsurf->view, shsurf->output);
}
if (!shell->locked) {
@ -2223,12 +2376,8 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
WESTON_ACTIVATE_FLAG_FULLSCREEN);
}
} else if (shsurf->state.maximized) {
struct weston_output *w_output = NULL;
set_maximized_position(shell, shsurf);
if (surface->output)
w_output = shsurf->output->output;
surface->output = w_output;
surface->output = shsurf->output;
} else {
struct weston_coord_surface offset = buf_offset;
struct weston_coord_global pos;
@ -2616,19 +2765,19 @@ static const struct weston_desktop_api shell_desktop_api = {
/* ************************ *
* end of libweston-desktop *
* ************************ */
static int
background_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "background for output %s",
(surface->output ? surface->output->name : "NULL"));
}
static void
background_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
{
struct shell_output *sh_output = es->committed_private;
struct desktop_shell *shell;
/* The output was destroyed before the background was committed */
if (!sh_output)
return;
shell = sh_output->shell;
struct desktop_shell *shell = sh_output->shell;
if (!weston_surface_has_content(es))
return;
@ -2644,7 +2793,6 @@ background_committed(struct weston_surface *es,
sh_output->output->pos);
weston_view_move_to_layer(sh_output->background_view,
&shell->background_layer.view_list);
weston_output_set_ready(sh_output->output);
}
static void
@ -2664,11 +2812,11 @@ desktop_shell_set_background(struct wl_client *client,
struct wl_resource *output_resource,
struct wl_resource *surface_resource)
{
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct shell_output *sh_output;
struct weston_head *head = weston_head_from_resource(output_resource);
char *label;
if (surface->committed) {
wl_resource_post_error(surface_resource,
@ -2681,7 +2829,7 @@ desktop_shell_set_background(struct wl_client *client,
return;
surface->output = head->output;
sh_output = weston_output_get_shell_private(surface->output);
sh_output = find_shell_output_from_weston_output(shell, surface->output);
if (sh_output->background_surface) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
@ -2691,9 +2839,7 @@ desktop_shell_set_background(struct wl_client *client,
surface->committed = background_committed;
surface->committed_private = sh_output;
str_printf(&label, "background for output %s", surface->output->name);
weston_surface_set_label(surface, label);
weston_surface_set_label_func(surface, background_get_label);
weston_desktop_shell_send_configure(resource, 0,
surface_resource,
@ -2708,22 +2854,21 @@ desktop_shell_set_background(struct wl_client *client,
&sh_output->background_surface_listener);
}
static int
panel_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "panel for output %s",
(surface->output ? surface->output->name : "NULL"));
}
static void
panel_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
{
struct shell_output *sh_output = es->committed_private;
struct weston_output *output;
struct weston_coord_global pos;
struct desktop_shell *shell;
/* The output was destroyed before the panel was committed */
if (!sh_output)
return;
output = sh_output->output;
pos = output->pos;
shell = sh_output->shell;
struct weston_output *output = sh_output->output;
struct weston_coord_global pos = output->pos;
struct desktop_shell *shell = sh_output->shell;
if (!weston_surface_has_content(es))
return;
@ -2778,11 +2923,11 @@ desktop_shell_set_panel(struct wl_client *client,
struct wl_resource *output_resource,
struct wl_resource *surface_resource)
{
struct desktop_shell *shell = wl_resource_get_user_data(resource);
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
struct shell_output *sh_output;
struct weston_head *head = weston_head_from_resource(output_resource);
char *label;
if (surface->committed) {
wl_resource_post_error(surface_resource,
@ -2795,7 +2940,7 @@ desktop_shell_set_panel(struct wl_client *client,
return;
surface->output = head->output;
sh_output = weston_output_get_shell_private(surface->output);
sh_output = find_shell_output_from_weston_output(shell, surface->output);
if (sh_output->panel_surface) {
wl_resource_post_error(surface_resource,
@ -2806,9 +2951,7 @@ desktop_shell_set_panel(struct wl_client *client,
surface->committed = panel_committed;
surface->committed_private = sh_output;
str_printf(&label, "panel for output %s", surface->output->name);
weston_surface_set_label(surface, label);
weston_surface_set_label_func(surface, panel_get_label);
weston_desktop_shell_send_configure(resource, 0,
surface_resource,
@ -2821,6 +2964,12 @@ desktop_shell_set_panel(struct wl_client *client,
wl_signal_add(&surface->destroy_signal, &sh_output->panel_surface_listener);
}
static int
lock_surface_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "lock window");
}
static void
lock_surface_committed(struct weston_surface *surface,
struct weston_coord_surface new_origin)
@ -2877,7 +3026,7 @@ desktop_shell_set_lock_surface(struct wl_client *client,
surface->committed = lock_surface_committed;
surface->committed_private = shell;
weston_surface_set_label_static(surface, "lock window");
weston_surface_set_label_func(surface, lock_surface_get_label);
shell->lock_surface = surface;
shell->lock_surface_listener.notify = handle_lock_surface_destroy;
@ -3283,6 +3432,7 @@ rotate_grab_motion(struct weston_pointer_grab *grab,
}
weston_view_update_transform(shsurf->view);
weston_surface_damage(shsurf->view->surface);
}
static void
@ -3406,7 +3556,7 @@ rotate_binding(struct weston_pointer *pointer, const struct timespec *time,
* the alt-tab switcher, which need to de-promote fullscreen layers. */
void
lower_fullscreen_layer(struct desktop_shell *shell,
struct shell_output *lowering_output)
struct weston_output *lowering_output)
{
struct workspace *ws;
struct weston_view *view, *prev;
@ -3674,6 +3824,13 @@ shell_fade_done(struct weston_view_animation *animation, void *data)
}
}
static int
fade_surface_get_label(struct weston_surface *surface,
char *buf, size_t len)
{
return snprintf(buf, len, "desktop shell fade surface");
}
static struct weston_curtain *
shell_fade_create_view(struct desktop_shell *shell)
{
@ -3682,9 +3839,9 @@ shell_fade_create_view(struct desktop_shell *shell)
struct weston_curtain_params curtain_params = {
.r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0,
.surface_committed = black_surface_committed,
.get_label = fade_surface_get_label,
.surface_private = shell,
.capture_input = true,
.label = xstrdup("desktop shell fade surface"),
};
struct weston_curtain *curtain;
bool first = true;
@ -3711,7 +3868,6 @@ shell_fade_create_view(struct desktop_shell *shell)
curtain_params.pos.c.y = y1;
curtain_params.width = x2 - x1;
curtain_params.height = y2 - y1;
curtain = weston_shell_utils_curtain_create(compositor, &curtain_params);
assert(curtain);
@ -3820,6 +3976,9 @@ shell_fade_init(struct desktop_shell *shell)
if (!shell->fade.curtain)
return;
weston_view_update_transform(shell->fade.curtain->view);
weston_surface_damage(shell->fade.curtain->view->surface);
loop = wl_display_get_event_loop(shell->compositor->wl_display);
shell->fade.startup_timer =
wl_event_loop_add_timer(loop, fade_startup_timeout, shell);
@ -3850,12 +4009,6 @@ wake_handler(struct wl_listener *listener, void *data)
unlock(shell);
}
static void
sleep_handler(struct wl_listener *listener, void *data)
{
weston_log("entering sleep mode: DPMS off\n");
}
static void
transform_handler(struct wl_listener *listener, void *data)
{
@ -3895,7 +4048,6 @@ weston_view_set_initial_position(struct weston_view *view,
int32_t range_x, range_y;
int32_t x, y;
struct weston_output *output, *target_output = NULL;
struct shell_output *shoutput;
struct weston_seat *seat;
pixman_rectangle32_t area;
struct weston_coord_global pos;
@ -3933,9 +4085,7 @@ weston_view_set_initial_position(struct weston_view *view,
* If this is negative it means that the surface is bigger than
* output.
*/
assert(target_output);
shoutput = weston_output_get_shell_private(target_output);
get_output_work_area(shell, shoutput, &area);
get_output_work_area(shell, target_output, &area);
x = area.x;
y = area.y;
@ -4317,12 +4467,6 @@ shell_reposition_view_on_output_change(struct weston_view *view)
struct shell_surface *shsurf;
int visible;
/* We can't simply reposition popups and such, they must move with
* the parent.
*/
if (view->geometry.parent)
return;
if (wl_list_empty(&ec->output_list))
return;
@ -4398,18 +4542,12 @@ shell_output_destroy(struct shell_output *shell_output)
{
struct desktop_shell *shell = shell_output->shell;
if (!shell->disallow_output_changed_move) {
shell_for_each_layer(shell, shell_output_changed_move_layer, NULL);
}
shell_for_each_layer(shell, shell_output_changed_move_layer, NULL);
if (shell_output->panel_surface) {
if (shell_output->panel_surface)
wl_list_remove(&shell_output->panel_surface_listener.link);
shell_output->panel_surface->committed_private = NULL;
}
if (shell_output->background_surface) {
if (shell_output->background_surface)
wl_list_remove(&shell_output->background_surface_listener.link);
shell_output->background_surface->committed_private = NULL;
}
wl_list_remove(&shell_output->destroy_listener.link);
wl_list_remove(&shell_output->link);
free(shell_output);
@ -4469,7 +4607,7 @@ handle_output_resized(struct wl_listener *listener, void *data)
struct desktop_shell *shell =
container_of(listener, struct desktop_shell, resized_listener);
struct weston_output *output = (struct weston_output *)data;
struct shell_output *sh_output = weston_output_get_shell_private(output);
struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output);
handle_output_resized_shsurfs(shell);
@ -4487,8 +4625,6 @@ create_shell_output(struct desktop_shell *shell,
if (shell_output == NULL)
return;
weston_output_set_shell_private(output, shell_output);
shell_output->output = output;
shell_output->shell = shell;
shell_output->destroy_listener.notify = handle_output_destroy;
@ -4496,7 +4632,7 @@ create_shell_output(struct desktop_shell *shell,
&shell_output->destroy_listener);
wl_list_insert(shell->output_list.prev, &shell_output->link);
if (!shell->disallow_output_changed_move && wl_list_length(&shell->output_list) == 1)
if (wl_list_length(&shell->output_list) == 1)
shell_for_each_layer(shell,
shell_output_changed_move_layer, NULL);
}
@ -4523,12 +4659,6 @@ handle_output_move_layer(struct desktop_shell *shell,
if (view->output != output)
continue;
/* We can't simply reposition popups and such, they must move with
* the parent.
*/
if (view->geometry.parent)
continue;
pos = weston_coord_global_add(
weston_view_get_pos_offset_global(view),
output->move);
@ -4627,7 +4757,6 @@ shell_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&shell->destroy_listener.link);
wl_list_remove(&shell->idle_listener.link);
wl_list_remove(&shell->wake_listener.link);
wl_list_remove(&shell->sleep_listener.link);
wl_list_remove(&shell->transform_listener.link);
text_backend_destroy(shell->text_backend);
@ -4809,8 +4938,6 @@ wet_shell_init(struct weston_compositor *ec,
wl_signal_add(&ec->idle_signal, &shell->idle_listener);
shell->wake_listener.notify = wake_handler;
wl_signal_add(&ec->wake_signal, &shell->wake_listener);
shell->sleep_listener.notify = sleep_handler;
wl_signal_add(&ec->sleep_signal, &shell->sleep_listener);
shell->transform_listener.notify = transform_handler;
wl_signal_add(&ec->transform_signal, &shell->transform_listener);

View file

@ -23,9 +23,6 @@
* DEALINGS IN THE SOFTWARE.
*/
#ifndef WESTON_DESKTOP_SHELL_H
#define WESTON_DESKTOP_SHELL_H
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
@ -35,170 +32,6 @@
#include "weston-desktop-shell-server-protocol.h"
struct focus_state {
struct desktop_shell *shell;
struct weston_seat *seat;
struct workspace *ws;
struct weston_surface *keyboard_focus;
struct wl_list link;
struct wl_listener seat_destroy_listener;
struct wl_listener surface_destroy_listener;
};
/*
* Surface stacking and ordering.
*
* This is handled using several linked lists of surfaces, organised into
* layers. The layers are ordered, and each of the surfaces in one layer are
* above all of the surfaces in the layer below. The set of layers is static and
* in the following order (top-most first):
* Lock layer (only ever displayed on its own)
* Cursor layer
* Input panel layer
* Fullscreen layer
* Panel layer
* Workspace layers
* Background layer
*
* The list of layers may be manipulated to remove whole layers of surfaces from
* display. For example, when locking the screen, all layers except the lock
* layer are removed.
*
* A surfaces layer is modified on configuring the surface, in
* set_surface_type() (which is only called when the surfaces type change is
* _committed_). If a surfaces type changes (e.g. when making a window
* fullscreen) its layer changes too.
*
* In order to allow popup and transient surfaces to be correctly stacked above
* their parent surfaces, each surface tracks both its parent surface, and a
* linked list of its children. When a surfaces layer is updated, so are the
* layers of its children. Note that child surfaces are *not* the same as
* subsurfaces child/parent surfaces are purely for maintaining stacking
* order.
*
* The children_link list of siblings of a surface (i.e. those surfaces which
* have the same parent) only contains weston_surfaces which have a
* shell_surface. Stacking is not implemented for non-shell_surface
* weston_surfaces. This means that the following implication does *not* hold:
* (shsurf->parent != NULL) !wl_list_is_empty(shsurf->children_link)
*/
struct shell_surface {
struct wl_signal destroy_signal;
struct weston_desktop_surface *desktop_surface;
struct weston_view *view;
struct weston_surface *wsurface_anim_fade;
struct weston_view *wview_anim_fade;
int32_t last_width, last_height;
struct desktop_shell *shell;
struct wl_list children_list;
struct wl_list children_link;
struct weston_coord_global saved_pos;
bool saved_position_valid;
bool saved_rotation_valid;
int unresponsive, grabbed;
uint32_t resize_edges;
uint32_t orientation;
struct {
struct weston_transform transform;
struct weston_matrix rotation;
} rotation;
struct {
struct weston_curtain *black_view;
} fullscreen;
struct shell_output *fullscreen_output;
struct shell_output *output;
struct wl_listener output_destroy_listener;
struct wl_listener surface_label_update;
struct surface_state {
bool fullscreen;
bool maximized;
bool lowered;
} state;
struct {
bool is_set;
struct weston_coord_global pos;
} xwayland;
int focus_count;
bool destroying;
struct wl_list link; /** desktop_shell::shsurf_list */
};
struct shell_grab {
struct weston_pointer_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
};
struct shell_touch_grab {
struct weston_touch_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
struct weston_touch *touch;
};
struct shell_tablet_tool_grab {
struct weston_tablet_tool_grab grab;
struct shell_surface *shsurf;
struct wl_listener shsurf_destroy_listener;
struct weston_tablet_tool *tool;
};
struct weston_move_grab {
struct shell_grab base;
struct weston_coord_global delta;
bool client_initiated;
};
struct weston_touch_move_grab {
struct shell_touch_grab base;
int active;
struct weston_coord_global delta;
};
struct weston_tablet_tool_move_grab {
struct shell_tablet_tool_grab base;
wl_fixed_t dx, dy;
};
struct rotate_grab {
struct shell_grab base;
struct weston_matrix rotation;
struct {
float x;
float y;
} center;
};
struct shell_seat {
struct weston_seat *seat;
struct wl_listener seat_destroy_listener;
struct weston_surface *focused_surface;
struct wl_listener caps_changed_listener;
struct wl_listener pointer_focus_listener;
struct wl_listener keyboard_focus_listener;
struct wl_listener tablet_tool_added_listener;
struct wl_list link; /** shell::seat_list */
};
struct tablet_tool_listener {
struct wl_listener base;
struct wl_listener removed_listener;
};
enum animation_type {
ANIMATION_NONE,
@ -251,7 +84,6 @@ struct desktop_shell {
struct wl_listener idle_listener;
struct wl_listener wake_listener;
struct wl_listener sleep_listener;
struct wl_listener transform_listener;
struct wl_listener resized_listener;
struct wl_listener destroy_listener;
@ -308,7 +140,6 @@ struct desktop_shell {
} fade;
bool allow_zap;
bool disallow_output_changed_move;
uint32_t binding_modifier;
enum animation_type win_animation_type;
enum animation_type win_close_animation_type;
@ -345,12 +176,12 @@ get_current_workspace(struct desktop_shell *shell);
void
get_output_work_area(struct desktop_shell *shell,
struct shell_output *output,
struct weston_output *output,
pixman_rectangle32_t *area);
void
lower_fullscreen_layer(struct desktop_shell *shell,
struct shell_output *lowering_output);
struct weston_output *lowering_output);
void
activate(struct desktop_shell *shell, struct weston_view *view,
@ -368,5 +199,3 @@ void
shell_for_each_layer(struct desktop_shell *shell,
shell_for_each_layer_func_t func,
void *data);
#endif /* WESTON_DESKTOP_SHELL_H */

View file

@ -1,19 +0,0 @@
buffers {
size_kb: 16384
fill_policy: RING_BUFFER
}
data_sources {
config {
name: "track_event"
track_event_config {
enabled_categories: "mesa.default"
enabled_categories: "mesa.slow"
}
}
}
duration_ms: 5000
write_into_file: true
file_write_period_ms: 500
flush_period_ms: 500

View file

@ -196,8 +196,7 @@ epub_exclude_files = ['search.html']
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
intersphinx_mapping = {'https://docs.python.org/3': None}
# -- Options for todo extension ----------------------------------------------

View file

@ -1208,6 +1208,15 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.

View file

@ -14,16 +14,14 @@ Welcome to Weston documentation!
Weston
------
Weston is a Wayland compositor designed for correctness, reliability,
predictability, and performance.
Weston is the reference implementation of a Wayland compositor, as well as a
useful environment in and of itself.
Out of the box, Weston provides a very basic desktop, or a full-featured
environment for non-desktop uses such as automotive, embedded, in-flight,
industrial, kiosks, set-top boxes and TVs.
It also provides a library called :ref:`libweston-label` which allows
users to build their own custom full-featured environments on top of
Weston's core.
industrial, kiosks, set-top boxes and TVs. It also provides a library allowing
other projects to build their own full-featured environments on top of Weston's
core.
The core focus of Weston is correctness and reliability. Weston aims to be lean
and fast, but more importantly, to be predictable. Whilst Weston does have

View file

@ -48,7 +48,7 @@ doxygen_conf_weston = configure_file(
script_data = configuration_data()
script_data.set('SRCDIR', meson.current_build_dir())
script_data.set('OUTDIR', meson.current_build_dir() / 'weston')
script_data.set('OUTDIR', meson.current_build_dir() + '/doc')
# Set a different directory for doctrees to avoid installing them
script_data.set('DOCTREES_DIR', meson.current_build_dir() + '/doctrees')
@ -82,11 +82,9 @@ endif
sphinx_doc = custom_target(
'weston-doc-breathe',
command: script_doxy_sphinx,
output: 'weston',
output: 'doc',
build_by_default: true,
env: sphinx_env,
install: true,
install_dir: dir_data / 'doc',
)
# we need this because we will have a stale 'doc' directory
@ -95,3 +93,10 @@ docs = run_target(
'docs',
command: script_doxy_sphinx,
)
install_subdir(
sphinx_doc.full_path(),
install_dir: dir_data / 'doc' / 'weston',
exclude_files: '.buildinfo',
strip_directory: true,
)

View file

@ -6,15 +6,4 @@ else
SPHINX_WERROR=""
fi
set -e
BUILDINFO_ORIG="@OUTDIR@/.buildinfo"
BUILDINFO_SAVE="@SRCDIR@/buildinfo.save"
[ -f "$BUILDINFO_SAVE" ] && mv -f "$BUILDINFO_SAVE" "$BUILDINFO_ORIG"
@DOXYGEN_CMD@ @DOXYGEN_CONF@
@SPHINX_CMD@ $SPHINX_WERROR -E -q -j auto -d @DOCTREES_DIR@ @SRCDIR@ @OUTDIR@
mv -f "$BUILDINFO_ORIG" "$BUILDINFO_SAVE"
@DOXYGEN_CMD@ @DOXYGEN_CONF@ && @SPHINX_CMD@ $SPHINX_WERROR -E -q -j auto -d @DOCTREES_DIR@ @SRCDIR@ @OUTDIR@

View file

@ -86,8 +86,7 @@ the surface was added to. However, the views are not provided to the IVI
controller.
After configuring all expected changes, the controller must call the
``commit_changes`` to atomically update the display layout and call
``screen_ready`` to inform the compositor that it can start issueing repaints.
``commit_changes`` to atomically update the display layout.
IVI-shell example implementation
--------------------------------

View file

@ -1,5 +1,3 @@
.. _libweston-label:
Libweston
=========
@ -12,7 +10,6 @@ Libweston
libweston/shell-utils.rst
libweston/output-management.rst
libweston/log.rst
libweston/debug-flight-recorder.rst
`Libweston` is an effort to separate the re-usable parts of Weston into a
library. `Libweston` provides most of the boring and tedious bits of correctly

View file

@ -1,51 +0,0 @@
.. _debugging flight recorder:
Debugging with Flight Recorder
==============================
Weston can write debug scopes data to a circular ring buffer. This ring
buffer can be accessed through a debug key, assuming you have a keyboard
attached, or in case Weston dies, through a coredump. This document describes
how to access that data in the later case.
The ring buffer data can be accessed with a gdb python script that searches
the coredump file for the that ring buffer address in order to retrieve
data from it.
Prior to setting this up make sure that flight recorder is configured
accordingly. Make sure that Weston is started with the debug scopes that
you're interested into. For instance if you'd like to get the :samp:`drm-backend` one
Weston should show when starting up:
::
Flight recorder: enabled, scopes subscribed: drm-backend
For that Weston needs to be started with :samp:`--debug -f drm-backend`.
Also, make sure that the system is configured to generate a core dump. Refer
to :samp:`man core(5)` for how to do that.
Next you'll need the `gdb python
script <https://gitlab.freedesktop.org/wayland/weston/-/blob/main/doc/scripts/gdb/flight_rec.py>`_,
as that will be needed to search for the ring buffer within the coredump.
Finally, to make this easier and push everything from the ring buffer to a
file, we would need to create a batch gdb file script to invoke the commands
for us.
As an example name that file :file:`test.gdb` and add the following to entries
to it, making sure to adjust the path for the python script.
::
source /path/to/flight_rec.py
display_flight_rec
Then run the following commands to dump the contents of the ring buffer
straight to a file:
::
$ gdb --batch --command=/path/to/test.gdb -q /path/to/test/weston/binary --core /path/to/coredump &> dump.log.txt

View file

@ -141,9 +141,8 @@ force the contents to be printed on :samp:`stdout` file-descriptor.
The user has first to specify which log scope to subscribe to.
Specifying which scopes to subscribe for the flight-recorder can be done using
:samp:`-f|--flight-rec-scopes`. By default, only the 'log' scope is subscribed
to. See :ref:`debugging flight recorder` on how retrieve the contents of the
flight recorder in case Weston dies/crashes unexpectedly.
:samp:`--flight-rec-scopes`. By default, the 'log' scope and 'drm-backend' are
the scopes subscribed to.
weston-debug protocol
~~~~~~~~~~~~~~~~~~~~~
@ -179,17 +178,6 @@ The following illustrates how to use it:
./weston-debug timeline > log.json
./wesgr -i log.json -o log.svg
Weston has experimental support for `Perfetto <https://perfetto.dev>`_ for
performance profiling. It can be enabled by using `-Dperfetto=true` during
the meson invocation to configure the build.
If Perfetto support is built in, timeline points are added to Perfetto tracks
when Perfetto is running, even when the 'timeline' scope is not enabled.
For capturing a trace you can use the supplied
`out of process trace <https://gitlab.freedesktop.org/wayland/weston/-/tree/main/doc/perfetto/perfetto_out_of_process_trace.cfg>`_.
config file.
Inserting timeline points
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -198,13 +186,6 @@ take the :type:`weston_compositor` instance, followed by the name of the
timeline point. What follows next is a variable number of arguments, which
**must** end with the macro :c:macro:`TLP_END`.
Adding Perfetto trace points
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In addition to timeline points, Perfetto can also display timing information
for individual functions. The easiest way to add profiling data for a function
is to insert the :c:macro:`WESTON_TRACE_FUNC` at the top of the function.
Debug protocol API
------------------

View file

@ -2,7 +2,6 @@
files = [
'compositor.rst',
'head.rst',
'debug-flight-recorder.rst',
'log.rst',
'output.rst',
'output-management.rst',

View file

@ -35,15 +35,12 @@ stitching them together is performed by a *renderer*. By doing so, it is
compositing all surfaces into a single image, which is being handed out to a
back-end, and finally, displayed on the screen.
libweston provides multiple useful renderers. There are
`OpenGL ES <https://www.khronos.org/opengles/>`_ and
`Vulkan <https://www.vulkan.org/>`_ renderers, which will often be accelerated
by your GPU when suitable drivers are installed.
Another uses the `Pixman <http://www.pixman.org>`_ library which is entirely
CPU (software) rendered.
You can select between these with the ``--renderer=gl``, ``--renderer=vulkan``
and ``--renderer=pixman`` arguments when starting Weston.
libweston provides two useful renderers. One uses
`OpenGL ES <https://www.khronos.org/opengles/>`_, which will often be accelerated
by your GPU when suitable drivers are installed. The other uses the
`Pixman <http://www.pixman.org>`_ library which is entirely CPU (software)
rendered. You can select between these with the ``--renderer=gl`` and
``--renderer=pixman`` arguments when starting Weston.
Multi-back-end support
----------------------

View file

@ -90,8 +90,7 @@ Standalone tests
Standalone tests do not have a fixture setup function defined in the test
program or the fixture setup function calls
:func:`weston_test_harness_execute_standalone` explicitly. All test cases must
be defined with :c:func:`TEST` or :c:func:`TEST_P`, and each such function must
return a value from :type:`test_result_code`.
be defined with :c:func:`TEST` or :c:func:`TEST_P`.
This is the simplest possible test example:
@ -99,7 +98,7 @@ This is the simplest possible test example:
TEST(always_success)
{
return RESULT_OK;
/* true */
}
@ -111,8 +110,7 @@ Plugin tests
Plugin tests must have a fixture setup function that calls
:func:`weston_test_harness_execute_as_plugin`. All test cases must be defined
with :c:func:`PLUGIN_TEST` which declares an implicit function argument
:type:`weston_compositor` ``*compositor``. Each such function must
return a value from :type:`test_result_code`.
:type:`weston_compositor` ``*compositor``.
The compositor fixture manufactures the necessary environment variables and the
command line argument array to launch Weston, and calls :func:`wet_main`
@ -139,7 +137,6 @@ This is an example of a plugin test that just logs a line:
{
/* struct weston_compositor *compositor; */
testlog("Got compositor %p\n", compositor);
return RESULT_OK;
}
@ -150,8 +147,7 @@ Client tests
Plugin tests must have a fixture setup function that calls
:func:`weston_test_harness_execute_as_client`. All test cases must be
defined with :c:func:`TEST` or :c:func:`TEST_P`, and each such function must
return a value from :type:`test_result_code`.
defined with :c:func:`TEST` or :c:func:`TEST_P`.
The compositor fixture manufactures the necessary environment variables and the
command line argument array to launch Weston, and calls :func:`wet_main`
@ -206,7 +202,6 @@ clients:
expect_protocol_error(client, &wp_viewport_interface,
WP_VIEWPORT_ERROR_BAD_VALUE);
return RESULT_OK;
}
TEST(test_roundtrip)
@ -215,7 +210,6 @@ clients:
client = create_client_and_test_surface(100, 50, 123, 77);
client_roundtrip(client);
return RESULT_OK;
}
@ -263,6 +257,15 @@ type of tests to keep the fixture setup simple. See
:ref:`test-suite-standalone`, :ref:`test-suite-plugin` and
:ref:`test-suite-client` how to set up each type in a test program.
.. note::
**TODO:** Currently it is not possible to gracefully skip or fail a test.
You can skip with ``exit(RESULT_SKIP)`` but that will quit the whole test
program and all defined tests that were not ran yet will be counted as
failed. You can fail a test by any means, e.g. ``exit(RESULT_FAIL)``, but
the same caveat applies. Succeeded tests must simply return and not call any
exit function.
.. toctree::
:hidden:

View file

@ -31,7 +31,6 @@
#include <libweston/config-parser.h>
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#include "weston-private.h"
struct {
@ -65,10 +64,12 @@ get_backend_from_string(const char *name,
return false;
}
static const struct weston_enum_map renderer_name_map[] = {
struct {
char *name;
enum weston_renderer_type renderer;
} renderer_name_map[] = {
{ "auto", WESTON_RENDERER_AUTO },
{ "gl", WESTON_RENDERER_GL },
{ "vulkan", WESTON_RENDERER_VULKAN },
{ "noop", WESTON_RENDERER_NOOP },
{ "pixman", WESTON_RENDERER_PIXMAN },
};
@ -77,15 +78,16 @@ bool
get_renderer_from_string(const char *name,
enum weston_renderer_type *renderer)
{
const struct weston_enum_map *entry;
size_t i;
if (!name)
name = "auto";
entry = weston_enum_map_find_name(renderer_name_map, name);
if (entry) {
*renderer = entry->value;
return true;
for (i = 0; i < ARRAY_LENGTH(renderer_name_map); i++) {
if (strcmp(name, renderer_name_map[i].name) == 0) {
*renderer = renderer_name_map[i].renderer;
return true;
}
}
return false;

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,6 @@ deps_weston = [
dep_libevdev,
dep_libdl,
dep_threads,
dep_libdisplay_info,
]
if get_option('xwayland')
@ -68,6 +67,32 @@ install_data(
install_dir: dir_data / 'wayland-sessions'
)
if get_option('screenshare')
srcs_screenshare = [
'screen-share.c',
fullscreen_shell_unstable_v1_client_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
]
deps_screenshare = [
dep_libexec_weston,
dep_libshared,
dep_libweston_public,
dep_libweston_private_h, # XXX: https://gitlab.freedesktop.org/wayland/weston/issues/292
dep_wayland_client,
]
plugin_screenshare = shared_library(
'screen-share',
srcs_screenshare,
include_directories: common_inc,
dependencies: deps_screenshare,
name_prefix: '',
install: true,
install_dir: dir_module_weston,
install_rpath: '$ORIGIN'
)
env_modmap += 'screen-share.so=@0@;'.format(plugin_screenshare.full_path())
endif
if get_option('systemd')
dep_libsystemd = dependency('libsystemd', required: false)
if not dep_libsystemd.found()

1247
frontend/screen-share.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -36,6 +36,11 @@ bool
get_renderer_from_string(const char *name,
enum weston_renderer_type *renderer);
int
wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc,
struct weston_config_section *section);
int
wet_output_set_eotf_mode(struct weston_output *output,
struct weston_config_section *section,
@ -48,8 +53,3 @@ wet_output_set_colorimetry_mode(struct weston_output *output,
typedef void (*wet_head_additional_setup)(struct weston_head *head,
struct weston_head *head_to_mirror);
struct weston_color_profile *
wet_create_output_color_profile(struct weston_output *output,
struct weston_config *wc,
const char *prof_name);

View file

@ -38,6 +38,7 @@ struct screenshooter {
struct wl_client *client;
struct wl_listener client_destroy_listener;
struct wl_listener compositor_destroy_listener;
struct weston_recorder *recorder;
struct wl_listener authorization;
};
@ -79,6 +80,30 @@ screenshooter_binding(struct weston_keyboard *keyboard,
&shooter->client_destroy_listener);
}
static void
recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
uint32_t key, void *data)
{
struct weston_compositor *ec = keyboard->seat->compositor;
struct weston_output *output;
struct screenshooter *shooter = data;
struct weston_recorder *recorder = shooter->recorder;;
static const char filename[] = "capture.wcap";
if (recorder) {
weston_recorder_stop(recorder);
shooter->recorder = NULL;
} else {
if (keyboard->focus && keyboard->focus->output)
output = keyboard->focus->output;
else
output = container_of(ec->output_list.next,
struct weston_output, link);
shooter->recorder = weston_recorder_start(output, filename);
}
}
static void
authorize_screenshooter(struct wl_listener *l,
struct weston_output_capture_attempt *att)
@ -116,6 +141,8 @@ screenshooter_create(struct weston_compositor *ec)
weston_compositor_add_key_binding(ec, KEY_S, MODIFIER_SUPER,
screenshooter_binding, shooter);
weston_compositor_add_key_binding(ec, KEY_R, MODIFIER_SUPER,
recorder_binding, shooter);
shooter->compositor_destroy_listener.notify = screenshooter_destroy;
wl_signal_add(&ec->destroy_signal,

View file

@ -115,7 +115,6 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd
struct weston_config *config = wet_get_config(wxw->compositor);
struct weston_config_section *section;
struct wl_client *client;
struct weston_client *wcl;
struct wl_event_loop *loop;
struct custom_env child_env;
int no_cloexec_fds[5];
@ -186,10 +185,6 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd
goto err_proc;
}
wcl = weston_compositor_get_client(wxw->compositor, client);
weston_client_set_internal_name(wcl, "(Xw)%" PRIu64,
weston_client_get_internal_id(wcl));
wxw->wm_fd = x11_wm_socket.fds[0];
/* Now we can no longer fail, close the child end of our sockets */
@ -265,10 +260,8 @@ wet_load_xwayland(struct weston_compositor *comp)
wxw->compositor = comp;
wxw->api = api;
wxw->xwayland = xwayland;
if (api->listen(xwayland, wxw, spawn_xserver) < 0) {
free(wxw);
if (api->listen(xwayland, wxw, spawn_xserver) < 0)
return NULL;
}
return wxw;
}

View file

@ -0,0 +1,974 @@
/*
* Copyright © 2013 Jason Ekstrand
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <libweston/libweston.h>
#include "frontend/weston.h"
#include "fullscreen-shell-unstable-v1-server-protocol.h"
#include "shared/helpers.h"
#include <libweston/shell-utils.h>
struct fullscreen_shell {
struct wl_client *client;
struct wl_listener client_destroyed;
struct wl_listener destroy_listener;
struct weston_compositor *compositor;
struct weston_layer layer;
struct wl_list output_list;
struct wl_listener output_created_listener;
struct wl_listener output_resized_listener;
struct wl_listener output_moved_listener;
struct wl_listener seat_created_listener;
/* List of one surface per client, presented for the NULL output
*
* This is implemented as a list in case someone fixes the shell
* implementation to support more than one client.
*/
struct wl_list default_surface_list; /* struct fs_client_surface::link */
};
struct fs_output {
struct fullscreen_shell *shell;
struct wl_list link;
struct weston_output *output;
struct wl_listener output_destroyed;
struct {
struct weston_surface *surface;
struct wl_listener surface_destroyed;
struct wl_resource *mode_feedback;
int presented_for_mode;
enum zwp_fullscreen_shell_v1_present_method method;
int32_t framerate;
} pending;
struct weston_surface *surface;
struct wl_listener surface_destroyed;
struct weston_view *view;
struct weston_curtain *curtain;
struct weston_transform transform; /* matrix from x, y */
int presented_for_mode;
enum zwp_fullscreen_shell_v1_present_method method;
uint32_t framerate;
};
struct pointer_focus_listener {
struct fullscreen_shell *shell;
struct wl_listener pointer_focus;
struct wl_listener seat_caps;
struct wl_listener seat_destroyed;
};
struct fs_client_surface {
struct weston_surface *surface;
enum zwp_fullscreen_shell_v1_present_method method;
struct wl_list link; /* struct fullscreen_shell::default_surface_list */
struct wl_listener surface_destroyed;
};
static void
remove_default_surface(struct fs_client_surface *surf)
{
wl_list_remove(&surf->surface_destroyed.link);
wl_list_remove(&surf->link);
free(surf);
}
static void
default_surface_destroy_listener(struct wl_listener *listener, void *data)
{
struct fs_client_surface *surf;
surf = container_of(listener, struct fs_client_surface, surface_destroyed);
remove_default_surface(surf);
}
static void
replace_default_surface(struct fullscreen_shell *shell, struct weston_surface *surface,
enum zwp_fullscreen_shell_v1_present_method method)
{
struct fs_client_surface *surf, *prev = NULL;
if (!wl_list_empty(&shell->default_surface_list))
prev = container_of(shell->default_surface_list.prev,
struct fs_client_surface, link);
if (prev)
remove_default_surface(prev);
if (!surface)
return;
surf = zalloc(sizeof *surf);
if (!surf)
return;
surf->surface = surface;
surf->method = method;
wl_list_insert(shell->default_surface_list.prev, &surf->link);
surf->surface_destroyed.notify = default_surface_destroy_listener;
wl_signal_add(&surface->destroy_signal, &surf->surface_destroyed);
}
static void
pointer_focus_changed(struct wl_listener *listener, void *data)
{
struct weston_pointer *pointer = data;
if (pointer->focus && pointer->focus->surface->resource)
weston_seat_set_keyboard_focus(pointer->seat, pointer->focus->surface);
}
static void
seat_caps_changed(struct wl_listener *l, void *data)
{
struct weston_seat *seat = data;
struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct pointer_focus_listener *listener;
struct fs_output *fsout;
listener = container_of(l, struct pointer_focus_listener, seat_caps);
/* no pointer */
if (pointer) {
if (!listener->pointer_focus.link.prev) {
wl_signal_add(&pointer->focus_signal,
&listener->pointer_focus);
}
} else {
if (listener->pointer_focus.link.prev) {
wl_list_remove(&listener->pointer_focus.link);
}
}
if (keyboard && keyboard->focus != NULL) {
wl_list_for_each(fsout, &listener->shell->output_list, link) {
if (fsout->surface) {
weston_seat_set_keyboard_focus(seat, fsout->surface);
return;
}
}
}
}
static void
seat_destroyed(struct wl_listener *l, void *data)
{
struct pointer_focus_listener *listener;
listener = container_of(l, struct pointer_focus_listener,
seat_destroyed);
free(listener);
}
static void
seat_created(struct wl_listener *l, void *data)
{
struct weston_seat *seat = data;
struct pointer_focus_listener *listener;
listener = zalloc(sizeof *listener);
if (!listener)
return;
listener->shell = container_of(l, struct fullscreen_shell,
seat_created_listener);
listener->pointer_focus.notify = pointer_focus_changed;
listener->seat_caps.notify = seat_caps_changed;
listener->seat_destroyed.notify = seat_destroyed;
wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
seat_caps_changed(&listener->seat_caps, seat);
}
static void
black_surface_committed(struct weston_surface *es,
struct weston_coord_surface new_origin)
{
}
static struct weston_curtain *
create_curtain(struct weston_compositor *ec, struct fs_output *fsout,
struct weston_coord_global pos, int w, int h)
{
struct weston_curtain_params curtain_params = {
.r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0,
.pos = pos, .width = w, .height = h,
.surface_committed = black_surface_committed,
.get_label = NULL,
.surface_private = fsout,
.capture_input = true,
};
struct weston_curtain *curtain;
curtain = weston_shell_utils_curtain_create(ec, &curtain_params);
if (!curtain) {
weston_log("no memory\n");
return NULL;
}
return curtain;
}
static void
fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
enum zwp_fullscreen_shell_v1_present_method method,
int32_t framerate, int presented_for_mode);
static void
fs_output_apply_pending(struct fs_output *fsout);
static void
fs_output_clear_pending(struct fs_output *fsout);
static void
fs_output_destroy(struct fs_output *fsout)
{
fs_output_set_surface(fsout, NULL, 0, 0, 0);
fs_output_clear_pending(fsout);
weston_shell_utils_curtain_destroy(fsout->curtain);
wl_list_remove(&fsout->link);
if (fsout->output)
wl_list_remove(&fsout->output_destroyed.link);
free(fsout);
}
static void
output_destroyed(struct wl_listener *listener, void *data)
{
struct fs_output *output = container_of(listener,
struct fs_output,
output_destroyed);
fs_output_destroy(output);
}
static void
surface_destroyed(struct wl_listener *listener, void *data)
{
struct fs_output *fsout = container_of(listener,
struct fs_output,
surface_destroyed);
fsout->surface = NULL;
fsout->view = NULL;
wl_list_remove(&fsout->transform.link);
wl_list_init(&fsout->transform.link);
}
static void
pending_surface_destroyed(struct wl_listener *listener, void *data)
{
struct fs_output *fsout = container_of(listener,
struct fs_output,
pending.surface_destroyed);
fsout->pending.surface = NULL;
}
static void
configure_presented_surface_internal(struct weston_surface *surface);
static struct fs_output *
fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
{
struct weston_seat *seat;
struct fs_output *fsout;
struct fs_client_surface *surf;
fsout = zalloc(sizeof *fsout);
if (!fsout)
return NULL;
fsout->shell = shell;
wl_list_insert(&shell->output_list, &fsout->link);
wl_list_init(&fsout->transform.link);
fsout->output = output;
fsout->output_destroyed.notify = output_destroyed;
wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
fsout->surface_destroyed.notify = surface_destroyed;
fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
fsout->curtain = create_curtain(shell->compositor, fsout,
output->pos,
output->width, output->height);
weston_view_move_to_layer(fsout->curtain->view,
&shell->layer.view_list);
if (!wl_list_empty(&shell->default_surface_list)) {
surf = container_of(shell->default_surface_list.prev,
struct fs_client_surface, link);
fs_output_set_surface(fsout, surf->surface, surf->method, 0, 0);
configure_presented_surface_internal(surf->surface);
wl_list_for_each(seat, &shell->compositor->seat_list, link) {
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && !keyboard->focus)
weston_seat_set_keyboard_focus(seat, surf->surface);
}
}
return fsout;
}
static struct fs_output *
fs_output_for_output(struct weston_output *output)
{
struct wl_listener *listener;
if (!output)
return NULL;
listener = wl_signal_get(&output->destroy_signal, output_destroyed);
return container_of(listener, struct fs_output, output_destroyed);
}
static void
restore_output_mode(struct weston_output *output)
{
if (output && output->original_mode)
weston_output_mode_switch_to_native(output);
}
static void
fs_output_scale_view(struct fs_output *fsout, float width, float height)
{
int32_t surf_x, surf_y, surf_width, surf_height;
struct weston_matrix *matrix;
struct weston_view *view = fsout->view;
struct weston_output *output = fsout->output;
struct weston_coord_global pos = fsout->output->pos;
weston_shell_utils_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
&surf_width, &surf_height);
if (output->width == surf_width && output->height == surf_height) {
pos.c.x -= surf_x;
pos.c.y -= surf_y;
weston_view_set_position(view, pos);
weston_view_remove_transform(fsout->view, &fsout->transform);
} else {
matrix = &fsout->transform.matrix;
weston_matrix_init(matrix);
weston_matrix_scale(matrix, width / surf_width,
height / surf_height, 1);
weston_view_add_transform(fsout->view,
&fsout->view->geometry.transformation_list,
&fsout->transform);
pos.c.x += (output->width - width) / 2 - surf_x;
pos.c.y += (output->height - height) / 2 - surf_y;
weston_view_set_position(view, pos);
}
}
static void
fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
static void
fs_output_configure_simple(struct fs_output *fsout,
struct weston_surface *configured_surface)
{
struct weston_output *output = fsout->output;
float output_aspect, surface_aspect;
int32_t surf_x, surf_y, surf_width, surf_height;
struct weston_coord_global pos;
if (fsout->pending.surface == configured_surface)
fs_output_apply_pending(fsout);
assert(fsout->view);
restore_output_mode(fsout->output);
wl_list_remove(&fsout->transform.link);
wl_list_init(&fsout->transform.link);
weston_shell_utils_subsurfaces_boundingbox(fsout->view->surface,
&surf_x, &surf_y,
&surf_width, &surf_height);
output_aspect = (float) output->width / (float) output->height;
surface_aspect = (float) surf_width / (float) surf_height;
switch (fsout->method) {
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
weston_shell_utils_center_on_output(fsout->view, fsout->output);
break;
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
if (output_aspect < surface_aspect)
fs_output_scale_view(fsout,
output->width,
output->width / surface_aspect);
else
fs_output_scale_view(fsout,
output->height * surface_aspect,
output->height);
break;
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
if (output_aspect < surface_aspect)
fs_output_scale_view(fsout,
output->height * surface_aspect,
output->height);
else
fs_output_scale_view(fsout,
output->width,
output->width / surface_aspect);
break;
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
fs_output_scale_view(fsout, output->width, output->height);
break;
default:
break;
}
pos = fsout->output->pos;
pos.c.x -= surf_x;
pos.c.y -= surf_y;
weston_view_set_position(fsout->curtain->view, pos);
weston_surface_set_size(fsout->curtain->view->surface,
fsout->output->width,
fsout->output->height);
}
static void
fs_output_configure_for_mode(struct fs_output *fsout,
struct weston_surface *configured_surface)
{
int32_t surf_x, surf_y, surf_width, surf_height;
struct weston_mode mode;
struct weston_coord_global pos;
int ret;
if (fsout->pending.surface != configured_surface) {
/* Nothing to really reconfigure. We'll just recenter the
* view in case they played with subsurfaces */
weston_shell_utils_center_on_output(fsout->view, fsout->output);
return;
}
/* We have a pending surface */
weston_shell_utils_subsurfaces_boundingbox(fsout->pending.surface,
&surf_x, &surf_y,
&surf_width, &surf_height);
/* The actual output mode is in physical units. We need to
* transform the surface size to physical unit size by flipping and
* possibly scaling it.
*/
switch (fsout->output->transform) {
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
mode.width = surf_height * fsout->output->native_scale;
mode.height = surf_width * fsout->output->native_scale;
break;
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_180:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
default:
mode.width = surf_width * fsout->output->native_scale;
mode.height = surf_height * fsout->output->native_scale;
}
mode.flags = 0;
mode.refresh = fsout->pending.framerate;
ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
fsout->output->native_scale);
if (ret != 0) {
/* The mode switch failed. Clear the pending and
* reconfigure as per normal */
if (fsout->pending.mode_feedback) {
zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
fsout->pending.mode_feedback);
wl_resource_destroy(fsout->pending.mode_feedback);
fsout->pending.mode_feedback = NULL;
}
fs_output_clear_pending(fsout);
return;
}
if (fsout->pending.mode_feedback) {
zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
fsout->pending.mode_feedback);
wl_resource_destroy(fsout->pending.mode_feedback);
fsout->pending.mode_feedback = NULL;
}
fs_output_apply_pending(fsout);
pos = fsout->output->pos;
pos.c.x -= surf_x;
pos.c.y -= surf_y;
weston_view_set_position(fsout->view, pos);
}
static void
fs_output_configure(struct fs_output *fsout,
struct weston_surface *surface)
{
if (fsout->pending.surface == surface) {
if (fsout->pending.presented_for_mode)
fs_output_configure_for_mode(fsout, surface);
else
fs_output_configure_simple(fsout, surface);
} else {
if (fsout->presented_for_mode)
fs_output_configure_for_mode(fsout, surface);
else
fs_output_configure_simple(fsout, surface);
}
weston_output_schedule_repaint(fsout->output);
}
static void
configure_presented_surface(struct weston_surface *surface,
struct weston_coord_surface new_origin)
{
configure_presented_surface_internal(surface);
}
static void
configure_presented_surface_internal(struct weston_surface *surface)
{
struct fullscreen_shell *shell = surface->committed_private;
struct fs_output *fsout;
if (surface->committed != configure_presented_surface)
return;
if (!weston_surface_has_content(surface))
return;
if (!weston_surface_is_mapped(surface))
weston_surface_map(surface);
wl_list_for_each(fsout, &shell->output_list, link)
if (fsout->surface == surface ||
fsout->pending.surface == surface)
fs_output_configure(fsout, surface);
}
static void
fs_output_apply_pending(struct fs_output *fsout)
{
assert(fsout->pending.surface);
if (!weston_surface_is_mapped(fsout->pending.surface) &&
!weston_surface_has_content(fsout->pending.surface))
return;
if (fsout->surface && fsout->surface != fsout->pending.surface) {
wl_list_remove(&fsout->surface_destroyed.link);
weston_view_destroy(fsout->view);
fsout->view = NULL;
if (wl_list_empty(&fsout->surface->views)) {
fsout->surface->committed = NULL;
fsout->surface->committed_private = NULL;
}
fsout->surface = NULL;
}
fsout->method = fsout->pending.method;
fsout->framerate = fsout->pending.framerate;
fsout->presented_for_mode = fsout->pending.presented_for_mode;
if (fsout->surface != fsout->pending.surface) {
fsout->surface = fsout->pending.surface;
if (!weston_surface_is_mapped(fsout->surface))
weston_surface_map(fsout->surface);
fsout->view = weston_view_create(fsout->surface);
if (!fsout->view) {
weston_log("no memory\n");
return;
}
wl_signal_add(&fsout->surface->destroy_signal,
&fsout->surface_destroyed);
weston_view_move_to_layer(fsout->view,
&fsout->shell->layer.view_list);
}
fs_output_clear_pending(fsout);
}
static void
fs_output_clear_pending(struct fs_output *fsout)
{
if (!fsout->pending.surface)
return;
if (fsout->pending.mode_feedback) {
zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
fsout->pending.mode_feedback);
wl_resource_destroy(fsout->pending.mode_feedback);
fsout->pending.mode_feedback = NULL;
}
wl_list_remove(&fsout->pending.surface_destroyed.link);
fsout->pending.surface = NULL;
}
static void
fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
enum zwp_fullscreen_shell_v1_present_method method,
int32_t framerate, int presented_for_mode)
{
fs_output_clear_pending(fsout);
if (surface) {
if (!surface->committed) {
surface->committed = configure_presented_surface;
surface->committed_private = fsout->shell;
}
fsout->pending.surface = surface;
wl_signal_add(&fsout->pending.surface->destroy_signal,
&fsout->pending.surface_destroyed);
fsout->pending.method = method;
fsout->pending.framerate = framerate;
fsout->pending.presented_for_mode = presented_for_mode;
} else if (fsout->surface) {
/* we clear immediately */
wl_list_remove(&fsout->surface_destroyed.link);
weston_view_destroy(fsout->view);
fsout->view = NULL;
if (wl_list_empty(&fsout->surface->views)) {
fsout->surface->committed = NULL;
fsout->surface->committed_private = NULL;
}
fsout->surface = NULL;
weston_output_schedule_repaint(fsout->output);
}
}
static void
fullscreen_shell_release(struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy(resource);
}
static void
fullscreen_shell_present_surface(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_res,
uint32_t method,
struct wl_resource *output_res)
{
struct fullscreen_shell *shell =
wl_resource_get_user_data(resource);
struct weston_surface *surface;
struct weston_seat *seat;
struct fs_output *fsout;
surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
switch(method) {
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
break;
default:
wl_resource_post_error(resource,
ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
"Invalid presentation method");
}
if (output_res) {
struct weston_head *head =
weston_head_from_resource(output_res);
if (!head)
return;
fsout = fs_output_for_output(head->output);
fs_output_set_surface(fsout, surface, method, 0, 0);
} else {
replace_default_surface(shell, surface, method);
wl_list_for_each(fsout, &shell->output_list, link)
fs_output_set_surface(fsout, surface, method, 0, 0);
}
if (surface) {
wl_list_for_each(seat, &shell->compositor->seat_list, link) {
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && !keyboard->focus)
weston_seat_set_keyboard_focus(seat, surface);
}
}
}
static void
mode_feedback_destroyed(struct wl_resource *resource)
{
struct fs_output *fsout = wl_resource_get_user_data(resource);
fsout->pending.mode_feedback = NULL;
}
static void
fullscreen_shell_present_surface_for_mode(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_res,
struct wl_resource *output_res,
int32_t framerate,
uint32_t feedback_id)
{
struct fullscreen_shell *shell =
wl_resource_get_user_data(resource);
struct weston_surface *surface;
struct weston_seat *seat;
struct fs_output *fsout;
struct weston_head *head = weston_head_from_resource(output_res);
if (!head)
return;
fsout = fs_output_for_output(head->output);
if (surface_res == NULL) {
fs_output_set_surface(fsout, NULL, 0, 0, 0);
return;
}
surface = wl_resource_get_user_data(surface_res);
fs_output_set_surface(fsout, surface, 0, framerate, 1);
fsout->pending.mode_feedback =
wl_resource_create(client,
&zwp_fullscreen_shell_mode_feedback_v1_interface,
1, feedback_id);
wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
fsout, mode_feedback_destroyed);
wl_list_for_each(seat, &shell->compositor->seat_list, link) {
struct weston_keyboard *keyboard =
weston_seat_get_keyboard(seat);
if (keyboard && !keyboard->focus)
weston_seat_set_keyboard_focus(seat, surface);
}
}
struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
fullscreen_shell_release,
fullscreen_shell_present_surface,
fullscreen_shell_present_surface_for_mode,
};
static void
output_geometry_changed(struct wl_listener *listener, void *data)
{
struct fs_output *fsout;
fsout = fs_output_for_output(data);
if (fsout && fsout->surface)
fs_output_configure(fsout, fsout->surface);
}
static void
output_created(struct wl_listener *listener, void *data)
{
struct fullscreen_shell *shell;
shell = container_of(listener, struct fullscreen_shell,
output_created_listener);
fs_output_create(shell, data);
}
static void
client_destroyed(struct wl_listener *listener, void *data)
{
struct fullscreen_shell *shell = container_of(listener,
struct fullscreen_shell,
client_destroyed);
shell->client = NULL;
}
static void
bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
uint32_t id)
{
struct fullscreen_shell *shell = data;
struct wl_resource *resource;
if (shell->client != NULL && shell->client != client)
return;
else if (shell->client == NULL) {
shell->client = client;
wl_client_add_destroy_listener(client, &shell->client_destroyed);
}
resource = wl_resource_create(client,
&zwp_fullscreen_shell_v1_interface,
1, id);
wl_resource_set_implementation(resource,
&fullscreen_shell_implementation,
shell, NULL);
if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
zwp_fullscreen_shell_v1_send_capability(resource,
ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
zwp_fullscreen_shell_v1_send_capability(resource,
ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
}
static void
fullscreen_shell_destroy(struct wl_listener *listener, void *data)
{
struct fs_output *fs_output, *fs_output_next;
struct fs_client_surface *surf;
struct fullscreen_shell *shell =
container_of(listener, struct fullscreen_shell, destroy_listener);
/* remove the curtain(s) */
wl_list_for_each_safe(fs_output, fs_output_next, &shell->output_list, link)
fs_output_destroy(fs_output);
wl_list_remove(&shell->output_created_listener.link);
wl_list_remove(&shell->output_moved_listener.link);
wl_list_remove(&shell->output_resized_listener.link);
if (!wl_list_empty(&shell->default_surface_list)) {
surf = container_of(shell->default_surface_list.prev,
struct fs_client_surface, link);
remove_default_surface(surf);
}
weston_layer_fini(&shell->layer);
free(shell);
}
WL_EXPORT int
wet_shell_init(struct weston_compositor *compositor,
int *argc, char *argv[])
{
struct fullscreen_shell *shell;
struct weston_seat *seat;
struct weston_output *output;
shell = zalloc(sizeof *shell);
if (shell == NULL)
return -1;
shell->compositor = compositor;
if (!weston_compositor_add_destroy_listener_once(compositor,
&shell->destroy_listener,
fullscreen_shell_destroy)) {
free(shell);
return 0;
}
wl_list_init(&shell->default_surface_list);
shell->client_destroyed.notify = client_destroyed;
weston_layer_init(&shell->layer, compositor);
weston_layer_set_position(&shell->layer,
WESTON_LAYER_POSITION_FULLSCREEN);
wl_list_init(&shell->output_list);
shell->output_created_listener.notify = output_created;
wl_signal_add(&compositor->output_created_signal,
&shell->output_created_listener);
wl_list_for_each(output, &compositor->output_list, link)
fs_output_create(shell, output);
shell->output_resized_listener.notify = output_geometry_changed;
wl_signal_add(&compositor->output_resized_signal,
&shell->output_resized_listener);
shell->output_moved_listener.notify = output_geometry_changed;
wl_signal_add(&compositor->output_moved_signal,
&shell->output_moved_listener);
shell->seat_created_listener.notify = seat_created;
wl_signal_add(&compositor->seat_created_signal,
&shell->seat_created_listener);
wl_list_for_each(seat, &compositor->seat_list, link)
seat_created(&shell->seat_created_listener, seat);
wl_global_create(compositor->wl_display,
&zwp_fullscreen_shell_v1_interface, 1, shell,
bind_fullscreen_shell);
screenshooter_create(compositor);
return 0;
}

View file

@ -0,0 +1,20 @@
if get_option('shell-fullscreen')
srcs_shell_fullscreen = [
'fullscreen-shell.c',
fullscreen_shell_unstable_v1_server_protocol_h,
fullscreen_shell_unstable_v1_protocol_c,
]
deps_shell_fullscreen = [
dep_libweston_public,
dep_libexec_weston,
]
shared_library(
'fullscreen-shell',
srcs_shell_fullscreen,
include_directories: common_inc,
dependencies: deps_shell_fullscreen,
name_prefix: '',
install: true,
install_dir: dir_module_weston
)
endif

View file

@ -258,14 +258,6 @@ struct weston_drm_backend_config {
* rendering device.
*/
char *additional_devices;
/** Try to offload blend-to-output color transformation
*
* As KMS currently only supports to offload the transformation in a
* LUT, this may result in precision issues. Also, this requires
* "color-management" to be enabled.
*/
bool offload_blend_to_output;
};
#ifdef __cplusplus

View file

@ -49,11 +49,6 @@ struct weston_headless_backend_config {
* mHz to 1,000,000 mHz. 0 is a special value that triggers repaints
* only on capture requests, not on damages. */
int refresh;
/** Create a fake seat, some clients may complain without a wl_seat.
* The default is not to create a wl_seat.
*/
bool fake_seat;
};
#ifdef __cplusplus

View file

@ -54,20 +54,19 @@ struct weston_pipewire_output_api {
const char *name,
const struct pipewire_config *config);
/** Set the size and frame rate of a PipeWire output to the specified value.
/** Set the size of a PipeWire output to the specified width and height.
*
* If the width or height or framerate are set to -1, the size or frame rate
* of the underlying PipeWire head will be used.
* If the width or height are set to -1, the size of the underlying
* PipeWire head will be used.
*
* \param output The weston output for which the size shall be set
* \param width Desired width of the output
* \param height Desired height of the output
* \param framerate Desired frame rate of the output
*
* Returns 0 on success, -1 on failure.
*/
int (*output_set_size)(struct weston_output *output,
int width, int height, int framerate);
int width, int height);
/** The pixel format to be used by the output.
*

View file

@ -83,7 +83,6 @@ struct weston_rdp_backend_config {
char *rdp_key;
char *server_cert;
char *server_key;
int vmconnect;
int env_socket;
bool resizeable;
int force_no_compression;
@ -94,7 +93,6 @@ struct weston_rdp_backend_config {
rdp_audio_in_teardown audio_in_teardown;
rdp_audio_out_setup audio_out_setup;
rdp_audio_out_teardown audio_out_teardown;
char *nla_ntlm_db;
};
#ifdef __cplusplus

View file

@ -1,314 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2012-2025 Collabora, Ltd.
* Copyright © 2017, 2018 General Electric Company
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <libweston/linalg-3.h>
struct weston_compositor;
struct weston_color_profile_param_builder;
struct weston_color_profile;
struct weston_color_transform;
/** Colorimetry mode for outputs and heads
*
* A list of colorimetry modes for driving displays, defined by ANSI/CTA-861-H.
*
* On heads, a bitmask of one or more entries shows which modes are claimed
* supported.
*
* On outputs, the mode to be used for driving the video sink.
*
* Default (RGB) colorimetry differs from all the others in that the signal
* colorimetry is not defined here. It is defined by the video sink, and it
* may be described in e.g. EDID.
*/
enum weston_colorimetry_mode {
/** Invalid colorimetry mode, or none supported. */
WESTON_COLORIMETRY_MODE_NONE = 0,
/** Default (RGB) colorimetry, video sink dependant */
WESTON_COLORIMETRY_MODE_DEFAULT = 0x01,
/** Rec. ITU-R BT.2020 constant luminance YCbCr */
WESTON_COLORIMETRY_MODE_BT2020_CYCC = 0x02,
/** Rec. ITU-R BT.2020 non-constant luminance YCbCr */
WESTON_COLORIMETRY_MODE_BT2020_YCC = 0x04,
/** Rec. ITU-R BT.2020 RGB */
WESTON_COLORIMETRY_MODE_BT2020_RGB = 0x08,
/** SMPTE ST 2113 DCI-P3 RGB D65 */
WESTON_COLORIMETRY_MODE_P3D65 = 0x10,
/** SMPTE ST 2113 DCI-P3 RGB Theater */
WESTON_COLORIMETRY_MODE_P3DCI = 0x20,
/** Rec. ITU-R BT.2100 ICtCp HDR (with PQ and/or HLG)*/
WESTON_COLORIMETRY_MODE_ICTCP = 0x40,
};
/** Bitmask of all defined colorimetry modes */
#define WESTON_COLORIMETRY_MODE_ALL_MASK \
((uint32_t)(WESTON_COLORIMETRY_MODE_DEFAULT | \
WESTON_COLORIMETRY_MODE_BT2020_CYCC | \
WESTON_COLORIMETRY_MODE_BT2020_YCC | \
WESTON_COLORIMETRY_MODE_BT2020_RGB | \
WESTON_COLORIMETRY_MODE_P3D65 | \
WESTON_COLORIMETRY_MODE_P3DCI | \
WESTON_COLORIMETRY_MODE_ICTCP))
const char *
weston_colorimetry_mode_to_str(enum weston_colorimetry_mode c);
/** EOTF mode for outputs and heads
*
* A list of EOTF modes for driving displays, defined by CTA-861-G for
* Dynamic Range and Mastering InfoFrame.
*
* On heads, a bitmask of one or more entries shows which modes are claimed
* supported.
*
* On outputs, the mode to be used for driving the video sink.
*
* For traditional non-HDR sRGB, use WESTON_EOTF_MODE_SDR.
*/
enum weston_eotf_mode {
/** Invalid EOTF mode, or none supported. */
WESTON_EOTF_MODE_NONE = 0,
/** Traditional gamma, SDR luminance range */
WESTON_EOTF_MODE_SDR = 0x01,
/** Traditional gamma, HDR luminance range */
WESTON_EOTF_MODE_TRADITIONAL_HDR = 0x02,
/** Preceptual quantizer, SMPTE ST 2084 */
WESTON_EOTF_MODE_ST2084 = 0x04,
/** Hybrid log-gamma, ITU-R BT.2100 */
WESTON_EOTF_MODE_HLG = 0x08,
};
/** Bitmask of all defined EOTF modes */
#define WESTON_EOTF_MODE_ALL_MASK \
((uint32_t)(WESTON_EOTF_MODE_SDR | WESTON_EOTF_MODE_TRADITIONAL_HDR | \
WESTON_EOTF_MODE_ST2084 | WESTON_EOTF_MODE_HLG))
const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e);
/** CIE 1931 xy chromaticity coordinates */
struct weston_CIExy {
float x;
float y;
};
/** Chromaticity coordinates and white point that defines the color gamut */
struct weston_color_gamut {
struct weston_CIExy primary[3]; /* RGB order */
struct weston_CIExy white_point;
};
void
weston_color_gamut_from_protocol(struct weston_color_gamut *dst,
int32_t r_x, int32_t r_y,
int32_t g_x, int32_t g_y,
int32_t b_x, int32_t b_y,
int32_t w_x, int32_t w_y);
enum weston_npm_direction {
WESTON_NPM_FORWARD,
WESTON_NPM_INVERSE
};
bool
weston_normalized_primary_matrix_init(struct weston_mat3f *npm,
const struct weston_color_gamut *gamut,
enum weston_npm_direction dir);
struct weston_mat3f
weston_bradford_adaptation(struct weston_CIExy from, struct weston_CIExy to);
/** Color primaries known by libweston */
enum weston_color_primaries {
WESTON_PRIMARIES_CICP_SRGB = 0,
WESTON_PRIMARIES_CICP_PAL_M,
WESTON_PRIMARIES_CICP_PAL,
WESTON_PRIMARIES_CICP_NTSC,
WESTON_PRIMARIES_CICP_GENERIC_FILM,
WESTON_PRIMARIES_CICP_BT2020,
WESTON_PRIMARIES_CICP_CIE1931_XYZ,
WESTON_PRIMARIES_CICP_DCI_P3,
WESTON_PRIMARIES_CICP_DISPLAY_P3,
WESTON_PRIMARIES_ADOBE_RGB,
};
/** Transfer functions known by libweston */
enum weston_transfer_function {
WESTON_TF_BT1886 = 0,
WESTON_TF_GAMMA22,
WESTON_TF_GAMMA28,
WESTON_TF_SRGB,
WESTON_TF_EXT_SRGB,
WESTON_TF_ST240,
WESTON_TF_ST428,
WESTON_TF_ST2084_PQ,
WESTON_TF_EXT_LINEAR,
WESTON_TF_LOG_100,
WESTON_TF_LOG_316,
WESTON_TF_XVYCC,
WESTON_TF_HLG,
WESTON_TF_POWER,
};
enum weston_alpha_mode {
WESTON_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL = 0,
WESTON_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
WESTON_ALPHA_MODE_STRAIGHT,
};
enum weston_color_matrix_coef {
WESTON_COLOR_MATRIX_COEF_UNSET = 0,
WESTON_COLOR_MATRIX_COEF_IDENTITY,
WESTON_COLOR_MATRIX_COEF_BT601,
WESTON_COLOR_MATRIX_COEF_BT709,
WESTON_COLOR_MATRIX_COEF_BT2020,
};
enum weston_color_quant_range {
WESTON_COLOR_QUANT_RANGE_UNSET = 0,
WESTON_COLOR_QUANT_RANGE_FULL,
WESTON_COLOR_QUANT_RANGE_LIMITED,
};
enum weston_ycbcr_chroma_location {
WESTON_YCBCR_CHROMA_LOCATION_UNSET = 0,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_0,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_1,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_2,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_3,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_4,
WESTON_YCBCR_CHROMA_LOCATION_TYPE_5,
};
/** Error codes that the color profile parameters functions may return. */
enum weston_color_profile_param_builder_error {
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF = 0,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_PRIMARIES_NAMED,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_CIE_XY_OUT_OF_RANGE,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_CREATE_FAILED,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_LUMINANCE,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INCOMPLETE_SET,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_ALREADY_SET,
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_UNSUPPORTED,
};
struct weston_color_profile_param_builder *
weston_color_profile_param_builder_create(struct weston_compositor *compositor);
void
weston_color_profile_param_builder_destroy(struct weston_color_profile_param_builder *builder);
bool
weston_color_profile_param_builder_get_error(struct weston_color_profile_param_builder *builder,
enum weston_color_profile_param_builder_error *err,
char **err_msg);
bool
weston_color_profile_param_builder_set_primaries(struct weston_color_profile_param_builder *builder,
const struct weston_color_gamut *primaries);
bool
weston_color_profile_param_builder_set_primaries_named(struct weston_color_profile_param_builder *builder,
enum weston_color_primaries primaries);
bool
weston_color_profile_param_builder_set_tf_named(struct weston_color_profile_param_builder *builder,
enum weston_transfer_function tf);
bool
weston_color_profile_param_builder_set_tf_power_exponent(struct weston_color_profile_param_builder *builder,
float power_exponent);
bool
weston_color_profile_param_builder_set_primary_luminance(struct weston_color_profile_param_builder *builder,
float ref_lum, float min_lum, float max_lum);
bool
weston_color_profile_param_builder_set_target_primaries(struct weston_color_profile_param_builder *builder,
const struct weston_color_gamut *target_primaries);
bool
weston_color_profile_param_builder_set_target_primaries_named(struct weston_color_profile_param_builder *builder,
enum weston_color_primaries target_primaries);
bool
weston_color_profile_param_builder_set_target_luminance(struct weston_color_profile_param_builder *builder,
float min_lum, float max_lum);
bool
weston_color_profile_param_builder_set_maxFALL(struct weston_color_profile_param_builder *builder,
float maxFALL);
bool
weston_color_profile_param_builder_set_maxCLL(struct weston_color_profile_param_builder *builder,
float maxCLL);
struct weston_color_profile *
weston_color_profile_param_builder_create_color_profile(struct weston_color_profile_param_builder *builder,
const char *name_part,
enum weston_color_profile_param_builder_error *err,
char **err_msg);
struct weston_color_profile *
weston_color_profile_ref(struct weston_color_profile *cprof);
void
weston_color_profile_unref(struct weston_color_profile *cprof);
const char *
weston_color_profile_get_description(struct weston_color_profile *cprof);
char *
weston_color_profile_get_details(struct weston_color_profile *cprof);
struct weston_color_profile *
weston_compositor_load_icc_file(struct weston_compositor *compositor,
const char *path);
#ifdef __cplusplus
}
#endif

View file

@ -32,7 +32,6 @@ extern "C" {
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#define WESTON_CONFIG_FILE_ENV_VAR "WESTON_CONFIG_FILE"
@ -108,20 +107,6 @@ int weston_config_next_section(struct weston_config *config,
uint32_t
weston_config_get_binding_modifier(struct weston_config *config, uint32_t default_mod);
/** Container for an array of strings. */
struct weston_string_array {
/** Length of \c array. */
size_t len;
/** Pointer to an array of strings. */
char **array;
};
void
weston_string_array_fini(struct weston_string_array *strarr);
struct weston_string_array
weston_parse_space_separated_list(const char *str);
#ifdef __cplusplus
}
#endif

View file

@ -217,8 +217,6 @@ struct weston_size
weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface);
struct weston_size
weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface);
char *
weston_desktop_surface_make_label(struct weston_desktop_surface *surface);
struct weston_desktop_surface *
weston_desktop_surface_get_parent(struct weston_desktop_surface *surface);
void

File diff suppressed because it is too large Load diff

View file

@ -1,259 +0,0 @@
/*
* Copyright 2025 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <math.h>
#include <libweston/linalg-types.h>
/* ================= 3-vectors and 3x3 matrices ============== */
/** Construct a column vector from elements */
#define WESTON_VEC3F(x, y, z) ((struct weston_vec3f){ .el = { (x), (y), (z) }})
/** Construct the [0, 0, 0]^T vector */
#define WESTON_VEC3F_ZERO ((struct weston_vec3f){ .el = {}})
/** Construct matrix from elements a{row}{column} */
#define WESTON_MAT3F(a00, a01, a02, \
a10, a11, a12, \
a20, a21, a22) \
((struct weston_mat3f){ .colmaj = { \
a00, a10, a20, \
a01, a11, a21, \
a02, a12, a22, \
}})
/** Construct the identity 3x3 matrix */
#define WESTON_MAT3F_IDENTITY \
((struct weston_mat3f){ .colmaj = { \
1.0f, 0.0f, 0.0f, \
0.0f, 1.0f, 0.0f, \
0.0f, 0.0f, 1.0f, \
}})
/** Construct a diagonal matrix */
static inline struct weston_mat3f
weston_m3f_diag(struct weston_vec3f d)
{
return WESTON_MAT3F(
d.x, 0.0f, 0.0f,
0.0f, d.y, 0.0f,
0.0f, 0.0f, d.z);
}
/** Copy the top-left 3x3 from 4x4 */
static inline struct weston_mat3f
weston_m3f_from_m4f_xyz(struct weston_mat4f M)
{
return WESTON_MAT3F(
M.col[0].el[0], M.col[1].el[0], M.col[2].el[0],
M.col[0].el[1], M.col[1].el[1], M.col[2].el[1],
M.col[0].el[2], M.col[1].el[2], M.col[2].el[2]
);
}
/** Drop w from vec4f */
static inline struct weston_vec3f
weston_v3f_from_v4f_xyz(struct weston_vec4f v)
{
return WESTON_VEC3F(v.x, v.y, v.z);
}
/** 3-vector dot product */
static inline float
weston_v3f_dot_v3f(struct weston_vec3f a, struct weston_vec3f b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
/**
* Convert an array of vec3f into planar format
*
* Takes an array of RGB triplets and converts it into a planar format where all R
* values come first, then all G values, then all B values.
*
* \param planar The destination array for planar data, must have space for 3 * len floats
* \param arr Array of RGB triplets as vec3f structs
* \param len Number of RGB triplets in the array
*/
static inline void
weston_v3f_array_to_planar(float *planar, const struct weston_vec3f *arr, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
planar[i ] = arr[i].r;
planar[i + len] = arr[i].g;
planar[i + 2 * len] = arr[i].b;
}
}
/** Clamp each element to the range [a, b], replacing NaN with a. */
static inline struct weston_vec3f
weston_v3f_clamp(struct weston_vec3f v, float a, float b)
{
return WESTON_VEC3F(v.x >= a ? (v.x <= b ? v.x : b) : a,
v.y >= a ? (v.y <= b ? v.y : b) : a,
v.z >= a ? (v.z <= b ? v.z : b) : a);
}
/** Element-wise vector subtraction a - b */
static inline struct weston_vec3f
weston_v3f_sub_v3f(struct weston_vec3f a, struct weston_vec3f b)
{
return WESTON_VEC3F(a.x - b.x,
a.y - b.y,
a.z - b.z);
}
/** Element-wise vector sum a + b */
static inline struct weston_vec3f
weston_v3f_add_v3f(struct weston_vec3f a, struct weston_vec3f b)
{
return WESTON_VEC3F(a.x + b.x,
a.y + b.y,
a.z + b.z);
}
/**
* Matrix infinity-norm
*
* http://www.netlib.org/lapack/lug/node75.html
*/
static inline float
weston_m3f_inf_norm(struct weston_mat3f M)
{
unsigned row;
double infnorm = -1.0;
for (row = 0; row < 3; row++) {
unsigned col;
double sum = 0.0;
for (col = 0; col < 3; col++)
sum += fabsf(M.col[col].el[row]);
if (infnorm < sum)
infnorm = sum;
}
return infnorm;
}
/** Transpose 3x3 matrix */
static inline struct weston_mat3f
weston_m3f_transpose(struct weston_mat3f M)
{
struct weston_mat3f R;
unsigned i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
R.col[j].el[i] = M.col[i].el[j];
return R;
}
/** Matrix-vector multiplication A * b */
static inline struct weston_vec3f
weston_m3f_mul_v3f(struct weston_mat3f A, struct weston_vec3f b)
{
struct weston_vec3f result;
unsigned r;
for (r = 0; r < 3; r++) {
struct weston_vec3f row =
WESTON_VEC3F(A.col[0].el[r], A.col[1].el[r], A.col[2].el[r]);
result.el[r] = weston_v3f_dot_v3f(row, b);
}
return result;
}
/** Matrix multiplication A * B */
static inline struct weston_mat3f
weston_m3f_mul_m3f(struct weston_mat3f A, struct weston_mat3f B)
{
struct weston_mat3f result;
unsigned c;
for (c = 0; c < 3; c++)
result.col[c] = weston_m3f_mul_v3f(A, B.col[c]);
return result;
}
/** Element-wise matrix addition A + B */
static inline struct weston_mat3f
weston_m3f_add_m3f(struct weston_mat3f A, struct weston_mat3f B)
{
struct weston_mat3f R;
unsigned i;
for (i = 0; i < 3 * 3; i++)
R.colmaj[i] = A.colmaj[i] + B.colmaj[i];
return R;
}
/** Element-wise matrix subtraction A - B */
static inline struct weston_mat3f
weston_m3f_sub_m3f(struct weston_mat3f A, struct weston_mat3f B)
{
struct weston_mat3f R;
unsigned i;
for (i = 0; i < 3 * 3; i++)
R.colmaj[i] = A.colmaj[i] - B.colmaj[i];
return R;
}
/** Element-wise scalar multiplication */
static inline struct weston_mat3f
weston_m3f_mul_scalar(struct weston_mat3f M, float scalar)
{
struct weston_mat3f R;
unsigned i;
for (i = 0; i < 3 * 3; i++)
R.colmaj[i] = scalar * M.colmaj[i];
return R;
}
bool
weston_m3f_invert(struct weston_mat3f *out, struct weston_mat3f M);
#ifdef __cplusplus
}
#endif

View file

@ -1,206 +0,0 @@
/*
* Copyright 2025 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <math.h>
#include <libweston/linalg-types.h>
/* ================= 4-vectors and 4x4 matrices ============== */
/** Construct a column vector from elements */
#define WESTON_VEC4F(x, y, z, w) ((struct weston_vec4f){ .el = { (x), (y), (z), (w) }})
/** Construct the [0, 0, 0, 0]^T vector */
#define WESTON_VEC4F_ZERO ((struct weston_vec4f){ .el = {}})
/** Construct matrix from elements a{row}{column} */
#define WESTON_MAT4F(a00, a01, a02, a03, \
a10, a11, a12, a13, \
a20, a21, a22, a23, \
a30, a31, a32, a33) \
((struct weston_mat4f){ .colmaj = { \
a00, a10, a20, a30, \
a01, a11, a21, a31, \
a02, a12, a22, a32, \
a03, a13, a23, a33, \
}})
/** Construct the identity 4x4 matrix */
#define WESTON_MAT4F_IDENTITY \
((struct weston_mat4f){ .colmaj = { \
1.0f, 0.0f, 0.0f, 0.0f, \
0.0f, 1.0f, 0.0f, 0.0f, \
0.0f, 0.0f, 1.0f, 0.0f, \
0.0f, 0.0f, 0.0f, 1.0f, \
}})
/** Construct a translation matrix */
static inline struct weston_mat4f
weston_m4f_translation(float tx, float ty, float tz)
{
return WESTON_MAT4F(
1.0f, 0.0f, 0.0f, tx,
0.0f, 1.0f, 0.0f, ty,
0.0f, 0.0f, 1.0f, tz,
0.0f, 0.0f, 0.0f, 1.0f);
}
/** Construct a scaling matrix */
static inline struct weston_mat4f
weston_m4f_scaling(float sx, float sy, float sz)
{
return WESTON_MAT4F(
sx, 0.0f, 0.0f, 0.0f,
0.0f, sy, 0.0f, 0.0f,
0.0f, 0.0f, sz, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
/** Construct a 2D x-y rotation matrix
*
* \param cos_th Cosine of the counter-clockwise angle.
* \param sin_th Sine of the counter-clockwise angle.
*/
static inline struct weston_mat4f
weston_m4f_rotation_xy(float cos_th, float sin_th)
{
return WESTON_MAT4F(
cos_th, -sin_th, 0.0f, 0.0f,
sin_th, cos_th, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
static inline struct weston_mat4f
weston_m4f_from_m3f_v3f(struct weston_mat3f R, struct weston_vec3f t)
{
return WESTON_MAT4F(
R.col[0].el[0], R.col[1].el[0], R.col[2].el[0], t.el[0],
R.col[0].el[1], R.col[1].el[1], R.col[2].el[1], t.el[1],
R.col[0].el[2], R.col[1].el[2], R.col[2].el[2], t.el[2],
0.0f, 0.0f, 0.0f, 1.0f
);
}
/** 4-vector dot product */
static inline float
weston_v4f_dot_v4f(struct weston_vec4f a, struct weston_vec4f b)
{
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
/**
* Matrix infinity-norm
*
* http://www.netlib.org/lapack/lug/node75.html
*/
static inline float
weston_m4f_inf_norm(struct weston_mat4f M)
{
unsigned row;
double infnorm = -1.0;
for (row = 0; row < 4; row++) {
unsigned col;
double sum = 0.0;
for (col = 0; col < 4; col++)
sum += fabsf(M.col[col].el[row]);
if (infnorm < sum)
infnorm = sum;
}
return infnorm;
}
/** Transpose 4x4 matrix */
static inline struct weston_mat4f
weston_m4f_transpose(struct weston_mat4f M)
{
struct weston_mat4f R;
unsigned i, j;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
R.col[j].el[i] = M.col[i].el[j];
return R;
}
/** Matrix-vector multiplication A * b */
static inline struct weston_vec4f
weston_m4f_mul_v4f(struct weston_mat4f A, struct weston_vec4f b)
{
struct weston_vec4f result;
unsigned r;
for (r = 0; r < 4; r++) {
struct weston_vec4f row =
WESTON_VEC4F(A.col[0].el[r], A.col[1].el[r], A.col[2].el[r], A.col[3].el[r]);
result.el[r] = weston_v4f_dot_v4f(row, b);
}
return result;
}
/** Matrix multiplication A * B */
static inline struct weston_mat4f
weston_m4f_mul_m4f(struct weston_mat4f A, struct weston_mat4f B)
{
struct weston_mat4f result;
unsigned c;
for (c = 0; c < 4; c++)
result.col[c] = weston_m4f_mul_v4f(A, B.col[c]);
return result;
}
/** Element-wise matrix subtraction A - B */
static inline struct weston_mat4f
weston_m4f_sub_m4f(struct weston_mat4f A, struct weston_mat4f B)
{
struct weston_mat4f R;
unsigned i;
for (i = 0; i < 4 * 4; i++)
R.colmaj[i] = A.colmaj[i] - B.colmaj[i];
return R;
}
bool
weston_m4f_invert(struct weston_mat4f *out, struct weston_mat4f M);
#ifdef __cplusplus
}
#endif

View file

@ -31,7 +31,6 @@
#include <stdbool.h>
#include <wayland-server-protocol.h>
#include <libweston/linalg-types.h>
#ifdef __cplusplus
extern "C" {
@ -45,12 +44,12 @@ enum weston_matrix_transform_type {
};
struct weston_matrix {
struct weston_mat4f M;
float d[16];
unsigned int type;
};
struct weston_vector {
struct weston_vec4f v;
float f[4];
};
/** Arbitrary coordinates in any space */

View file

@ -1,11 +1,6 @@
install_headers(
'colorimetry.h',
'config-parser.h',
'libweston.h',
'linalg.h',
'linalg-3.h',
'linalg-4.h',
'linalg-types.h',
'desktop.h',
'matrix.h',
'plugin-registry.h',

View file

@ -31,7 +31,7 @@ extern "C" {
/* parameter for weston_curtain_create() */
struct weston_curtain_params {
char *label;
int (*get_label)(struct weston_surface *es, char *buf, size_t len);
void (*surface_committed)(struct weston_surface *es,
struct weston_coord_surface new_origin);
void *surface_private;
@ -61,6 +61,10 @@ weston_shell_utils_subsurfaces_boundingbox(struct weston_surface *surface,
int32_t *x, int32_t *y,
int32_t *w, int32_t *h);
int
weston_shell_utils_surface_get_label(struct weston_surface *surface,
char *buf, size_t len);
/* helper to create a view w/ a color */
struct weston_curtain *
weston_shell_utils_curtain_create(struct weston_compositor *compositor,
@ -71,13 +75,6 @@ weston_shell_utils_curtain_destroy(struct weston_curtain *curtain);
enum weston_layer_position
weston_shell_utils_view_get_layer_position(struct weston_view *view);
void
weston_output_set_shell_private(struct weston_output *output,
void *private_data);
void *
weston_output_get_shell_private(struct weston_output *output);
#ifdef __cplusplus
}
#endif

View file

@ -88,9 +88,6 @@ void
weston_log_scope_write(struct weston_log_scope *scope,
const char *data, size_t len);
FILE *
weston_log_scope_stream(struct weston_log_scope *scope);
int
weston_log_scope_vprintf(struct weston_log_scope *scope,
const char *fmt, va_list ap);
@ -99,14 +96,6 @@ int
weston_log_scope_printf(struct weston_log_scope *scope,
const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
void
weston_log_scope_puts(struct weston_log_scope *scope, const char *str);
void
weston_log_subscription_write(struct weston_log_subscription *sub,
const char *data, size_t len);
void
weston_log_subscription_printf(struct weston_log_subscription *sub,
const char *fmt, ...)
@ -157,12 +146,6 @@ struct weston_log_scope *
weston_log_scopes_iterate(struct weston_log_context *log_ctx,
struct weston_log_scope *nscope);
void
weston_add_scope_to_advertised_list(struct weston_log_context *ctx,
const char *name);
bool
weston_log_scope_to_be_advertised(struct weston_log_context *ctx, const char *name);
#ifdef __cplusplus
}
#endif

View file

@ -103,9 +103,8 @@ weston_windowed_output_get_api(struct weston_compositor *compositor,
if (type >= ARRAY_LENGTH(api_names))
return NULL;
return (const struct weston_windowed_output_api *)
weston_plugin_api_get(compositor, api_names[type],
sizeof(struct weston_windowed_output_api));
return weston_plugin_api_get(compositor, api_names[type],
sizeof(struct weston_windowed_output_api));
}
#ifdef __cplusplus

View file

@ -1455,8 +1455,6 @@ ivi_hmi_controller_UI_ready(struct wl_client *client,
hmi_ctrl->interface->commit_changes();
ivi_hmi_controller_add_launchers(hmi_ctrl, 256);
hmi_ctrl->interface->screen_ready(hmi_ctrl->workspace_background_output);
hmi_ctrl->is_initialized = 1;
}

View file

@ -219,17 +219,6 @@ struct ivi_layout_interface {
*/
void (*add_listener_configure_desktop_surface)(struct wl_listener *listener);
/**
* \brief add a listener for desktop_surface ping timeout notification
*
* When a desktop_client fails to respond to compositor pings within
* the configured timeout period, this signal is emitted to registered
* listeners. The void* data argument will contain a pointer to the
* weston_desktop_client associated with the unresponsive surface.
*/
void (*add_listener_desktop_surface_ping_timeout)(struct wl_listener *listener);
/**
* \brief Get all ivi_surfaces which are currently registered and managed
* by the services
@ -647,12 +636,6 @@ struct ivi_layout_interface {
* See add_listener_show_input_panel for more details.
*/
void (*add_listener_update_input_panel)(struct wl_listener *listener);
/**
* \brief Set weston_output ready to be painted
*/
void (*screen_ready)(struct weston_output *output);
};
static inline const struct ivi_layout_interface *

View file

@ -115,7 +115,6 @@ struct ivi_layout {
struct wl_signal removed;
struct wl_signal configure_changed;
struct wl_signal configure_desktop_changed;
struct wl_signal ping_timeout;
} surface_notification;
struct {

View file

@ -46,9 +46,6 @@ void
ivi_layout_desktop_surface_configure(struct ivi_layout_surface *ivisurf,
int32_t width, int32_t height);
void
ivi_layout_desktop_surface_ping_timeout(struct weston_desktop_client *client);
struct ivi_layout_surface*
ivi_layout_desktop_surface_create(struct weston_surface *wl_surface,
struct weston_desktop_surface *surface);

View file

@ -63,7 +63,6 @@
#include "frontend/weston.h"
#include <libweston/libweston.h>
#include <libweston/shell-utils.h>
#include "ivi-shell.h"
#include "ivi-layout-export.h"
#include "ivi-layout-private.h"
@ -285,7 +284,7 @@ destroy_screen(struct ivi_layout_screen *iviscrn)
}
static void
output_destroy_iviscreen(struct wl_listener *listener, void *data)
output_destroyed_event(struct wl_listener *listener, void *data)
{
struct weston_output *destroyed_output = data;
struct ivi_layout_screen *iviscrn;
@ -296,8 +295,8 @@ output_destroy_iviscreen(struct wl_listener *listener, void *data)
}
static struct ivi_layout_screen *
create_screen(struct weston_output *output)
static void
add_screen(struct weston_output *output)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_screen *iviscrn = NULL;
@ -310,24 +309,26 @@ create_screen(struct weston_output *output)
wl_list_init(&iviscrn->pending.layer_list);
wl_list_init(&iviscrn->order.layer_list);
wl_list_insert(&layout->screen_list, &iviscrn->link);
return iviscrn;
}
static void
create_ivi_screen(struct ivi_layout *layout, struct weston_output *output)
output_created_event(struct wl_listener *listener, void *data)
{
create_screen(output);
struct weston_output *created_output = data;
add_screen(created_output);
}
/**
* Internal API to initialize ivi_screens found from output_list of weston_compositor.
* Called by ivi_layout_init.
*/
static void
output_create_iviscreen(struct wl_listener *listener, void *data)
create_screen(struct weston_compositor *ec)
{
struct ivi_layout *layout =
container_of(listener, struct ivi_layout, output_created);
struct weston_output *output = data;
struct weston_output *output = NULL;
create_ivi_screen(layout, output);
wl_list_for_each(output, &ec->output_list, link)
add_screen(output);
}
/**
@ -462,33 +463,33 @@ calc_inverse_matrix_transform(const struct weston_matrix *matrix,
}
/* The vectors and matrices involved will always produce f[3] == 1.0. */
top_left.v.el[0] = rect_input->x;
top_left.v.el[1] = rect_input->y;
top_left.v.el[2] = 0.0f;
top_left.v.el[3] = 1.0f;
top_left.f[0] = rect_input->x;
top_left.f[1] = rect_input->y;
top_left.f[2] = 0.0f;
top_left.f[3] = 1.0f;
bottom_right.v.el[0] = rect_input->x + rect_input->width;
bottom_right.v.el[1] = rect_input->y + rect_input->height;
bottom_right.v.el[2] = 0.0f;
bottom_right.v.el[3] = 1.0f;
bottom_right.f[0] = rect_input->x + rect_input->width;
bottom_right.f[1] = rect_input->y + rect_input->height;
bottom_right.f[2] = 0.0f;
bottom_right.f[3] = 1.0f;
weston_matrix_transform(&m, &top_left);
weston_matrix_transform(&m, &bottom_right);
if (top_left.v.el[0] < bottom_right.v.el[0]) {
rect_output->x = floor(top_left.v.el[0]);
rect_output->width = ceil(bottom_right.v.el[0] - rect_output->x);
if (top_left.f[0] < bottom_right.f[0]) {
rect_output->x = floorf(top_left.f[0]);
rect_output->width = ceilf(bottom_right.f[0] - rect_output->x);
} else {
rect_output->x = floor(bottom_right.v.el[0]);
rect_output->width = ceil(top_left.v.el[0] - rect_output->x);
rect_output->x = floorf(bottom_right.f[0]);
rect_output->width = ceilf(top_left.f[0] - rect_output->x);
}
if (top_left.v.el[1] < bottom_right.v.el[1]) {
rect_output->y = floor(top_left.v.el[1]);
rect_output->height = ceil(bottom_right.v.el[1] - rect_output->y);
if (top_left.f[1] < bottom_right.f[1]) {
rect_output->y = floorf(top_left.f[1]);
rect_output->height = ceilf(bottom_right.f[1] - rect_output->y);
} else {
rect_output->y = floor(bottom_right.v.el[1]);
rect_output->height = ceil(top_left.v.el[1] - rect_output->y);
rect_output->y = floorf(bottom_right.f[1]);
rect_output->height = ceilf(top_left.f[1] - rect_output->y);
}
ivi_rectangle_intersect(rect_output, boundingbox, rect_output);
@ -987,16 +988,6 @@ ivi_layout_add_listener_configure_desktop_surface(struct wl_listener *listener)
wl_signal_add(&layout->surface_notification.configure_desktop_changed, listener);
}
static void
ivi_layout_add_listener_desktop_surface_ping_timeout(struct wl_listener *listener)
{
struct ivi_layout *layout = get_instance();
assert(listener);
wl_signal_add(&layout->surface_notification.ping_timeout, listener);
}
static int32_t
ivi_layout_shell_add_destroy_listener_once(struct wl_listener *listener, wl_notify_func_t destroy_handler)
{
@ -1573,12 +1564,6 @@ ivi_layout_screen_set_render_order(struct weston_output *output,
iviscrn->order.dirty = 1;
}
static void
ivi_layout_set_screen_ready(struct weston_output *output)
{
weston_output_set_ready(output);
}
/**
* This function is used by the additional ivi-module because of dumping ivi_surface sceenshot.
* The ivi-module, e.g. ivi-controller.so, is in wayland-ivi-extension of Genivi's Layer Management.
@ -1927,14 +1912,6 @@ ivi_layout_desktop_surface_configure(struct ivi_layout_surface *ivisurf,
ivisurf);
}
void
ivi_layout_desktop_surface_ping_timeout(struct weston_desktop_client *client)
{
struct ivi_layout *layout = get_instance();
wl_signal_emit_mutable(&layout->surface_notification.ping_timeout, client);
}
struct ivi_layout_surface*
ivi_layout_desktop_surface_create(struct weston_surface *wl_surface,
struct weston_desktop_surface *surface)
@ -2121,7 +2098,6 @@ void
ivi_layout_init(struct weston_compositor *ec, struct ivi_shell *shell)
{
struct ivi_layout *layout = get_instance();
struct weston_output *output;
layout->shell = shell;
@ -2137,7 +2113,6 @@ ivi_layout_init(struct weston_compositor *ec, struct ivi_shell *shell)
wl_signal_init(&layout->surface_notification.removed);
wl_signal_init(&layout->surface_notification.configure_changed);
wl_signal_init(&layout->surface_notification.configure_desktop_changed);
wl_signal_init(&layout->surface_notification.ping_timeout);
wl_signal_init(&layout->input_panel_notification.configure_changed);
wl_signal_init(&layout->input_panel_notification.show);
@ -2151,13 +2126,12 @@ ivi_layout_init(struct weston_compositor *ec, struct ivi_shell *shell)
weston_layer_set_position(&layout->layout_layer,
WESTON_LAYER_POSITION_NORMAL);
layout->output_created.notify = output_create_iviscreen;
create_screen(ec);
layout->output_created.notify = output_created_event;
wl_signal_add(&ec->output_created_signal, &layout->output_created);
wl_list_for_each(output, &ec->output_list, link)
create_ivi_screen(layout, output);
layout->output_destroyed.notify = output_destroy_iviscreen;
layout->output_destroyed.notify = output_destroyed_event;
wl_signal_add(&ec->output_destroyed_signal, &layout->output_destroyed);
layout->transitions = ivi_layout_transition_set_create(ec);
@ -2172,10 +2146,6 @@ void
ivi_layout_fini(void)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_screen *iviscrn, *iviscrn_tmp;
wl_list_for_each_safe(iviscrn, iviscrn_tmp, &layout->screen_list, link)
destroy_screen(iviscrn);
weston_layer_fini(&layout->layout_layer);
@ -2194,33 +2164,32 @@ static struct ivi_layout_interface ivi_layout_interface = {
/**
* surface controller interfaces
*/
.add_listener_create_surface = ivi_layout_add_listener_create_surface,
.add_listener_remove_surface = ivi_layout_add_listener_remove_surface,
.add_listener_configure_surface = ivi_layout_add_listener_configure_surface,
.add_listener_configure_desktop_surface = ivi_layout_add_listener_configure_desktop_surface,
.add_listener_desktop_surface_ping_timeout = ivi_layout_add_listener_desktop_surface_ping_timeout,
.get_surface = shell_get_ivi_layout_surface,
.get_surfaces = ivi_layout_get_surfaces,
.get_id_of_surface = ivi_layout_get_id_of_surface,
.get_surface_from_id = ivi_layout_get_surface_from_id,
.get_properties_of_surface = ivi_layout_get_properties_of_surface,
.get_surfaces_on_layer = ivi_layout_get_surfaces_on_layer,
.surface_set_visibility = ivi_layout_surface_set_visibility,
.surface_set_opacity = ivi_layout_surface_set_opacity,
.surface_set_source_rectangle = ivi_layout_surface_set_source_rectangle,
.surface_set_destination_rectangle = ivi_layout_surface_set_destination_rectangle,
.surface_add_listener = ivi_layout_surface_add_listener,
.surface_get_weston_surface = ivi_layout_surface_get_weston_surface,
.surface_set_transition = ivi_layout_surface_set_transition,
.surface_set_transition_duration = ivi_layout_surface_set_transition_duration,
.surface_set_id = ivi_layout_surface_set_id,
.surface_activate = ivi_layout_surface_activate,
.surface_is_active = ivi_layout_surface_is_active,
.add_listener_create_surface = ivi_layout_add_listener_create_surface,
.add_listener_remove_surface = ivi_layout_add_listener_remove_surface,
.add_listener_configure_surface = ivi_layout_add_listener_configure_surface,
.add_listener_configure_desktop_surface = ivi_layout_add_listener_configure_desktop_surface,
.get_surface = shell_get_ivi_layout_surface,
.get_surfaces = ivi_layout_get_surfaces,
.get_id_of_surface = ivi_layout_get_id_of_surface,
.get_surface_from_id = ivi_layout_get_surface_from_id,
.get_properties_of_surface = ivi_layout_get_properties_of_surface,
.get_surfaces_on_layer = ivi_layout_get_surfaces_on_layer,
.surface_set_visibility = ivi_layout_surface_set_visibility,
.surface_set_opacity = ivi_layout_surface_set_opacity,
.surface_set_source_rectangle = ivi_layout_surface_set_source_rectangle,
.surface_set_destination_rectangle = ivi_layout_surface_set_destination_rectangle,
.surface_add_listener = ivi_layout_surface_add_listener,
.surface_get_weston_surface = ivi_layout_surface_get_weston_surface,
.surface_set_transition = ivi_layout_surface_set_transition,
.surface_set_transition_duration = ivi_layout_surface_set_transition_duration,
.surface_set_id = ivi_layout_surface_set_id,
.surface_activate = ivi_layout_surface_activate,
.surface_is_active = ivi_layout_surface_is_active,
/**
* layer controller interfaces
*/
.add_listener_create_layer = ivi_layout_add_listener_create_layer,
.add_listener_create_layer = ivi_layout_add_listener_create_layer,
.add_listener_remove_layer = ivi_layout_add_listener_remove_layer,
.layer_create_with_dimension = ivi_layout_layer_create_with_dimension,
.layer_destroy = ivi_layout_layer_destroy,
@ -2247,7 +2216,6 @@ static struct ivi_layout_interface ivi_layout_interface = {
.screen_add_layer = ivi_layout_screen_add_layer,
.screen_remove_layer = ivi_layout_screen_remove_layer,
.screen_set_render_order = ivi_layout_screen_set_render_order,
.screen_ready = ivi_layout_set_screen_ready,
/**
* animation

View file

@ -49,10 +49,8 @@
#include "ivi-layout-shell.h"
#include "libweston/libweston.h"
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#include "shared/xalloc.h"
#include "frontend/weston.h"
#include <libweston/shell-utils.h>
/* Representation of ivi_surface protocol object. */
struct ivi_shell_surface
@ -73,8 +71,6 @@ struct ivi_shell_surface
struct wl_list children_link;
struct wl_list link;
struct wl_listener surface_label_update;
};
struct ivi_input_panel_surface
@ -211,6 +207,16 @@ ivi_shell_surface_committed(struct weston_surface *surface,
}
}
static int
ivi_shell_surface_get_label(struct weston_surface *surface,
char *buf,
size_t len)
{
struct ivi_shell_surface *shell_surf = get_ivi_shell_surface(surface);
return snprintf(buf, len, "ivi-surface %#x", shell_surf->id_surface);
}
static void
layout_surface_cleanup(struct ivi_shell_surface *ivisurf)
{
@ -232,7 +238,7 @@ layout_surface_cleanup(struct ivi_shell_surface *ivisurf)
ivisurf->surface->committed = NULL;
ivisurf->surface->committed_private = NULL;
weston_surface_set_label(ivisurf->surface, NULL);
weston_surface_set_label_func(ivisurf->surface, NULL);
ivisurf->surface = NULL;
}
@ -317,7 +323,6 @@ application_surface_create(struct wl_client *client,
struct weston_surface *weston_surface =
wl_resource_get_user_data(surface_resource);
struct wl_resource *res;
char *label;
if (weston_surface_set_role(weston_surface, "ivi_surface",
resource, IVI_APPLICATION_ERROR_ROLE) < 0)
@ -338,7 +343,7 @@ application_surface_create(struct wl_client *client,
ivisurf = xzalloc(sizeof *ivisurf);
wl_list_init(&ivisurf->surface_label_update.link);
wl_list_init(&ivisurf->link);
wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
ivisurf->shell = shell;
@ -367,9 +372,8 @@ application_surface_create(struct wl_client *client,
weston_surface->committed = ivi_shell_surface_committed;
weston_surface->committed_private = ivisurf;
str_printf(&label, "ivi-surface %u", ivisurf->id_surface);
weston_surface_set_label(weston_surface, label);
weston_surface_set_label_func(weston_surface,
ivi_shell_surface_get_label);
res = wl_resource_create(client, &ivi_surface_interface, 1, id);
if (res == NULL) {
@ -618,7 +622,7 @@ static void
desktop_surface_ping_timeout(struct weston_desktop_client *client,
void *user_data)
{
ivi_layout_desktop_surface_ping_timeout(client);
/* Not supported */
}
static void
@ -628,18 +632,6 @@ desktop_surface_pong(struct weston_desktop_client *client,
/* Not supported */
}
static void
desktop_surface_update_label(struct wl_listener *listener, void *data)
{
struct weston_desktop_surface *desktop_surface = data;
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
char *label;
label = weston_desktop_surface_make_label(desktop_surface);
weston_surface_set_label(surface, label);
}
static void
desktop_surface_added(struct weston_desktop_surface *surface,
void *user_data)
@ -672,10 +664,6 @@ desktop_surface_added(struct weston_desktop_surface *surface,
wl_list_init(&ivisurf->children_link);
weston_desktop_surface_set_user_data(surface, ivisurf);
ivisurf->surface_label_update.notify = desktop_surface_update_label;
weston_desktop_surface_add_metadata_listener(surface, &ivisurf->surface_label_update);
desktop_surface_update_label(&ivisurf->surface_label_update, surface);
}
static void
@ -688,7 +676,6 @@ desktop_surface_removed(struct weston_desktop_surface *surface,
assert(ivisurf != NULL);
wl_list_remove(&ivisurf->surface_label_update.link);
weston_desktop_surface_set_user_data(surface, NULL);
wl_list_for_each_safe(ivisurf_child, tmp, &ivisurf->children_list,
@ -889,6 +876,12 @@ update_input_panels(struct wl_listener *listener, void *data)
ivi_layout_update_text_input_cursor(data);
}
static int
input_panel_get_label(struct weston_surface *surface, char *buf, size_t len)
{
return snprintf(buf, len, "input panel");
}
static void
input_panel_committed(struct weston_surface *surface,
struct weston_coord_surface new_origin)
@ -950,7 +943,7 @@ create_input_panel_surface(struct ivi_shell *shell,
surface->committed = input_panel_committed;
surface->committed_private = ipsurf;
weston_surface_set_label_static(surface, "input panel");
weston_surface_set_label_func(surface, input_panel_get_label);
wl_list_init(&ipsurf->link);
wl_list_insert(&shell->input_panel.surfaces, &ipsurf->link);
@ -1023,7 +1016,7 @@ destroy_input_panel_surface_resource(struct wl_resource *resource)
ipsurf->surface->committed = NULL;
ipsurf->surface->committed_private = NULL;
weston_surface_set_label(ipsurf->surface, NULL);
weston_surface_set_label_func(ipsurf->surface, NULL);
ipsurf->surface = NULL;
wl_list_remove(&ipsurf->surface_destroy_listener.link);

View file

@ -96,9 +96,3 @@ workspace-id=3
icon-id=4010
icon=@westondatadir@/icon_ivi_smoke.png
path=@bindir@/weston-smoke
[ivi-launcher]
workspace-id=3
icon-id=4011
icon=@westondatadir@/icon_ivi_simple-egl-vertical.png
command=@bindir@/weston-simple-egl -v

View file

@ -23,8 +23,6 @@
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <assert.h>
#include <linux/input.h>
#include <stdbool.h>
@ -36,7 +34,6 @@
#include "frontend/weston.h"
#include "libweston/libweston.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
#include <libweston/shell-utils.h>
#include <libweston/xwayland-api.h>
@ -140,7 +137,7 @@ xwayland_get_xwayland_name(struct kiosk_shell_surface *shsurf, enum window_atom_
static void
kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
struct kiosk_shell_output *shoutput);
struct weston_output *output);
static void
kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
struct kiosk_shell_surface *parent);
@ -150,6 +147,9 @@ kiosk_shell_output_set_active_surface_tree(struct kiosk_shell_output *shoutput,
static void
kiosk_shell_output_raise_surface_subtree(struct kiosk_shell_output *shoutput,
struct kiosk_shell_surface *shroot);
static struct kiosk_shell_output *
kiosk_shell_find_shell_output(struct kiosk_shell *shell,
struct weston_output *output);
static void
kiosk_shell_surface_notify_parent_destroy(struct wl_listener *listener, void *data)
@ -183,7 +183,7 @@ kiosk_shell_surface_get_parent_root(struct kiosk_shell_surface *shsurf)
static bool
kiosk_shell_output_has_app_id(char *config_app_ids, const char *app_id);
static struct kiosk_shell_output *
static struct weston_output *
kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *shsurf)
{
struct kiosk_shell_output *shoutput;
@ -208,7 +208,7 @@ kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *sh
if (found_wm_name && found_wm_class) {
shsurf->appid_output_assigned = true;
return shoutput;
return shoutput->output;
}
}
}
@ -219,7 +219,7 @@ kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *sh
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_name_app_ids,
wm_name)) {
shsurf->appid_output_assigned = true;
return shoutput;
return shoutput->output;
}
}
}
@ -229,7 +229,7 @@ kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *sh
if (kiosk_shell_output_has_app_id(shoutput->x11_wm_class_app_ids,
wm_class)) {
shsurf->appid_output_assigned = true;
return shoutput;
return shoutput->output;
}
}
}
@ -237,7 +237,7 @@ kiosk_shell_surface_find_best_output_for_xwayland(struct kiosk_shell_surface *sh
return NULL;
}
static struct kiosk_shell_output *
static struct weston_output *
kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
{
struct weston_output *output;
@ -255,14 +255,14 @@ kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
if (kiosk_shell_output_has_app_id(shoutput->app_ids, app_id)) {
shsurf->appid_output_assigned = true;
return shoutput;
return shoutput->output;
}
}
}
shoutput = kiosk_shell_surface_find_best_output_for_xwayland(shsurf);
if (shoutput)
return shoutput;
output = kiosk_shell_surface_find_best_output_for_xwayland(shsurf);
if (output)
return output;
/* Group all related windows in the same output. */
root = kiosk_shell_surface_get_parent_root(shsurf);
@ -271,20 +271,20 @@ kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
output = weston_shell_utils_get_focused_output(shsurf->shell->compositor);
if (output)
return weston_output_get_shell_private(output);
return output;
output = weston_shell_utils_get_default_output(shsurf->shell->compositor);
if (output)
return weston_output_get_shell_private(output);
return output;
return NULL;
}
static void
kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
struct kiosk_shell_output *shoutput)
struct weston_output *output)
{
shsurf->output = shoutput;
shsurf->output = output;
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
@ -296,39 +296,39 @@ kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
shsurf->output_destroy_listener.notify =
kiosk_shell_surface_notify_output_destroy;
wl_signal_add(&shsurf->output->output->destroy_signal,
wl_signal_add(&shsurf->output->destroy_signal,
&shsurf->output_destroy_listener);
}
static void
kiosk_shell_surface_set_fullscreen(struct kiosk_shell_surface *shsurf,
struct kiosk_shell_output *shoutput)
struct weston_output *output)
{
if (!shoutput)
shoutput = kiosk_shell_surface_find_best_output(shsurf);
if (!output)
output = kiosk_shell_surface_find_best_output(shsurf);
kiosk_shell_surface_set_output(shsurf, shoutput);
kiosk_shell_surface_set_output(shsurf, output);
weston_desktop_surface_set_fullscreen(shsurf->desktop_surface, true);
if (shsurf->output)
weston_desktop_surface_set_size(shsurf->desktop_surface,
shsurf->output->output->width,
shsurf->output->output->height);
shsurf->output->width,
shsurf->output->height);
}
static void
kiosk_shell_surface_set_maximized(struct kiosk_shell_surface *shsurf)
{
struct kiosk_shell_output *shoutput =
struct weston_output *output =
kiosk_shell_surface_find_best_output(shsurf);
kiosk_shell_surface_set_output(shsurf, shoutput);
kiosk_shell_surface_set_output(shsurf, output);
weston_desktop_surface_set_maximized(shsurf->desktop_surface, true);
if (shsurf->output)
weston_desktop_surface_set_size(shsurf->desktop_surface,
shsurf->output->output->width,
shsurf->output->output->height);
shsurf->output->width,
shsurf->output->height);
}
static void
@ -382,7 +382,9 @@ static void
kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
struct kiosk_shell_surface *parent)
{
struct kiosk_shell_output *shoutput = shsurf->output;
struct kiosk_shell_output *shoutput =
kiosk_shell_find_shell_output(shsurf->shell,
shsurf->output);
struct kiosk_shell_surface *shroot = parent ?
kiosk_shell_surface_get_parent_root(parent) :
kiosk_shell_surface_get_parent_root(shsurf);
@ -434,37 +436,23 @@ static void
kiosk_shell_surface_reconfigure_for_output(struct kiosk_shell_surface *shsurf)
{
struct weston_desktop_surface *desktop_surface;
struct weston_output *w_output;
if (!shsurf->output)
return;
w_output = shsurf->output->output;
desktop_surface = shsurf->desktop_surface;
if (weston_desktop_surface_get_maximized(desktop_surface) ||
weston_desktop_surface_get_fullscreen(desktop_surface)) {
weston_desktop_surface_set_size(desktop_surface,
w_output->width,
w_output->height);
shsurf->output->width,
shsurf->output->height);
}
weston_shell_utils_center_on_output(shsurf->view, w_output);
weston_shell_utils_center_on_output(shsurf->view, shsurf->output);
weston_view_update_transform(shsurf->view);
}
static void
desktop_surface_update_label(struct wl_listener *listener, void *data)
{
struct weston_desktop_surface *desktop_surface = data;
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
char *label;
label = weston_desktop_surface_make_label(desktop_surface);
weston_surface_set_label(surface, label);
}
static void
kiosk_shell_surface_destroy(struct kiosk_shell_surface *shsurf)
{
@ -489,8 +477,6 @@ kiosk_shell_surface_destroy(struct kiosk_shell_surface *shsurf)
shsurf->parent = NULL;
}
wl_list_remove(&shsurf->surface_label_update.link);
free(shsurf);
}
@ -528,10 +514,6 @@ kiosk_shell_surface_create(struct kiosk_shell *shell,
wl_signal_init(&shsurf->destroy_signal);
wl_signal_init(&shsurf->parent_destroy_signal);
shsurf->surface_label_update.notify = desktop_surface_update_label;
weston_desktop_surface_add_metadata_listener(desktop_surface, &shsurf->surface_label_update);
desktop_surface_update_label(&shsurf->surface_label_update, desktop_surface);
/* start life inserting itself as root of its own surface tree list */
wl_list_init(&shsurf->surface_tree_list);
wl_list_init(&shsurf->surface_tree_link);
@ -548,7 +530,8 @@ kiosk_shell_surface_activate(struct kiosk_shell_surface *shsurf,
struct weston_desktop_surface *dsurface = shsurf->desktop_surface;
struct weston_surface *surface =
weston_desktop_surface_get_surface(dsurface);
struct kiosk_shell_output *shoutput = shsurf->output;
struct kiosk_shell_output *shoutput =
kiosk_shell_find_shell_output(shsurf->shell, shsurf->output);
/* keyboard focus */
weston_view_activate_input(shsurf->view, kiosk_seat->seat, activate_flags);
@ -693,6 +676,13 @@ kiosk_shell_output_raise_surface_subtree(struct kiosk_shell_output *shoutput,
}
}
static int
kiosk_shell_background_surface_get_label(struct weston_surface *surface,
char *buf, size_t len)
{
return snprintf(buf, len, "kiosk shell background surface");
}
static void
kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
{
@ -726,7 +716,7 @@ kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
curtain_params.capture_input = true;
curtain_params.label = xstrdup("kiosk shell background surface");
curtain_params.get_label = kiosk_shell_background_surface_get_label;
curtain_params.surface_committed = NULL;
curtain_params.surface_private = NULL;
@ -834,11 +824,8 @@ kiosk_shell_output_create(struct kiosk_shell *shell, struct weston_output *outpu
wl_list_insert(shell->output_list.prev, &shoutput->link);
weston_output_set_shell_private(output, shoutput);
kiosk_shell_output_recreate_background(shoutput);
kiosk_shell_output_configure(shoutput);
weston_output_set_ready(output);
return shoutput;
}
@ -853,11 +840,14 @@ desktop_surface_added(struct weston_desktop_surface *desktop_surface,
{
struct kiosk_shell *shell = data;
struct kiosk_shell_surface *shsurf;
struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface);
shsurf = kiosk_shell_surface_create(shell, desktop_surface);
if (!shsurf)
return;
weston_surface_set_label_func(surface, weston_shell_utils_surface_get_label);
kiosk_shell_surface_set_fullscreen(shsurf, NULL);
}
@ -880,9 +870,6 @@ find_focus_successor(struct kiosk_shell_surface *shsurf,
struct weston_layer *layer;
struct weston_view *view;
if (!shsurf->output)
return NULL;
wl_list_for_each(layer, layers, link) {
struct kiosk_shell *shell = shsurf->shell;
@ -898,7 +885,7 @@ find_focus_successor(struct kiosk_shell_surface *shsurf,
continue;
/* pick views only on the same output */
if (view->output != shsurf->output->output)
if (view->output != shsurf->output)
continue;
view_shsurf = get_kiosk_shell_surface(view->surface);
@ -960,7 +947,7 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
successor = find_focus_successor(shsurf,
kiosk_seat->focused_surface);
shoutput = shsurf->output;
shoutput = kiosk_shell_find_shell_output(shsurf->shell, shsurf->output);
if (shoutput && successor) {
enum weston_layer_position succesor_view_layer_pos;
@ -1004,17 +991,17 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
return;
if (!shsurf->appid_output_assigned && app_id) {
struct kiosk_shell_output *shoutput = NULL;
struct weston_output *output = NULL;
/* reset previous output being set in _added() as the output is
* being cached */
shsurf->output = NULL;
shoutput = kiosk_shell_surface_find_best_output(shsurf);
output = kiosk_shell_surface_find_best_output(shsurf);
kiosk_shell_surface_set_output(shsurf, shoutput);
kiosk_shell_surface_set_output(shsurf, output);
weston_desktop_surface_set_size(shsurf->desktop_surface,
shoutput->output->width,
shoutput->output->height);
shsurf->output->width,
shsurf->output->height);
/* even if we couldn't find an appid set for a particular
* output still flag the shsurf as to a avoid changing the
* output every time */
@ -1034,7 +1021,7 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (!weston_surface_is_mapped(surface) || (is_resized && is_fullscreen)) {
if (is_fullscreen || !shsurf->xwayland.is_set) {
weston_shell_utils_center_on_output(shsurf->view,
shsurf->output->output);
shsurf->output);
} else {
struct weston_coord_surface offset;
struct weston_geometry geometry =
@ -1053,7 +1040,9 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
if (!weston_surface_is_mapped(surface)) {
struct weston_seat *seat =
get_kiosk_shell_first_seat(shsurf->shell);
struct kiosk_shell_output *shoutput = shsurf->output;
struct kiosk_shell_output *shoutput =
kiosk_shell_find_shell_output(shsurf->shell,
shsurf->output);
struct kiosk_shell_seat *kiosk_seat;
weston_surface_map(surface);
@ -1145,10 +1134,6 @@ desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surf
{
struct kiosk_shell_surface *shsurf =
weston_desktop_surface_get_user_data(desktop_surface);
struct kiosk_shell_output *shoutput = NULL;
if (output)
shoutput = weston_output_get_shell_private(output);
/* We should normally be able to ignore fullscreen requests for
* top-level surfaces, since we set them as fullscreen at creation
@ -1163,7 +1148,7 @@ desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surf
*/
if (!shsurf->parent || fullscreen)
kiosk_shell_surface_set_fullscreen(shsurf, shoutput);
kiosk_shell_surface_set_fullscreen(shsurf, output);
else
kiosk_shell_surface_set_normal(shsurf);
}
@ -1247,6 +1232,20 @@ static const struct weston_desktop_api kiosk_shell_desktop_api = {
* kiosk_shell
*/
static struct kiosk_shell_output *
kiosk_shell_find_shell_output(struct kiosk_shell *shell,
struct weston_output *output)
{
struct kiosk_shell_output *shoutput;
wl_list_for_each(shoutput, &shell->output_list, link) {
if (shoutput->output == output)
return shoutput;
}
return NULL;
}
static void
kiosk_shell_activate_view(struct kiosk_shell *shell,
struct weston_view *view,
@ -1335,7 +1334,7 @@ kiosk_shell_handle_output_resized(struct wl_listener *listener, void *data)
container_of(listener, struct kiosk_shell, output_resized_listener);
struct weston_output *output = data;
struct kiosk_shell_output *shoutput =
weston_output_get_shell_private(output);
kiosk_shell_find_shell_output(shell, output);
struct weston_view *view;
kiosk_shell_output_recreate_background(shoutput);

View file

@ -57,7 +57,7 @@ struct kiosk_shell_surface {
struct kiosk_shell *shell;
struct kiosk_shell_output *output;
struct weston_output *output;
struct wl_listener output_destroy_listener;
struct wl_signal destroy_signal;
@ -80,8 +80,6 @@ struct kiosk_shell_surface {
} xwayland;
bool appid_output_assigned;
struct wl_listener surface_label_update;
};
struct kiosk_shell_seat {

View file

@ -199,19 +199,7 @@ weston_view_animation_frame(struct weston_animation *base,
struct weston_compositor *compositor =
animation->view->surface->compositor;
/* Animations are created with timestamp 0, so we need to set a
* real time base on the first repaint.
*
* In some cases, such as when the repaint loop has just started
* for a new display, the time we're given could be 0 for our
* second call - but this is ok because weston_spring_update() will
* do nothing as long as spring.timestamp == time.
*
* We can safely just keep updating the timestamp until we get
* something non-zero, and the spring will start updating after
* that.
*/
if (!timespec_to_msec(&animation->spring.timestamp))
if (base->frame_counter <= 1)
animation->spring.timestamp = *time;
weston_spring_update(&animation->spring, time);
@ -287,6 +275,7 @@ weston_view_animation_run(struct weston_view_animation *animation)
{
struct timespec zero_time = { 0 };
animation->animation.frame_counter = 0;
weston_view_animation_frame(&animation->animation, NULL, &zero_time);
}

View file

@ -40,12 +40,26 @@
#include "pixman-renderer.h"
#include "pixel-formats.h"
#include "renderer-gl/gl-renderer.h"
#include "renderer-vulkan/vulkan-renderer.h"
#include "shared/weston-assert.h"
#include "shared/weston-egl-ext.h"
#include "linux-dmabuf.h"
#include "linux-explicit-synchronization.h"
#include "shared/xalloc.h"
static struct gbm_device *
create_gbm_device(int fd)
{
struct gbm_device *gbm;
/* GBM will load a dri driver, but even though they need symbols from
* libglapi, in some version of Mesa they are not linked to it. Since
* only the gl-renderer module links to it, the call above won't make
* these symbols globally available, and loading the DRI driver fails.
* Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
gbm = gbm_create_device(fd);
return gbm;
}
/* When initializing EGL, if the preferred buffer format isn't available
* we may be able to substitute an ARGB format for an XRGB one.
@ -85,32 +99,12 @@ drm_backend_create_gl_renderer(struct drm_backend *b)
&options.base);
}
static int
drm_backend_create_vulkan_renderer(struct drm_backend *b)
{
const struct pixel_format_info *format[3] = {
b->format,
fallback_format_for(b->format),
};
struct vulkan_renderer_display_options options = {
.formats = format,
.formats_count = 1,
};
if (format[1])
options.formats_count = 2;
return weston_compositor_init_renderer(b->compositor,
WESTON_RENDERER_VULKAN,
&options.base);
}
int
init_egl(struct drm_backend *b)
{
struct drm_device *device = b->drm;
b->gbm = gbm_create_device(device->kms_device->fd);
b->gbm = create_gbm_device(device->drm.fd);
if (!b->gbm)
return -1;
@ -123,24 +117,6 @@ init_egl(struct drm_backend *b)
return 0;
}
int
init_vulkan(struct drm_backend *b)
{
struct drm_device *device = b->drm;
b->gbm = gbm_create_device(device->kms_device->fd);
if (!b->gbm)
return -1;
if (drm_backend_create_vulkan_renderer(b) < 0) {
gbm_device_destroy(b->gbm);
b->gbm = NULL;
return -1;
}
return 0;
}
static void drm_output_fini_cursor_egl(struct drm_output *output)
{
unsigned int i;
@ -154,19 +130,6 @@ static void drm_output_fini_cursor_egl(struct drm_output *output)
}
}
static void drm_output_fini_cursor_vulkan(struct drm_output *output)
{
unsigned int i;
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
/* This cursor does not have a GBM device */
if (output->gbm_cursor_fb[i] && !output->gbm_cursor_fb[i]->bo)
output->gbm_cursor_fb[i]->type = BUFFER_PIXMAN_DUMB;
drm_fb_unref(output->gbm_cursor_fb[i]);
output->gbm_cursor_fb[i] = NULL;
}
}
static int
drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
{
@ -174,13 +137,13 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
unsigned int i;
/* No point creating cursors if we don't have a plane for them. */
if (!output->cursor_handle)
if (!output->cursor_plane)
return 0;
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
struct gbm_bo *bo;
if (gbm_device_get_fd(b->gbm) != output->device->kms_device->fd) {
if (gbm_device_get_fd(b->gbm) != output->device->drm.fd) {
output->gbm_cursor_fb[i] =
drm_fb_create_dumb(output->device,
device->cursor_width,
@ -216,60 +179,11 @@ err:
return -1;
}
static int
drm_output_init_cursor_vulkan(struct drm_output *output, struct drm_backend *b)
{
struct drm_device *device = output->device;
unsigned int i;
/* No point creating cursors if we don't have a plane for them. */
if (!output->cursor_handle)
return 0;
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
struct gbm_bo *bo;
if (gbm_device_get_fd(b->gbm) != output->device->kms_device->fd) {
output->gbm_cursor_fb[i] =
drm_fb_create_dumb(output->device,
device->cursor_width,
device->cursor_height,
DRM_FORMAT_ARGB8888);
/* Override buffer type, since we know it is a cursor */
output->gbm_cursor_fb[i]->type = BUFFER_CURSOR;
output->gbm_cursor_handle[i] =
output->gbm_cursor_fb[i]->handles[0];
} else {
bo = gbm_bo_create(b->gbm, device->cursor_width, device->cursor_height,
GBM_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo)
goto err;
output->gbm_cursor_fb[i] =
drm_fb_get_from_bo(bo, device, false, BUFFER_CURSOR);
if (!output->gbm_cursor_fb[i]) {
gbm_bo_destroy(bo);
goto err;
}
output->gbm_cursor_handle[i] = gbm_bo_get_handle(bo).s32;
}
}
return 0;
err:
weston_log("cursor buffers unavailable, using vulkan cursors\n");
device->cursors_are_broken = true;
drm_output_fini_cursor_vulkan(output);
return -1;
}
static void
create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
{
struct weston_mode *mode = output->base.current_mode;
struct drm_plane *plane = output->scanout_handle->plane;
struct drm_plane *plane = output->scanout_plane;
struct weston_drm_format *fmt;
const uint64_t *modifiers;
unsigned int num_modifiers;
@ -298,7 +212,7 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
* on a different GPU), we have to use linear buffers to make sure that
* the allocated GBM surface is correctly displayed on the KMS device.
*/
if (gbm_device_get_fd(gbm) != output->device->kms_device->fd)
if (gbm_device_get_fd(gbm) != output->device->drm.fd)
output->gbm_bo_flags |= GBM_BO_USE_LINEAR;
/* We may allocate with no modifiers in the following situations:
@ -315,215 +229,26 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
output->gbm_bo_flags);
}
enum format_alpha_required {
FORMAT_ALPHA_REQUIRED = true,
FORMAT_ALPHA_NOT_REQUIRED = false,
};
enum format_component_type {
FORMAT_COMPONENT_TYPE_ANY,
FORMAT_COMPONENT_TYPE_FLOAT_ONLY,
};
static const struct pixel_format_info *
find_compatible_format(struct weston_compositor *compositor,
struct wl_array *formats, int min_bpc,
enum format_component_type component_type,
enum format_alpha_required alpha_required)
{
const struct pixel_format_info **tmp, *p;
const struct pixel_format_info *candidate = NULL;
/**
* Given a format array, this looks for a format respecting a few
* criteria. First of all, this ignores formats that do not contain an
* alpha channel when alpha_required == FORMAT_ALPHA_REQUIRED. Similar
* for formats that are not floating point when component_type ==
* FORMAT_COMPONENT_TYPE_FLOAT_ONLY. Also, it ignores formats that do
* not have bits per color channel (bpc) bigger or equal to min_bpc.
*
* When we have multiple formats matching these criteria, we use the
* following to choose:
*
* 1. a format with lower bytes per pixel (bpp) is favored.
*
* 2. if FORMAT_ALPHA_REQUIRED:
* we prefer the format with more bits on the alpha channel
* else
* we prefer the format with more bits on the color channels
*/
wl_array_for_each(tmp, formats) {
p = *tmp;
/* Skip candidates that do not match minimum criteria. */
if (component_type == FORMAT_COMPONENT_TYPE_FLOAT_ONLY &&
p->component_type != PIXEL_COMPONENT_TYPE_FLOAT)
continue;
if (alpha_required == FORMAT_ALPHA_REQUIRED && p->bits.a == 0)
continue;
if (p->bits.r < min_bpc || p->bits.g < min_bpc || p->bits.b < min_bpc)
continue;
/* No other good candidate so far, so pick this one. */
if (!candidate) {
candidate = p;
continue;
}
/**
* New candidate, let's compare with old and untie.
*/
if (p->bpp > candidate->bpp)
continue;
if (alpha_required == FORMAT_ALPHA_REQUIRED) {
if (p->bits.a <= candidate->bits.a)
continue;
} else {
if (p->bits.r + p->bits.g + p->bits.b <=
candidate->bits.r + candidate->bits.g + candidate->bits.b)
continue;
}
candidate = p;
}
return candidate;
}
static bool
drm_output_pick_format_egl(struct drm_output *output)
{
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct weston_compositor *compositor = b->compositor;
const struct weston_renderer *renderer = compositor->renderer;
const struct pixel_format_info **renderer_formats;
const struct pixel_format_info **f;
unsigned int renderer_formats_count;
struct wl_array supported_formats;
enum format_component_type component_type;
uint32_t min_bpc;
unsigned int i;
bool ret = true;
bool found;
wl_array_init(&supported_formats);
/**
* This computes the intersection between renderer formats supported by
* EGL and the output scanout plane supported formats. We need that as
* we want to select a format supported by both.
*/
renderer_formats =
renderer->gl->get_supported_rendering_formats(b->compositor,
&renderer_formats_count);
for (i = 0; i < renderer_formats_count; i++) {
struct drm_plane *scanout_plane = output->scanout_handle->plane;
if (!weston_drm_format_array_find_format(&scanout_plane->formats,
renderer_formats[i]->format))
continue;
f = wl_array_add(&supported_formats, sizeof(*f));
*f = renderer_formats[i];
}
if (output->base.from_blend_to_output_by_backend) {
component_type = FORMAT_COMPONENT_TYPE_FLOAT_ONLY;
min_bpc = 16;
} else if (output->base.eotf_mode != WESTON_EOTF_MODE_SDR) {
component_type = FORMAT_COMPONENT_TYPE_ANY;
min_bpc = 10;
} else {
/**
* If no requirements, we simply use b->format instead of
* looking for a format with bpc >= min_bpc.
*/
min_bpc = 0;
}
if (min_bpc != 0) {
if (output->has_underlay) {
output->format =
find_compatible_format(compositor, &supported_formats,
min_bpc, component_type,
FORMAT_ALPHA_REQUIRED);
if (output->format)
goto done;
weston_log("Disabling underlay planes: EGL GBM or the primary plane for output '%s'\n" \
"does not support format with min bpc %u and alpha channel.\n",
output->base.name, min_bpc);
output->has_underlay = false;
}
output->format =
find_compatible_format(compositor, &supported_formats,
min_bpc, component_type,
FORMAT_ALPHA_NOT_REQUIRED);
if (output->format)
goto done;
weston_log("Error: EGL GBM or the primary plane for output '%s' does not support format\n" \
"with min bpc %u.\n", output->base.name, min_bpc);
ret = false;
goto done;
}
found = false;
wl_array_for_each(f, &supported_formats) {
if ((*f)->format == b->format->format) {
found = true;
break;
}
}
if (!found) {
weston_log("Error: format %s unsupported by EGL GBM or the primary plane for output '%s'.\n",
b->format->drm_format_name, output->base.name);
ret = false;
goto done;
}
if (output->has_underlay && (b->format->bits.a == 0)) {
weston_log("Disabling underlay planes: b->format %s does not have alpha channel,\n"
"which is required to support underlay planes.\n",
b->format->drm_format_name);
output->has_underlay = false;
}
output->format = b->format;
done:
wl_array_release(&supported_formats);
return ret;
}
/* Init output state that depends on gl or gbm */
int
drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
{
const struct weston_renderer *renderer = b->compositor->renderer;
const struct weston_mode *mode = output->base.current_mode;
const struct pixel_format_info *format[2] = { 0 };
struct gl_renderer_output_options options;
if (!output->format && !drm_output_pick_format_egl(output))
return -1;
format[0] = output->format;
if (!output->has_underlay)
format[1] = fallback_format_for(output->format);
options.formats = format;
options.formats_count = format[1] ? 2 : 1;
options.area.x = 0;
options.area.y = 0;
options.area.width = mode->width;
options.area.height = mode->height;
options.fb_size.width = mode->width;
options.fb_size.height = mode->height;
const struct pixel_format_info *format[2] = {
output->format,
fallback_format_for(output->format),
};
struct gl_renderer_output_options options = {
.formats = format,
.formats_count = 1,
.area.x = 0,
.area.y = 0,
.area.width = mode->width,
.area.height = mode->height,
.fb_size.width = mode->width,
.fb_size.height = mode->height,
};
assert(output->gbm_surface == NULL);
create_gbm_surface(b->gbm, output);
@ -532,6 +257,8 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
return -1;
}
if (options.formats[1])
options.formats_count = 2;
options.window_for_legacy = (EGLNativeWindowType) output->gbm_surface;
options.window_for_platform = output->gbm_surface;
if (renderer->gl->output_window_create(&output->base, &options) < 0) {
@ -546,208 +273,6 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
return 0;
}
static struct gbm_bo *
drm_gbm_create_bo(struct gbm_device *gbm, struct drm_output *output)
{
struct weston_mode *mode = output->base.current_mode;
struct drm_plane *plane = output->scanout_handle->plane;
struct weston_drm_format *fmt;
const uint64_t *modifiers;
unsigned int num_modifiers;
struct gbm_bo *bo = NULL;
/*
* TODO: Currently, this method allocates a buffer based on the list
* of acceptable modifiers received from the DRM backend but does not
* check it against formats renderable by the renderer.
* To support cases where the renderer may not support the same
* modifiers (e.g. Vulkan software renderer) it should match against
* renderer modifiers.
*/
fmt = weston_drm_format_array_find_format(&plane->formats,
output->format->format);
if (!fmt) {
weston_log("format %s not supported by output %s\n",
output->format->drm_format_name,
output->base.name);
return NULL;
}
if (!weston_drm_format_has_modifier(fmt, DRM_FORMAT_MOD_INVALID)) {
modifiers = weston_drm_format_get_modifiers(fmt, &num_modifiers);
bo = gbm_bo_create_with_modifiers(gbm, mode->width, mode->height,
output->format->format,
modifiers, num_modifiers);
}
/*
* If we cannot use modifiers to allocate the GBM surface and
* the GBM device differs from the KMS display device, try to
* use linear buffers and hope that the allocated GBM surface
* is correctly displayed on the KMS device.
*/
if (gbm_device_get_fd(gbm) != output->device->kms_device->fd)
output->gbm_bo_flags |= GBM_BO_USE_LINEAR;
if (!bo) {
bo = gbm_bo_create(gbm, mode->width, mode->height,
output->format->format, output->gbm_bo_flags);
}
return bo;
}
struct drm_gbm_dmabuf {
struct linux_dmabuf_memory base;
struct gbm_bo *bo;
};
static void
drm_gbm_dmabuf_destroy(struct linux_dmabuf_memory *dmabuf)
{
struct dmabuf_attributes *attributes;
struct drm_gbm_dmabuf *drm_gbm_dmabuf;
struct gbm_bo *bo;
drm_gbm_dmabuf = container_of(dmabuf, struct drm_gbm_dmabuf, base);
bo = drm_gbm_dmabuf->bo;
assert(bo);
gbm_bo_destroy(bo);
attributes = dmabuf->attributes;
for (int i = 0; i < attributes->n_planes; ++i)
close(attributes->fd[i]);
free(dmabuf->attributes);
free(drm_gbm_dmabuf);
}
static struct drm_gbm_dmabuf *
drm_gbm_bo_get_dmabuf(struct gbm_device *gbm, struct drm_output *output, struct gbm_bo *bo)
{
struct drm_gbm_dmabuf *drm_gbm_dmabuf;
struct dmabuf_attributes *attributes;
attributes = xzalloc(sizeof(*attributes));
attributes->width = gbm_bo_get_width(bo);
attributes->height = gbm_bo_get_height(bo);
attributes->format = gbm_bo_get_format(bo);
attributes->n_planes = gbm_bo_get_plane_count(bo);
for (int i = 0; i < attributes->n_planes; ++i) {
attributes->fd[i] = gbm_bo_get_fd(bo);
attributes->stride[i] = gbm_bo_get_stride_for_plane(bo, i);
attributes->offset[i] = gbm_bo_get_offset(bo, i);
}
attributes->modifier = gbm_bo_get_modifier(bo);
drm_gbm_dmabuf = xzalloc(sizeof(*drm_gbm_dmabuf));
drm_gbm_dmabuf->base.attributes = attributes;
drm_gbm_dmabuf->base.destroy = drm_gbm_dmabuf_destroy;
drm_gbm_dmabuf->bo = bo;
return drm_gbm_dmabuf;
}
static void
create_renderbuffers(struct gbm_device *gbm, struct drm_output *output, unsigned int n)
{
struct weston_renderer *renderer = output->base.compositor->renderer;
for (unsigned int i = 0; i < n; i++) {
struct drm_gbm_dmabuf *drm_gbm_dmabuf;
struct gbm_bo *bo;
bo = drm_gbm_create_bo(gbm, output);
if (!bo) {
weston_log("failed to allocate bo\n");
return;
}
drm_gbm_dmabuf = drm_gbm_bo_get_dmabuf(gbm, output, bo);
if (!drm_gbm_dmabuf) {
weston_log("failed to allocate dmabuf\n");
return;
}
output->renderbuffer[i] =
renderer->create_renderbuffer_dmabuf(&output->base,
&drm_gbm_dmabuf->base,
NULL, NULL);
if (!output->renderbuffer[i]) {
weston_log("failed to allocate renderbuffer\n");
return;
}
output->linux_dmabuf_memory[i] = &drm_gbm_dmabuf->base;
}
}
static bool
drm_output_pick_format_vulkan(struct drm_output *output)
{
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
/* Any other value of eotf_mode requires color-management, which is not
* yet supported by vulkan-renderer. */
assert(output->base.eotf_mode == WESTON_EOTF_MODE_SDR);
if (!b->format->vulkan_format) {
weston_log("Error: failed to pick format for output '%s', format %s unsupported by vulkan-renderer.\n",
output->base.name, b->format->drm_format_name);
return false;
}
assert(b->format);
output->format = b->format;
if (output->has_underlay && (output->format->bits.a == 0)) {
weston_log("Disabling underlay planes: output '%s' with format %s does not have alpha channel,\n"
"which is required to support underlay planes.\n",
output->base.name, output->format->drm_format_name);
output->has_underlay = false;
}
return true;
}
/* Init output state that depends on vulkan */
int
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b)
{
const struct weston_mode *mode = output->base.current_mode;
struct weston_renderer *renderer = b->compositor->renderer;
if (!output->format && !drm_output_pick_format_vulkan(output))
return -1;
const struct vulkan_renderer_surfaceless_options options = {
.area.x = 0,
.area.y = 0,
.area.width = mode->width,
.area.height = mode->height,
.fb_size.width = mode->width,
.fb_size.height = mode->height,
};
if (renderer->vulkan->output_surfaceless_create(&output->base, &options) < 0) {
weston_log("failed to create vulkan renderer output state\n");
return -1;
}
create_renderbuffers(b->gbm, output, ARRAY_LENGTH(output->renderbuffer));
if (!output->linux_dmabuf_memory[0]) {
weston_log("failed to create dmabufs\n");
return -1;
}
drm_output_init_cursor_vulkan(output, b);
return 0;
}
void
drm_output_fini_egl(struct drm_output *output)
{
@ -755,8 +280,12 @@ drm_output_fini_egl(struct drm_output *output)
const struct weston_renderer *renderer = b->compositor->renderer;
/* Destroying the GBM surface will destroy all our GBM buffers,
* regardless of refcount. */
weston_assert_ptr_null(b->compositor, output->scanout_handle);
* regardless of refcount. Ensure we destroy them here. */
if (!b->compositor->shutting_down &&
output->scanout_plane->state_cur->fb &&
output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
drm_plane_reset_state(output->scanout_plane);
}
renderer->gl->output_destroy(&output->base);
gbm_surface_destroy(output->gbm_surface);
@ -764,22 +293,6 @@ drm_output_fini_egl(struct drm_output *output)
drm_output_fini_cursor_egl(output);
}
void
drm_output_fini_vulkan(struct drm_output *output)
{
struct drm_backend *b = output->backend;
const struct weston_renderer *renderer = b->compositor->renderer;
weston_assert_ptr_null(b->compositor, output->scanout_handle);
for (unsigned int i = 0; i < ARRAY_LENGTH(output->renderbuffer); i++)
renderer->destroy_renderbuffer(output->renderbuffer[i]);
renderer->vulkan->output_destroy(&output->base);
drm_output_fini_cursor_vulkan(output);
}
struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{
@ -811,36 +324,3 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
return ret;
}
struct drm_fb *
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage)
{
struct drm_output *output = state->output;
struct drm_device *device = output->device;
struct linux_dmabuf_memory *dmabuf;
struct drm_fb *ret;
output->base.compositor->renderer->repaint_output(&output->base,
damage,
output->renderbuffer[output->current_image]);
dmabuf = output->linux_dmabuf_memory[output->current_image];
if (!dmabuf) {
weston_log("failed to get dmabuf\n");
return NULL;
}
/* Output transparent/opaque image according to the format required by
* the client. */
ret = drm_fb_get_from_dmabuf_attributes(dmabuf->attributes, device,
!output->format->opaque_substitute,
false, true, NULL);
if (!ret) {
weston_log("failed to get drm_fb for dmabuf\n");
return NULL;
}
output->current_image = (output->current_image + 1) % ARRAY_LENGTH(output->renderbuffer);
return ret;
}

View file

@ -78,12 +78,6 @@
#define DRM_PLANE_ALPHA_OPAQUE 0xffffUL
#endif
#ifndef MAX_DMABUF_PLANES
#define MAX_DMABUF_PLANES 4
#endif
#define DRM_MAX_REUSE_FAILURES 10
/**
* A small wrapper to print information into the 'drm-backend' debug scope.
*
@ -117,15 +111,8 @@
* system. To avoid confusing side effects, we explicitly cast to the widest
* possible type and use a matching format specifier.
*/
#define DO_DRM_DEBUG_COMPLEX(scope, ...) \
weston_log_scope_printf(scope, __VA_ARGS__)
#define DO_DRM_DEBUG(scope, string) \
weston_log_scope_puts(scope, string)
#define drm_debug(b, format, ...) \
DO_DRM_DEBUG ## __VA_OPT__(_COMPLEX) \
((b)->debug, format __VA_OPT__(,) __VA_ARGS__)
#define drm_debug(b, ...) \
weston_log_scope_printf((b)->debug, __VA_ARGS__)
#define MAX_CLONED_CONNECTORS 4
@ -162,6 +149,28 @@ struct drm_property_info {
uint64_t range_values[2];
};
/**
* Reasons why placing a view on a plane failed. Needed by the dma-buf feedback.
*/
enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_NONE = 0,
FAILURE_REASONS_FORCE_RENDERER = 1 << 0,
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = 1 << 1,
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = 1 << 2,
FAILURE_REASONS_ADD_FB_FAILED = 1 << 3,
FAILURE_REASONS_NO_PLANES_AVAILABLE = 1 << 4,
FAILURE_REASONS_PLANES_REJECTED = 1 << 5,
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION = 1 << 6,
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM = 1 << 7,
FAILURE_REASONS_NO_BUFFER = 1 << 8,
FAILURE_REASONS_BUFFER_TOO_BIG = 1 << 9,
FAILURE_REASONS_BUFFER_TYPE = 1 << 10,
FAILURE_REASONS_GLOBAL_ALPHA = 1 << 11,
FAILURE_REASONS_NO_GBM = 1 << 12,
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = 1 << 13,
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED = 1 << 14,
};
/**
* We use this to keep track of actions we need to do with the dma-buf feedback
* in order to keep it up-to-date with the info we get from the DRM-backend.
@ -172,35 +181,15 @@ enum actions_needed_dmabuf_feedback {
ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE = (1 << 1),
};
enum drm_plane_subtype {
PLANE_SUBTYPE_OVERLAY_ONLY = 0,
PLANE_SUBTYPE_UNDERLAY_ONLY = 1,
PLANE_SUBTYPE_BOTH = 2,
};
enum drm_recovery_status {
DRM_RECOVERY_UNNECESSARY = 0,
DRM_RECOVERY_WAIT_FOR_IDLE = 1,
DRM_RECOVERY_SCHEDULED = 2,
DRM_RECOVERY_APPLIED = 3,
};
struct drm_kms_device {
int id;
char *filename;
dev_t devnum;
struct udev_device *udev_device;
int fd;
struct weston_launcher *fd_owner;
};
struct drm_device {
struct drm_backend *backend;
/* owned */
struct drm_kms_device *kms_device;
struct wl_event_source *drm_event_source;
struct {
int id;
int fd;
char *filename;
dev_t devnum;
} drm;
/* Track the GEM handles if the device does not have a gbm device, which
* tracks the handles for us.
@ -217,9 +206,7 @@ struct drm_device {
bool will_repaint;
enum drm_recovery_status recovery_status;
int32_t atomic_completes_pending;
bool state_invalid;
bool atomic_modeset;
@ -231,7 +218,7 @@ struct drm_device {
int32_t cursor_height;
bool cursors_are_broken;
bool disable_client_buffer_scanout;
bool sprites_are_broken;
void *repaint_data;
@ -246,11 +233,6 @@ struct drm_device {
/* drm_backend::kms_list */
struct wl_list link;
/* struct drm_colorop_3x1d_lut::link */
struct wl_list drm_colorop_3x1d_lut_list;
int reused_state_failures;
};
struct drm_backend {
@ -258,6 +240,7 @@ struct drm_backend {
struct weston_compositor *compositor;
struct udev *udev;
struct wl_event_source *drm_source;
struct udev_monitor *udev_monitor;
struct wl_event_source *udev_drm_source;
@ -271,22 +254,14 @@ struct drm_backend {
bool use_pixman_shadow;
bool offload_blend_to_output;
struct udev_input input;
uint32_t pageflip_timeout;
/* True, if underlay planes exist. */
bool has_underlay;
struct weston_log_scope *debug;
struct {
uint32_t frame_counter_interval;
struct wl_event_source *pageflip_timer_counter;
bool timer_armed;
} perf_page_flips_stats;
/* True if we need a workaround for some very old kernels */
bool stale_timestamp_workaround;
};
struct drm_mode {
@ -299,7 +274,6 @@ enum drm_fb_type {
BUFFER_INVALID = 0, /**< never used */
BUFFER_CLIENT, /**< directly sourced from client */
BUFFER_DMABUF, /**< imported from linux_dmabuf client */
BUFFER_DMABUF_BACKEND, /**< imported from dmabuf renderbuffer */
BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
BUFFER_GBM_SURFACE, /**< internal EGL rendering */
BUFFER_CURSOR, /**< internal cursor buffer */
@ -314,9 +288,9 @@ struct drm_fb {
int refcnt;
uint32_t fb_id, size;
uint32_t handles[MAX_DMABUF_PLANES];
uint32_t strides[MAX_DMABUF_PLANES];
uint32_t offsets[MAX_DMABUF_PLANES];
uint32_t handles[4];
uint32_t strides[4];
uint32_t offsets[4];
int num_planes;
const struct pixel_format_info *format;
uint64_t modifier;
@ -329,12 +303,6 @@ struct drm_fb {
struct gbm_bo *bo;
struct gbm_surface *gbm_surface;
/* Used when direct-display extension is turned on for that dmabuf */
bool direct_display;
int fds[MAX_DMABUF_PLANES];
/* tracks how many fds we've dup'ed */
int num_duped_fds;
/* Used by dumb fbs */
void *map;
};
@ -362,15 +330,6 @@ struct drm_pending_state {
struct wl_list output_list;
};
enum drm_output_propose_state_mode {
DRM_OUTPUT_PROPOSE_STATE_INVALID = 0, /**< Invalid state */
DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
DRM_OUTPUT_PROPOSE_STATE_RENDERER_AND_CURSOR, /**< only assign to renderer & cursor plane */
DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY, /**< only assign to renderer */
DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY, /**< no renderer use, only planes */
DRM_OUTPUT_PROPOSE_STATE_REUSE = 128, /**< bit indicates reuse prior state with new buffers */
};
/*
* Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
* plus >= 1 each of encoder/connector/plane. Since everything but the planes
@ -384,13 +343,11 @@ enum drm_output_propose_state_mode {
struct drm_output_state {
struct drm_pending_state *pending_state;
struct drm_output *output;
enum drm_output_propose_state_mode mode;
struct wl_list link;
enum dpms_enum dpms;
enum weston_hdcp_protection protection;
struct wl_list plane_list;
bool tear;
bool planes_enabled;
};
/**
@ -402,7 +359,7 @@ struct drm_output_state {
*/
struct drm_plane_state {
struct drm_plane *plane;
struct drm_plane_handle *handle;
struct drm_output *output;
struct drm_output_state *output_state;
struct drm_fb *fb;
@ -411,7 +368,7 @@ struct drm_plane_state {
struct weston_buffer_release_reference release;
} fb_ref;
struct weston_paint_node *paint_node; /**< maintained for drm_assign_planes only */
struct weston_view *ev; /**< maintained for drm_assign_planes only */
int32_t src_x, src_y;
uint32_t src_w, src_h;
@ -423,9 +380,6 @@ struct drm_plane_state {
uint64_t zpos;
uint16_t alpha;
enum wdrm_plane_color_encoding color_encoding;
enum wdrm_plane_color_range color_range;
bool complete;
/* We don't own the fd, so we shouldn't close it */
@ -464,6 +418,8 @@ struct drm_plane {
uint32_t crtc_id;
struct drm_property_info props[WDRM_PLANE__COUNT];
/* True if the plane's zpos_max < primary plane's zpos_min. */
bool is_underlay;
/* The last state submitted to the kernel for this plane. */
struct drm_plane_state *state_cur;
@ -479,16 +435,6 @@ struct drm_plane {
struct weston_drm_format_array formats;
};
struct drm_plane_handle {
struct drm_output *output;
struct drm_plane *plane;
/* Whether this plane supports overlay, underlay, or both */
enum drm_plane_subtype subtype;
struct wl_list link; /* drm_output::plane_handle_list */
};
struct drm_connector {
struct drm_device *device;
@ -548,19 +494,6 @@ struct drm_writeback {
struct weston_drm_format_array formats;
};
struct drm_colorop_3x1d_lut {
/* drm_device::drm_colorop_3x1d_lut_list */
struct wl_list link;
struct drm_device *device;
uint64_t lut_size;
struct weston_color_transform *xform;
struct wl_listener destroy_listener;
uint32_t blob_id;
};
struct drm_head {
struct weston_head base;
struct drm_connector connector;
@ -591,15 +524,6 @@ struct drm_crtc {
/* Holds the properties for the CRTC */
struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
/* CRTC prop WDRM_CRTC_GAMMA_LUT_SIZE */
uint32_t lut_size;
/* CRTC prop WDRM_CRTC_BACKGROUND_COLOR */
uint64_t background_color;
/* Union of formats of all compatible writeback connectors */
struct weston_drm_format_array writeback_formats;
};
struct drm_output {
@ -618,20 +542,14 @@ struct drm_output {
bool dpms_off_pending;
bool mode_switch_pending;
/* List of hardware planes this output can use, excluding the special
* cursor and scanout planes. */
struct wl_list plane_handle_list;
/* True, if underlay planes exist. */
bool has_underlay;
uint32_t gbm_cursor_handle[2];
struct drm_fb *gbm_cursor_fb[2];
struct drm_plane_handle *cursor_handle;
struct drm_plane *cursor_plane;
struct weston_view *cursor_view;
struct wl_listener cursor_view_destroy_listener;
int current_cursor;
struct gbm_surface *gbm_surface;
struct linux_dmabuf_memory *linux_dmabuf_memory[2];
const struct pixel_format_info *format;
uint32_t gbm_bo_flags;
@ -641,12 +559,11 @@ struct drm_output {
unsigned max_bpc;
enum wdrm_colorspace connector_colorspace;
bool deprecated_gamma_is_set;
bool legacy_gamma_not_supported;
uint16_t legacy_gamma_size;
struct drm_colorop_3x1d_lut *blend_to_output_xform;
/* Plane being displayed directly on the CRTC */
struct drm_plane_handle *scanout_handle;
struct drm_plane *scanout_plane;
/* The last state submitted to the kernel for this CRTC. */
struct drm_output_state *state_cur;
@ -658,26 +575,20 @@ struct drm_output {
struct drm_writeback_state *wb_state;
struct drm_fb *dumb[2];
weston_renderbuffer_t renderbuffer[2];
struct weston_renderbuffer *renderbuffer[2];
int current_image;
struct vaapi_recorder *recorder;
struct wl_listener recorder_frame_listener;
struct wl_event_source *pageflip_timer;
/* how many page flips */
uint32_t page_flips_counted;
/* how many page flips / interval */
float page_flips_per_timer_interval;
bool is_virtual;
void (*virtual_destroy)(struct weston_output *base);
submit_frame_cb virtual_submit_frame;
enum wdrm_content_type content_type;
bool reused_state;
bool force_rebuild_state;
};
void
@ -691,20 +602,11 @@ to_drm_head(struct weston_head *base)
return container_of(base, struct drm_head, base);
}
void
drm_device_recovery_schedule(struct drm_device *device);
void
drm_device_recovery_required(struct drm_device *device);
void
drm_device_recovery_complete(struct drm_device *device);
void
drm_writeback_reference_planes(struct drm_writeback_state *state,
struct wl_list *plane_state_list);
bool
drm_writeback_try_complete(struct drm_writeback_state *state);
drm_writeback_should_wait_completion(struct drm_writeback_state *state);
void
drm_writeback_fail_screenshot(struct drm_writeback_state *state,
const char *err_msg);
@ -748,55 +650,24 @@ to_drm_mode(struct weston_mode *base)
}
static inline const char *
drm_output_get_plane_type_name_internal(struct drm_plane *p, struct drm_plane_handle *h)
drm_output_get_plane_type_name(struct drm_plane *p)
{
assert(!p || !h);
if (h)
p = h->plane;
switch (p->type) {
case WDRM_PLANE_TYPE_PRIMARY:
return "primary";
case WDRM_PLANE_TYPE_CURSOR:
return "cursor";
case WDRM_PLANE_TYPE_OVERLAY:
if (!h)
return "overlay(no subtype)";
switch (h->subtype) {
case PLANE_SUBTYPE_OVERLAY_ONLY:
return "overlay";
case PLANE_SUBTYPE_UNDERLAY_ONLY:
return "underlay";
case PLANE_SUBTYPE_BOTH:
return "over/underlay";
}
// fall through
return p->is_underlay ? "underlay" : "overlay";
default:
assert(0);
break;
}
}
static inline const char *
drm_output_get_plane_type_name(struct drm_plane *p)
{
return drm_output_get_plane_type_name_internal(p, NULL);
}
static inline const char *
drm_output_get_handle_type_name(struct drm_plane_handle *h)
{
return drm_output_get_plane_type_name_internal(NULL, h);
}
struct drm_crtc *
drm_crtc_find(struct drm_device *device, uint32_t crtc_id);
bool
drm_crtc_supports_background_color(struct drm_crtc *crtc);
struct drm_head *
drm_head_find_by_connector(struct drm_backend *backend, struct drm_device *device, uint32_t connector_id);
@ -879,6 +750,10 @@ drm_pending_state_apply(struct drm_pending_state *pending_state);
int
drm_pending_state_apply_sync(struct drm_pending_state *pending_state);
void
drm_output_set_gamma(struct weston_output *output_base,
uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b);
void
drm_output_update_msc(struct drm_output *output, unsigned int seq);
void
@ -895,15 +770,13 @@ drm_fb_unref(struct drm_fb *fb);
struct drm_fb *
drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format);
struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons);
struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type);
void
drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev);
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output);
@ -913,23 +786,15 @@ wdrm_colorspace_from_output(struct weston_output *output);
#ifdef BUILD_DRM_GBM
extern struct drm_fb *
drm_fb_get_from_paint_node(struct drm_output_state *state,
struct weston_paint_node *pnode,
uint32_t *try_view_on_plane_failure_reasons);
struct weston_paint_node *pnode);
extern bool
drm_can_scanout_dmabuf(struct weston_backend *backend,
struct linux_dmabuf_buffer *dmabuf);
struct drm_fb *
drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
struct drm_device *device, bool is_opaque,
bool direct_display, bool is_internal,
uint32_t *try_view_on_plane_failure_reasons);
#else
static inline struct drm_fb *
drm_fb_get_from_paint_node(struct drm_output_state *state,
struct weston_paint_node *pnode,
uint32_t *try_view_on_plane_failure_reasons)
struct weston_paint_node *pnode)
{
return NULL;
}
@ -986,7 +851,7 @@ void
drm_plane_state_free(struct drm_plane_state *state, bool force);
void
drm_plane_state_put_back(struct drm_plane_state *state);
void
bool
drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
struct weston_paint_node *node,
uint64_t zpos);
@ -999,14 +864,6 @@ drm_assign_planes(struct weston_output *output_base);
bool
drm_plane_is_available(struct drm_plane *plane, struct drm_output *output);
bool
drm_plane_supports_color_encoding(struct drm_plane *plane,
enum wdrm_plane_color_encoding encoding);
bool
drm_plane_supports_color_range(struct drm_plane *plane,
enum wdrm_plane_color_range range);
void
drm_output_render(struct drm_output_state *state);
@ -1014,12 +871,6 @@ int
parse_gbm_format(const char *s, const struct pixel_format_info *default_format,
const struct pixel_format_info **format);
struct drm_plane_handle *
drm_plane_create_handle(struct drm_plane *plane, struct drm_output *output);
void
drm_plane_destroy_handle(struct drm_plane_handle *plane);
#ifdef BUILD_DRM_VIRTUAL
extern int
drm_backend_init_virtual_output_api(struct weston_compositor *compositor);
@ -1044,18 +895,6 @@ drm_output_fini_egl(struct drm_output *output);
struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
int
init_vulkan(struct drm_backend *b);
int
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b);
void
drm_output_fini_vulkan(struct drm_output *output);
struct drm_fb *
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage);
#else
inline static int
init_egl(struct drm_backend *b)
@ -1080,29 +919,4 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{
return NULL;
}
inline static int
init_vulkan(struct drm_backend *b)
{
weston_log("Compiled without GBM support\n");
return -1;
}
inline static int
drm_output_init_vulkan(struct drm_output *output, struct drm_backend *b)
{
return -1;
}
inline static void
drm_output_fini_vulkan(struct drm_output *output)
{
}
inline static struct drm_fb *
drm_output_render_vulkan(struct drm_output_state *state, pixman_region32_t *damage)
{
return NULL;
}
#endif

View file

@ -56,8 +56,6 @@ enum wdrm_plane_property {
WDRM_PLANE_ZPOS,
WDRM_PLANE_ROTATION,
WDRM_PLANE_ALPHA,
WDRM_PLANE_COLOR_ENCODING,
WDRM_PLANE_COLOR_RANGE,
WDRM_PLANE__COUNT
};
@ -84,27 +82,6 @@ enum wdrm_plane_rotation {
WDRM_PLANE_ROTATION__COUNT,
};
/**
* Possible values for the WDRM_PLANE_COLOR_ENCODING property.
*/
enum wdrm_plane_color_encoding {
WDRM_PLANE_COLOR_ENCODING_BT601 = 0,
WDRM_PLANE_COLOR_ENCODING_BT709,
WDRM_PLANE_COLOR_ENCODING_BT2020,
WDRM_PLANE_COLOR_ENCODING__COUNT
};
#define WDRM_PLANE_COLOR_ENCODING_DEFAULT WDRM_PLANE_COLOR_ENCODING_BT709
/**
* Possible values for the WDRM_PLANE_COLOR_RANGE property.
*/
enum wdrm_plane_color_range {
WDRM_PLANE_COLOR_RANGE_LIMITED = 0,
WDRM_PLANE_COLOR_RANGE_FULL,
WDRM_PLANE_COLOR_RANGE__COUNT
};
#define WDRM_PLANE_COLOR_RANGE_DEFAULT WDRM_PLANE_COLOR_RANGE_LIMITED
/**
* List of properties attached to a DRM connector
*/
@ -123,7 +100,6 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR_CONTENT_TYPE,
WDRM_CONNECTOR_COLORSPACE,
WDRM_CONNECTOR_VRR_CAPABLE,
WDRM_CONNECTOR__COUNT
};
@ -197,6 +173,5 @@ enum wdrm_crtc_property {
WDRM_CRTC_GAMMA_LUT,
WDRM_CRTC_GAMMA_LUT_SIZE,
WDRM_CRTC_VRR_ENABLED,
WDRM_CRTC_BACKGROUND_COLOR,
WDRM_CRTC__COUNT
};

View file

@ -38,7 +38,6 @@
#include "drm-internal.h"
#include "pixel-formats.h"
#include "renderer-gl/gl-renderer.h"
#include "shared/weston-assert.h"
#define POISON_PTR ((void *)8)
@ -105,7 +104,7 @@ get_drm_plane_index_maximum(struct drm_device *device)
* @param device DRM device
* @param output Output to create internal plane for
*/
static struct drm_plane_handle *
static struct drm_plane *
drm_virtual_plane_create(struct drm_device *device, struct drm_output *output)
{
struct drm_backend *b = device->backend;
@ -146,7 +145,7 @@ drm_virtual_plane_create(struct drm_device *device, struct drm_output *output)
plane->plane_idx = get_drm_plane_index_maximum(device) + 1;
wl_list_insert(&device->plane_list, &plane->link);
return drm_plane_create_handle(plane, output);
return plane;
err:
drm_plane_state_free(plane->state_cur, true);
@ -158,15 +157,11 @@ err:
/**
* Destroy one DRM plane
*
* @param handle Plane handle to deallocate (will be freed along with the plane)
* @param plane Plane to deallocate (will be freed)
*/
static void
drm_virtual_plane_destroy(struct drm_plane_handle *handle)
drm_virtual_plane_destroy(struct drm_plane *plane)
{
struct drm_plane *plane = handle->plane;
drm_plane_destroy_handle(handle);
drm_plane_state_free(plane->state_cur, true);
weston_plane_release(&plane->base);
wl_list_remove(&plane->link);
@ -210,9 +205,8 @@ static int
drm_virtual_output_repaint(struct weston_output *output_base)
{
struct drm_output_state *state = NULL;
struct weston_compositor *compositor = output_base->compositor;
struct drm_output *output = to_drm_output(output_base);
struct drm_plane *scanout_plane = output->scanout_handle->plane;
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_plane_state *scanout_state;
struct drm_pending_state *pending_state;
struct drm_device *device;
@ -233,10 +227,14 @@ drm_virtual_output_repaint(struct weston_output *output_base)
assert(!output->state_last);
/* assign_planes() is always called before a repaint, so we must have a
* valid output state here. */
/* If planes have been disabled in the core, we might not have
* hit assign_planes at all, so might not have valid output state
* here. */
state = drm_pending_state_get_output(pending_state, output);
weston_assert_ptr_not_null(compositor, state);
if (!state)
state = drm_output_state_duplicate(output->state_cur,
pending_state,
DRM_OUTPUT_STATE_CLEAR_PLANES);
drm_output_render(state);
scanout_state = drm_output_state_get_plane(state, scanout_plane);
@ -260,7 +258,7 @@ drm_virtual_output_deinit(struct weston_output *base)
drm_output_fini_egl(output);
drm_virtual_plane_destroy(output->scanout_handle);
drm_virtual_plane_destroy(output->scanout_plane);
drm_virtual_crtc_destroy(output->crtc);
}
@ -303,8 +301,8 @@ drm_virtual_output_enable(struct weston_output *output_base)
goto err;
}
output->scanout_handle = drm_virtual_plane_create(device, output);
if (!output->scanout_handle) {
output->scanout_plane = drm_virtual_plane_create(device, output);
if (!output->scanout_plane) {
weston_log("Failed to find primary plane for output %s\n",
output->base.name);
return -1;
@ -320,6 +318,12 @@ drm_virtual_output_enable(struct weston_output *output_base)
output->base.assign_planes = drm_assign_planes;
output->base.set_dpms = NULL;
output->base.switch_mode = NULL;
output->base.gamma_size = 0;
output->base.set_gamma = NULL;
weston_compositor_stack_plane(b->compositor,
&output->scanout_plane->base,
&output->base.primary_plane);
return 0;
err:
@ -440,6 +444,11 @@ drm_virtual_output_finish_frame(struct weston_output *output_base,
output->state_last = NULL;
weston_output_finish_frame(&output->base, stamp, presented_flags);
/* We can't call this from frame_notify, because the output's
* repaint needed flag is cleared just after that */
if (output->recorder)
weston_output_schedule_repaint(&output->base);
}
static const struct weston_drm_virtual_output_api virt_api = {

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,6 @@
#include "shared/hash.h"
#include "shared/helpers.h"
#include "shared/weston-drm-fourcc.h"
#include "shared/weston-assert.h"
#include "drm-internal.h"
#include "linux-dmabuf.h"
@ -100,7 +99,7 @@ static void gem_handle_put(struct drm_device *device, int handle)
ref_count = hash_table_lookup(device->gem_handle_refcnt, handle);
if (!ref_count) {
weston_log("failed to find GEM handle %d for device %s\n",
handle, device->kms_device->filename);
handle, device->drm.filename);
return;
}
(*ref_count)--;
@ -108,28 +107,20 @@ static void gem_handle_put(struct drm_device *device, int handle)
if (*ref_count == 0) {
hash_table_remove(device->gem_handle_refcnt, handle);
free(ref_count);
drmCloseBufferHandle(device->kms_device->fd, handle);
drmCloseBufferHandle(device->drm.fd, handle);
}
}
static int
drm_fb_import_plane(struct drm_device *device, struct drm_fb *fb, int plane)
{
int bo_fd = -1;
int bo_fd;
uint32_t handle;
int ret;
/* neither a BO nor a direct-display means we shouldn't be calling this */
assert(!!fb->bo ^ fb->direct_display);
if (fb->bo) {
bo_fd = gbm_bo_get_fd_for_plane(fb->bo, plane);
if (bo_fd < 0)
return bo_fd;
}
if (fb->direct_display)
bo_fd = fb->fds[plane];
bo_fd = gbm_bo_get_fd_for_plane(fb->bo, plane);
if (bo_fd < 0)
return bo_fd;
/*
* drmPrimeFDToHandle is dangerous, because the GEM handles are
@ -156,10 +147,7 @@ drm_fb_import_plane(struct drm_device *device, struct drm_fb *fb, int plane)
fb->handles[plane] = gem_handle_get(device, handle);
out:
/* on the direct-display path the dup'ed fds will be closed by
* drm_fb_destroy_dmabuf */
if (fb->bo)
close(bo_fd);
close(bo_fd);
return ret;
}
#endif
@ -183,35 +171,23 @@ drm_fb_maybe_import(struct drm_device *device, struct drm_fb *fb)
struct gbm_device *gbm_device;
int ret = 0;
int plane;
int num_planes;
/* No import possible, if there is no gbm bo or fb is not using
* direct-display */
if (!fb->bo && !fb->direct_display)
/* No import possible, if there is no gbm bo */
if (!fb->bo)
return 0;
if (fb->bo) {
weston_assert_false(device->backend->compositor, fb->direct_display);
/* No import necessary, if the gbm bo and the fb use the same device */
gbm_device = gbm_bo_get_device(fb->bo);
if (gbm_device_get_fd(gbm_device) == fb->fd)
return 0;
/* No import necessary, if the gbm bo and the fb use the same device */
gbm_device = gbm_bo_get_device(fb->bo);
if (gbm_device_get_fd(gbm_device) == fb->fd)
return 0;
if (fb->fd != device->kms_device->fd) {
weston_log("fb was not allocated for scanout device %s\n",
device->kms_device->filename);
return -1;
}
num_planes = gbm_bo_get_plane_count(fb->bo);
} else {
weston_assert_true(device->backend->compositor, fb->direct_display);
num_planes = fb->num_planes;
if (fb->fd != device->drm.fd) {
weston_log("fb was not allocated for scanout device %s\n",
device->drm.filename);
return -1;
}
for (plane = 0; plane < num_planes; plane++) {
for (plane = 0; plane < gbm_bo_get_plane_count(fb->bo); plane++) {
ret = drm_fb_import_plane(device, fb, plane);
if (ret)
goto err;
@ -313,7 +289,7 @@ drm_fb_create_dumb(struct drm_device *device, int width, int height,
create_arg.width = width;
create_arg.height = height;
ret = drmIoctl(device->kms_device->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
ret = drmIoctl(device->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
if (ret)
goto err_fb;
@ -325,7 +301,7 @@ drm_fb_create_dumb(struct drm_device *device, int width, int height,
fb->size = create_arg.size;
fb->width = width;
fb->height = height;
fb->fd = device->kms_device->fd;
fb->fd = device->drm.fd;
if (drm_fb_addfb(device, fb) != 0) {
weston_log("failed to create kms fb: %s\n", strerror(errno));
@ -339,18 +315,18 @@ drm_fb_create_dumb(struct drm_device *device, int width, int height,
goto err_add_fb;
fb->map = mmap(NULL, fb->size, PROT_WRITE,
MAP_SHARED, device->kms_device->fd, map_arg.offset);
MAP_SHARED, device->drm.fd, map_arg.offset);
if (fb->map == MAP_FAILED)
goto err_add_fb;
return fb;
err_add_fb:
drmModeRmFB(device->kms_device->fd, fb->fb_id);
drmModeRmFB(device->drm.fd, fb->fb_id);
err_bo:
memset(&destroy_arg, 0, sizeof(destroy_arg));
destroy_arg.handle = create_arg.handle;
drmIoctl(device->kms_device->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
drmIoctl(device->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
err_fb:
free(fb);
return NULL;
@ -388,35 +364,27 @@ drm_fb_destroy_dmabuf(struct drm_fb *fb)
* If we imported the dmabuf into a scanout device, we are responsible
* for closing the GEM handle.
*/
for (i = 0; i < MAX_DMABUF_PLANES; i++) {
if (fb->scanout_device && fb->handles[i] != 0) {
for (i = 0; i < 4; i++)
if (fb->scanout_device && fb->handles[i] != 0)
gem_handle_put(fb->scanout_device, fb->handles[i]);
fb->handles[i] = 0;
}
}
for (i = 0; i < fb->num_duped_fds; i++)
close(fb->fds[i]);
drm_fb_destroy(fb);
}
struct drm_fb *
drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
struct drm_device *device, bool is_opaque,
bool direct_display, bool is_internal,
uint32_t *try_view_on_plane_failure_reasons)
static struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons)
{
struct drm_backend *backend = device->backend;
struct drm_fb *fb;
int i;
struct gbm_import_fd_modifier_data import_mod = {
.width = attributes->width,
.height = attributes->height,
.format = attributes->format,
.num_fds = attributes->n_planes,
.modifier = attributes->modifier,
.width = dmabuf->attributes.width,
.height = dmabuf->attributes.height,
.format = dmabuf->attributes.format,
.num_fds = dmabuf->attributes.n_planes,
.modifier = dmabuf->attributes.modifier,
};
/* We should not import to KMS a buffer that has been allocated using no
@ -426,7 +394,7 @@ drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
* KMS driver can't know. So giving the buffer to KMS is not safe, as
* not knowing its layout can result in garbage being displayed. In
* short, importing a buffer to KMS requires explicit modifiers. */
if (attributes->modifier == DRM_FORMAT_MOD_INVALID) {
if (dmabuf->attributes.modifier == DRM_FORMAT_MOD_INVALID) {
if (try_view_on_plane_failure_reasons)
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_DMABUF_MODIFIER_INVALID;
@ -442,7 +410,7 @@ drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
* these types of buffers should be handled through buffer
* transforms and not as spot-checks requiring specific
* knowledge. */
if (attributes->flags)
if (dmabuf->attributes.flags)
return NULL;
fb = zalloc(sizeof *fb);
@ -450,30 +418,12 @@ drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
return NULL;
fb->refcnt = 1;
fb->type = is_internal ? BUFFER_DMABUF_BACKEND : BUFFER_DMABUF;
fb->type = BUFFER_DMABUF;
fb->backend = device->backend;
ARRAY_COPY(import_mod.fds, attributes->fd);
ARRAY_COPY(import_mod.strides, attributes->stride);
ARRAY_COPY(import_mod.offsets, attributes->offset);
/* skip bo import if dmabuf is using direct-display extension */
if (direct_display) {
fb->direct_display = true;
/* we're making a dup of the fds from attributes->fd as
* opposed to just copying the fds with ARRAY_COPY() */
for (i = 0; i < attributes->n_planes; i++) {
fb->fds[i] = dup(attributes->fd[i]);
if (fb->fds[i] == -1) {
weston_log("failed to dup dmabuf attribute fd: %s\n",
strerror(errno));
goto err_free;
}
fb->num_duped_fds++;
}
goto bo_import_skip;
}
ARRAY_COPY(import_mod.fds, dmabuf->attributes.fd);
ARRAY_COPY(import_mod.strides, dmabuf->attributes.stride);
ARRAY_COPY(import_mod.offsets, dmabuf->attributes.offset);
fb->bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_FD_MODIFIER,
&import_mod, GBM_BO_USE_SCANOUT);
@ -484,20 +434,19 @@ drm_fb_get_from_dmabuf_attributes(struct dmabuf_attributes *attributes,
goto err_free;
}
bo_import_skip:
fb->width = attributes->width;
fb->height = attributes->height;
fb->modifier = attributes->modifier;
fb->width = dmabuf->attributes.width;
fb->height = dmabuf->attributes.height;
fb->modifier = dmabuf->attributes.modifier;
fb->size = 0;
fb->fd = device->kms_device->fd;
fb->fd = device->drm.fd;
ARRAY_COPY(fb->strides, attributes->stride);
ARRAY_COPY(fb->offsets, attributes->offset);
ARRAY_COPY(fb->strides, dmabuf->attributes.stride);
ARRAY_COPY(fb->offsets, dmabuf->attributes.offset);
fb->format = pixel_format_get_info(attributes->format);
fb->format = pixel_format_get_info(dmabuf->attributes.format);
if (!fb->format) {
weston_log("couldn't look up format info for 0x%lx\n",
(unsigned long) attributes->format);
(unsigned long) dmabuf->attributes.format);
goto err_free;
}
@ -512,8 +461,8 @@ bo_import_skip:
goto err_free;
}
fb->num_planes = attributes->n_planes;
for (i = 0; fb->bo && i < attributes->n_planes; i++) {
fb->num_planes = dmabuf->attributes.n_planes;
for (i = 0; i < dmabuf->attributes.n_planes; i++) {
union gbm_bo_handle handle;
handle = gbm_bo_get_handle_for_plane(fb->bo, i);
@ -539,18 +488,6 @@ err_free:
return NULL;
}
struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons)
{
return drm_fb_get_from_dmabuf_attributes(&dmabuf->attributes,
device, is_opaque,
dmabuf->direct_display,
false,
try_view_on_plane_failure_reasons);
}
struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type)
@ -571,7 +508,7 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
fb->refcnt = 1;
fb->backend = device->backend;
fb->bo = bo;
fb->fd = device->kms_device->fd;
fb->fd = device->drm.fd;
fb->width = gbm_bo_get_width(bo);
fb->height = gbm_bo_get_height(bo);
@ -645,7 +582,6 @@ drm_fb_unref(struct drm_fb *fb)
gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
break;
case BUFFER_DMABUF:
case BUFFER_DMABUF_BACKEND:
drm_fb_destroy_dmabuf(fb);
break;
#endif
@ -678,7 +614,7 @@ drm_can_scanout_dmabuf(struct weston_backend *backend,
static bool
drm_fb_compatible_with_plane(struct drm_fb *fb, struct drm_plane *plane,
struct weston_paint_node *pnode)
struct weston_view *view)
{
struct drm_device *device = plane->device;
struct drm_backend *b = device->backend;
@ -702,11 +638,10 @@ drm_fb_compatible_with_plane(struct drm_fb *fb, struct drm_plane *plane,
return true;
}
drm_debug(b, "\t\t\t\t[%s] not assigning paint node %s on %s, "
drm_debug(b, "\t\t\t\t[%s] not assigning view %p on %s, "
"plane %d (format %s (0x%lx) with modifier 0x%llx) not supported\n",
drm_output_get_plane_type_name(plane),
pnode->internal_name,
drm_output_get_plane_type_name(plane),
view, drm_output_get_plane_type_name(plane),
plane->plane_id, fb->format->drm_format_name,
(unsigned long) fb->format->format,
(unsigned long long) fb->modifier);
@ -739,29 +674,28 @@ drm_fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
struct drm_fb *
drm_fb_get_from_paint_node(struct drm_output_state *state,
struct weston_paint_node *pnode,
uint32_t *try_view_on_plane_failure_reasons)
struct weston_paint_node *pnode)
{
struct drm_output *output = state->output;
struct drm_backend *b = output->backend;
struct drm_device *device = output->device;
struct weston_surface *surface = pnode->surface;
struct weston_buffer *buffer = surface->buffer_ref.buffer;
struct weston_view *ev = pnode->view;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
struct drm_fb_private *private;
struct drm_buffer_fb *buf_fb;
bool is_opaque = pnode->is_fully_opaque;
bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
struct drm_fb *fb;
struct drm_plane *plane;
if (surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
surface->desired_protection > output->base.current_protection) {
*try_view_on_plane_failure_reasons |=
if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
ev->surface->desired_protection > output->base.current_protection) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION;
return NULL;
}
if (!buffer) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_BUFFER;
pnode->try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_BUFFER;
return NULL;
}
@ -777,7 +711,7 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
wl_list_for_each(buf_fb, &private->buffer_fb_list, link) {
if (buf_fb->device == device) {
*try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
pnode->try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
return buf_fb->fb ? drm_fb_ref(buf_fb->fb) : NULL;
}
}
@ -788,7 +722,7 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
/* GBM is used for dmabuf import as well as from client wl_buffer. */
if (!b->gbm) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_GBM;
pnode->try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_GBM;
goto unsuitable;
}
@ -807,13 +741,13 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
fb = drm_fb_get_from_bo(bo, device, is_opaque, BUFFER_CLIENT);
if (!fb) {
*try_view_on_plane_failure_reasons |=
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_ADD_FB_FAILED;
gbm_bo_destroy(bo);
goto unsuitable;
}
} else {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_BUFFER_TYPE;
pnode->try_view_on_plane_failure_reasons |= FAILURE_REASONS_BUFFER_TYPE;
goto unsuitable;
}
@ -824,7 +758,7 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
if (plane->type == WDRM_PLANE_TYPE_CURSOR)
continue;
if (drm_fb_compatible_with_plane(fb, plane, pnode))
if (drm_fb_compatible_with_plane(fb, plane, pnode->view))
fb->plane_mask |= 1 << (plane->plane_idx);
}
if (fb->plane_mask == 0) {
@ -837,12 +771,12 @@ drm_fb_get_from_paint_node(struct drm_output_state *state,
* drm_fb we take an additional ref for the weston_buffer's cache. */
buf_fb->fb = drm_fb_ref(fb);
drm_debug(b, "\t\t\t[paint node] paint node %s format: %s\n",
pnode->internal_name, fb->format->drm_format_name);
drm_debug(b, "\t\t\t[view] view %p format: %s\n",
ev, fb->format->drm_format_name);
return fb;
unsuitable:
*try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
pnode->try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
return NULL;
}
#endif

View file

@ -160,7 +160,7 @@ drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
return -1;
}
ret = drmModeCreatePropertyBlob(device->kms_device->fd,
ret = drmModeCreatePropertyBlob(device->drm.fd,
&meta, sizeof meta, &blob_id);
if (ret != 0) {
weston_log("Error: failed to create KMS blob for HDR metadata on output '%s': %s\n",
@ -168,7 +168,7 @@ drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
return -1;
}
drmModeDestroyPropertyBlob(device->kms_device->fd,
drmModeDestroyPropertyBlob(device->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = blob_id;

View file

@ -79,27 +79,6 @@ struct drm_property_enum_info plane_rotation_enums[] = {
},
};
struct drm_property_enum_info plane_color_encoding_enums[] = {
[WDRM_PLANE_COLOR_ENCODING_BT601] = {
.name = "ITU-R BT.601 YCbCr",
},
[WDRM_PLANE_COLOR_ENCODING_BT709] = {
.name = "ITU-R BT.709 YCbCr",
},
[WDRM_PLANE_COLOR_ENCODING_BT2020] = {
.name = "ITU-R BT.2020 YCbCr",
},
};
struct drm_property_enum_info plane_color_range_enums[] = {
[WDRM_PLANE_COLOR_RANGE_LIMITED] = {
.name = "YCbCr limited range",
},
[WDRM_PLANE_COLOR_RANGE_FULL] = {
.name = "YCbCr full range",
},
};
const struct drm_property_info plane_props[] = {
[WDRM_PLANE_TYPE] = {
.name = "type",
@ -124,18 +103,8 @@ const struct drm_property_info plane_props[] = {
.name = "rotation",
.enum_values = plane_rotation_enums,
.num_enum_values = WDRM_PLANE_ROTATION__COUNT,
},
},
[WDRM_PLANE_ALPHA] = { .name = "alpha" },
[WDRM_PLANE_COLOR_ENCODING] = {
.name = "COLOR_ENCODING",
.enum_values = plane_color_encoding_enums,
.num_enum_values = WDRM_PLANE_COLOR_ENCODING__COUNT,
},
[WDRM_PLANE_COLOR_RANGE] = {
.name = "COLOR_RANGE",
.enum_values = plane_color_range_enums,
.num_enum_values = WDRM_PLANE_COLOR_RANGE__COUNT,
},
};
struct drm_property_enum_info dpms_state_enums[] = {
@ -249,9 +218,6 @@ const struct drm_property_info connector_props[] = {
.enum_values = colorspace_enums,
.num_enum_values = WDRM_COLORSPACE__COUNT,
},
[WDRM_CONNECTOR_VRR_CAPABLE] = {
.name = "vrr_capable",
},
};
const struct drm_property_info crtc_props[] = {
@ -263,7 +229,6 @@ const struct drm_property_info crtc_props[] = {
[WDRM_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT", },
[WDRM_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE", },
[WDRM_CRTC_VRR_ENABLED] = { .name = "VRR_ENABLED", },
[WDRM_CRTC_BACKGROUND_COLOR] = { .name = "BACKGROUND_COLOR", },
};
@ -430,17 +395,6 @@ drm_rotation_from_output_transform(struct drm_plane *plane,
return out;
}
static int
wdrm_vrr_enabled_from_output(struct drm_output *drm_output)
{
struct weston_output *output = &drm_output->base;
if (output->vrr_mode == WESTON_VRR_MODE_GAME)
return 1;
return 0;
}
/**
* Cache DRM property values
*
@ -505,7 +459,7 @@ drm_property_info_populate(struct drm_device *device,
for (i = 0; i < props->count_props; i++) {
unsigned int k;
prop = drmModeGetProperty(device->kms_device->fd, props->props[i]);
prop = drmModeGetProperty(device->drm.fd, props->props[i]);
if (!prop)
continue;
@ -632,7 +586,7 @@ drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
if (blob_id == 0)
goto fallback;
blob = drmModeGetPropertyBlob(device->kms_device->fd, blob_id);
blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (!blob)
goto fallback;
@ -672,36 +626,26 @@ fallback:
return 0;
}
bool
drm_plane_supports_color_encoding(struct drm_plane *plane,
enum wdrm_plane_color_encoding encoding)
void
drm_output_set_gamma(struct weston_output *output_base,
uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
{
const struct drm_property_info *info;
const struct drm_property_enum_info *enum_info;
int rc;
struct drm_output *output = to_drm_output(output_base);
struct drm_device *device = output->device;
assert(encoding >= 0);
assert(encoding < WDRM_PLANE_COLOR_ENCODING__COUNT);
assert(output);
info = &plane->props[WDRM_PLANE_COLOR_ENCODING];
enum_info = &info->enum_values[encoding];
/* check */
if (output_base->gamma_size != size)
return;
return enum_info->valid;
}
bool
drm_plane_supports_color_range(struct drm_plane *plane,
enum wdrm_plane_color_range range)
{
const struct drm_property_info *info;
const struct drm_property_enum_info *enum_info;
assert(range >= 0);
assert(range < WDRM_PLANE_COLOR_RANGE__COUNT);
info = &plane->props[WDRM_PLANE_COLOR_RANGE];
enum_info = &info->enum_values[range];
return enum_info->valid;
output->deprecated_gamma_is_set = true;
rc = drmModeCrtcSetGamma(device->drm.fd,
output->crtc->crtc_id,
size, r, g, b);
if (rc)
weston_log("set gamma failed: %s\n", strerror(errno));
}
/**
@ -737,7 +681,6 @@ drm_output_assign_state(struct drm_output_state *state,
drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
output->crtc->crtc_id);
output->atomic_complete_pending = true;
device->atomic_completes_pending++;
}
if (device->atomic_modeset &&
@ -777,32 +720,28 @@ drm_output_set_cursor(struct drm_output_state *output_state)
struct drm_output *output = output_state->output;
struct drm_device *device = output->device;
struct drm_crtc *crtc = output->crtc;
struct drm_plane_handle *plane_handle = output->cursor_handle;
struct drm_plane *plane;
struct drm_plane *plane = output->cursor_plane;
struct drm_plane_state *state;
uint32_t handle;
if (!plane_handle)
if (!plane)
return;
plane = plane_handle->plane;
state = drm_output_state_get_existing_plane(output_state, plane);
if (!state)
return;
if (!state->fb) {
drmModeSetCursor(device->kms_device->fd, crtc->crtc_id, 0, 0, 0);
drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
return;
}
assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
assert(!plane->state_cur->handle ||
plane->state_cur->handle->output == output);
assert(!plane->state_cur->output || plane->state_cur->output == output);
handle = output->gbm_cursor_handle[output->current_cursor];
if (plane->state_cur->fb != state->fb) {
if (drmModeSetCursor(device->kms_device->fd, crtc->crtc_id, handle,
if (drmModeSetCursor(device->drm.fd, crtc->crtc_id, handle,
device->cursor_width, device->cursor_height)) {
weston_log("failed to set cursor: %s\n",
strerror(errno));
@ -810,7 +749,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
}
}
if (drmModeMoveCursor(device->kms_device->fd, crtc->crtc_id,
if (drmModeMoveCursor(device->drm.fd, crtc->crtc_id,
state->dest_x, state->dest_y)) {
weston_log("failed to move cursor: %s\n", strerror(errno));
goto err;
@ -820,13 +759,13 @@ drm_output_set_cursor(struct drm_output_state *output_state)
err:
device->cursors_are_broken = true;
drmModeSetCursor(device->kms_device->fd, crtc->crtc_id, 0, 0, 0);
drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
}
static void
drm_output_reset_legacy_gamma(struct drm_output *output)
{
uint32_t len = output->legacy_gamma_size;
uint32_t len = output->base.gamma_size;
uint16_t *lut;
uint32_t i;
int ret;
@ -845,7 +784,7 @@ drm_output_reset_legacy_gamma(struct drm_output *output)
for (i = 0; i < len; i++)
lut[i] = 0xffff * i / (len - 1);
ret = drmModeCrtcSetGamma(output->device->kms_device->fd,
ret = drmModeCrtcSetGamma(output->device->drm.fd,
output->crtc->crtc_id,
len, lut, lut, lut);
if (ret == -EOPNOTSUPP || ret == -ENOSYS)
@ -864,7 +803,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
struct drm_output *output = state->output;
struct drm_device *device = output->device;
struct drm_backend *backend = device->backend;
struct drm_plane *scanout_plane = output->scanout_handle->plane;
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_crtc *crtc = output->crtc;
struct drm_property_info *dpms_prop;
struct drm_plane_state *scanout_state;
@ -881,16 +820,28 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
connectors[n_conn++] = head->connector.connector_id;
}
/* If disable_planes is set then assign_planes() wasn't
* called for this render, so we could still have a stale
* cursor plane set up.
*/
if (output->base.disable_planes) {
drm_output_set_cursor_view(output, NULL);
if (output->cursor_plane) {
output->cursor_plane->base.x = INT32_MIN;
output->cursor_plane->base.y = INT32_MIN;
}
}
if (state->dpms != WESTON_DPMS_ON) {
if (output->cursor_handle) {
ret = drmModeSetCursor(device->kms_device->fd, crtc->crtc_id,
if (output->cursor_plane) {
ret = drmModeSetCursor(device->drm.fd, crtc->crtc_id,
0, 0, 0);
if (ret)
weston_log("drmModeSetCursor failed disable: %s\n",
strerror(errno));
}
ret = drmModeSetCrtc(device->kms_device->fd, crtc->crtc_id, 0, 0, 0,
ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
if (ret)
weston_log("drmModeSetCrtc failed disabling: %s\n",
@ -924,12 +875,12 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
assert(scanout_state->in_fence_fd == -1);
mode = to_drm_mode(output->base.current_mode);
if (device->recovery_status == DRM_RECOVERY_SCHEDULED ||
if (device->state_invalid ||
!scanout_plane->state_cur->fb ||
scanout_plane->state_cur->fb->strides[0] !=
scanout_state->fb->strides[0]) {
ret = drmModeSetCrtc(device->kms_device->fd, crtc->crtc_id,
ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id,
0, 0,
connectors, n_conn,
@ -939,7 +890,8 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
goto err;
}
drm_output_reset_legacy_gamma(output);
if (!output->deprecated_gamma_is_set)
drm_output_reset_legacy_gamma(output);
}
pinfo = scanout_state->fb->format;
@ -947,7 +899,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
crtc->crtc_id, scanout_state->plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN");
if (drmModePageFlip(device->kms_device->fd, crtc->crtc_id,
if (drmModePageFlip(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
weston_log("queueing pageflip failed: %s\n", strerror(errno));
@ -968,7 +920,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (dpms_prop->prop_id == 0)
continue;
ret = drmModeConnectorSetProperty(device->kms_device->fd,
ret = drmModeConnectorSetProperty(device->drm.fd,
head->connector.connector_id,
dpms_prop->prop_id,
state->dpms);
@ -984,6 +936,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
return 0;
err:
drm_output_set_cursor_view(output, NULL);
drm_output_state_free(state);
return -1;
}
@ -1040,15 +993,6 @@ crtc_add_prop_zero_ok(drmModeAtomicReq *req, struct drm_crtc *crtc,
return crtc_add_prop(req, crtc, prop, val);
}
bool
drm_crtc_supports_background_color(struct drm_crtc *crtc)
{
if (crtc->props_crtc[WDRM_CRTC_BACKGROUND_COLOR].prop_id != 0)
return true;
return false;
}
static int
connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
enum wdrm_connector_property prop, uint64_t val)
@ -1253,47 +1197,6 @@ drm_connector_set_colorspace(struct drm_connector *connector,
WDRM_CONNECTOR_COLORSPACE, enum_info->value);
}
static int
drm_plane_set_color_encoding(struct drm_plane *plane,
enum wdrm_plane_color_encoding color_encoding,
drmModeAtomicReq *req)
{
if (color_encoding == WDRM_PLANE_COLOR_ENCODING__COUNT)
return 0;
if (plane->props[WDRM_PLANE_COLOR_ENCODING].prop_id == 0) {
if (color_encoding == WDRM_PLANE_COLOR_ENCODING_DEFAULT)
return 0;
return -1;
}
assert(drm_plane_supports_color_encoding(plane, color_encoding));
return plane_add_prop(req, plane, WDRM_PLANE_COLOR_ENCODING,
color_encoding);
}
static int
drm_plane_set_color_range(struct drm_plane *plane,
enum wdrm_plane_color_range color_range,
drmModeAtomicReq *req)
{
if (color_range == WDRM_PLANE_COLOR_RANGE__COUNT)
return 0;
if (plane->props[WDRM_PLANE_COLOR_RANGE].prop_id == 0) {
if (color_range == WDRM_PLANE_COLOR_RANGE_DEFAULT)
return 0;
return -1;
}
assert(drm_plane_supports_color_range(plane, color_range));
return plane_add_prop(req, plane, WDRM_PLANE_COLOR_RANGE, color_range);
}
static int
drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req,
@ -1335,22 +1238,14 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
current_mode->blob_id);
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1);
if (output->base.from_blend_to_output_by_backend &&
output->blend_to_output_xform)
ret |= crtc_add_prop(req, crtc, WDRM_CRTC_GAMMA_LUT,
output->blend_to_output_xform->blob_id);
else
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_GAMMA_LUT, 0);
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_DEGAMMA_LUT, 0);
if (!output->deprecated_gamma_is_set) {
ret |= crtc_add_prop_zero_ok(req, crtc,
WDRM_CRTC_GAMMA_LUT, 0);
ret |= crtc_add_prop_zero_ok(req, crtc,
WDRM_CRTC_DEGAMMA_LUT, 0);
}
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_CTM, 0);
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_VRR_ENABLED,
wdrm_vrr_enabled_from_output(output));
ret |= crtc_add_prop_zero_ok(req, crtc,
WDRM_CRTC_BACKGROUND_COLOR,
crtc->background_color);
ret |= crtc_add_prop_zero_ok(req, crtc, WDRM_CRTC_VRR_ENABLED, 0);
/* No need for the DPMS property, since it is implicit in
* routing and CRTC activity. */
@ -1370,11 +1265,6 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
ret |= connector_add_prop(req, &wb_state->wb->connector,
WDRM_CONNECTOR_WRITEBACK_OUT_FENCE_PTR,
(uintptr_t)&wb_state->out_fence_fd);
drm_debug(b, "\t\t\t[CONN:%lu] FORMAT: %s\n",
(unsigned long) wb_state->wb->connector.connector_id,
wb_state->fb->format->drm_format_name);
if (!(*flags & DRM_MODE_ATOMIC_TEST_ONLY))
wb_state->state = DRM_OUTPUT_WB_SCREENSHOT_CHECK_FENCE;
}
@ -1392,13 +1282,11 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
wl_list_for_each(head, &output->base.head_list, base.output_link)
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
}
wl_list_for_each_safe(head, tmp, &output->disable_head, disable_head_link) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
*flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
if (!(*flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
wl_list_for_each_safe(head, tmp, &output->disable_head,
disable_head_link) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
wl_list_remove(&head->disable_head_link);
wl_list_init(&head->disable_head_link);
}
@ -1485,13 +1373,6 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
WDRM_PLANE_ALPHA,
plane_state->alpha);
ret |= drm_plane_set_color_encoding(plane,
plane_state->color_encoding,
req);
ret |= drm_plane_set_color_range(plane,
plane_state->color_range, req);
if (ret != 0) {
weston_log("couldn't set plane state\n");
return ret;
@ -1545,10 +1426,12 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
break;
}
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
if (device->state_invalid) {
struct weston_head *head_base;
struct drm_head *head;
struct drm_crtc *crtc;
uint32_t connector_id;
int err;
drm_debug(b, "\t\t[atomic] previous state invalid; "
"starting with fresh state\n");
@ -1558,6 +1441,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
* disable all the CRTCs and connectors we aren't using. */
wl_list_for_each(head_base,
&b->compositor->head_list, compositor_link) {
struct drm_property_info *info;
head = to_drm_head(head_base);
if (!head)
continue;
@ -1565,13 +1449,22 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
if (weston_head_is_enabled(head_base))
continue;
connector_id = head->connector.connector_id;
if (head->connector.device != device)
continue;
drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
head_base->name);
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0);
info = &head->connector.props[WDRM_CONNECTOR_CRTC_ID];
err = drmModeAtomicAddProperty(req, connector_id,
info->prop_id, 0);
drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> 0\n",
(unsigned long) connector_id,
(unsigned long) info->prop_id,
info->name);
if (err <= 0)
ret = -1;
}
wl_list_for_each(crtc, &device->crtc_list, link) {
@ -1587,7 +1480,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
* off, as the kernel will refuse to generate an event
* for an off->off state and fail the commit.
*/
props = drmModeObjectGetProperties(device->kms_device->fd,
props = drmModeObjectGetProperties(device->drm.fd,
crtc->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!props) {
@ -1631,15 +1524,12 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
if (ret != 0) {
weston_log("atomic: couldn't compile atomic state\n");
if (mode == DRM_STATE_TEST_ONLY)
goto out_test_only;
else
goto out;
goto out;
}
if (may_tear)
tear_flag = DRM_MODE_PAGE_FLIP_ASYNC;
ret = drmModeAtomicCommit(device->kms_device->fd, req, flags | tear_flag,
ret = drmModeAtomicCommit(device->drm.fd, req, flags | tear_flag,
device);
drm_debug(b, "[atomic] drmModeAtomicCommit\n");
if (ret != 0 && may_tear && mode == DRM_STATE_TEST_ONLY) {
@ -1648,12 +1538,16 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
* out of our state in case we were testing for a later commit.
*/
drm_debug(b, "[atomic] drmModeAtomicCommit (no tear fallback)\n");
ret = drmModeAtomicCommit(device->kms_device->fd, req, flags, device);
ret = drmModeAtomicCommit(device->drm.fd, req, flags, device);
if (ret == 0)
drm_pending_state_clear_tearing(pending_state);
}
if (mode == DRM_STATE_TEST_ONLY)
goto out_test_only;
/* Test commits do not take ownership of the state; return
* without freeing here. */
if (mode == DRM_STATE_TEST_ONLY) {
drmModeAtomicFree(req);
return ret;
}
if (ret != 0) {
wl_list_for_each(output_state, &pending_state->output_list, link)
@ -1669,20 +1563,13 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
link)
drm_output_assign_state(output_state, mode);
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
device->recovery_status = DRM_RECOVERY_APPLIED;
if (mode == DRM_STATE_APPLY_SYNC)
drm_device_recovery_complete(device);
}
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
out:
drm_pending_state_free(pending_state);
/* Test commits do not take ownership of the state; return
* without freeing here. */
out_test_only:
drmModeAtomicFree(req);
drm_pending_state_free(pending_state);
return ret;
}
@ -1701,8 +1588,8 @@ out_test_only:
* claim it will work.
*
* Unlike drm_pending_state_apply() and drm_pending_state_apply_sync(), this
* function does _not_ take ownership of pending_state, nor does it complete
* a state recovery.
* function does _not_ take ownership of pending_state, nor does it clear
* state_invalid.
*/
int
drm_pending_state_test(struct drm_pending_state *pending_state)
@ -1723,8 +1610,7 @@ drm_pending_state_test(struct drm_pending_state *pending_state)
* applying KMS state to a device. Updates the state for all outputs in the
* pending_state, as well as disabling any unclaimed outputs.
*
* Unconditionally takes ownership of pending_state, and moves along any
* scheduled state recovery.
* Unconditionally takes ownership of pending_state, and clears state_invalid.
*/
int
drm_pending_state_apply(struct drm_pending_state *pending_state)
@ -1733,7 +1619,6 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
struct drm_backend *b = device->backend;
struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc;
bool failed = false;
if (wl_list_empty(&pending_state->output_list)) {
drm_pending_state_free(pending_state);
@ -1744,7 +1629,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_ASYNC);
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables
@ -1753,7 +1638,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output)
continue;
drmModeSetCrtc(device->kms_device->fd, crtc->crtc_id, 0, 0, 0,
drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
}
}
@ -1776,23 +1661,15 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
weston_output_repaint_failed(&output->base);
drm_output_state_free(output->state_cur);
output->state_cur = drm_output_state_alloc(output);
failed = true;
device->state_invalid = true;
if (b->compositor->renderer->type == WESTON_RENDERER_GL) {
drm_output_fini_egl(output);
drm_output_init_egl(output, b);
} else if (b->compositor->renderer->type == WESTON_RENDERER_VULKAN) {
drm_output_fini_vulkan(output);
drm_output_init_vulkan(output, b);
}
}
}
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
device->recovery_status = DRM_RECOVERY_APPLIED;
drm_device_recovery_complete(device);
}
if (failed)
drm_device_recovery_required(device);
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
@ -1806,8 +1683,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
* disable outputs. Does so synchronously: the request is guaranteed to have
* completed on return, and the output will not be touched afterwards.
*
* Unconditionally takes ownership of pending_state, and moves along any
* scheduled state recovery.
* Unconditionally takes ownership of pending_state, and clears state_invalid.
*/
int
drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
@ -1815,13 +1691,12 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
struct drm_device *device = pending_state->device;
struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc;
bool failed;
if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_SYNC);
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables
@ -1830,7 +1705,7 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output)
continue;
drmModeSetCrtc(device->kms_device->fd, crtc->crtc_id, 0, 0, 0,
drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL);
}
}
@ -1844,16 +1719,10 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
if (ret != 0) {
weston_log("Couldn't apply state for output %s\n",
output_state->output->base.name);
failed = true;
}
}
if (device->recovery_status == DRM_RECOVERY_SCHEDULED) {
device->recovery_status = DRM_RECOVERY_APPLIED;
drm_device_recovery_complete(device);
}
if (failed)
drm_device_recovery_required(device);
device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list));
@ -1889,7 +1758,6 @@ page_flip_handler(int fd, unsigned int frame,
assert(output->page_flip_pending);
output->page_flip_pending = false;
output->page_flips_counted++;
drm_output_update_complete(output, flags, sec, usec);
}
@ -1903,8 +1771,6 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
struct drm_crtc *crtc;
struct drm_output *output;
struct timespec now;
float page_flips_per_timer_interval;
uint32_t frame_counter_interval;
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
@ -1920,14 +1786,6 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
if (!output || !output->base.enabled)
return;
output->page_flips_counted++;
/* store them temporarily as drm_output_update_complete might destroy
* the output */
page_flips_per_timer_interval = output->page_flips_per_timer_interval;
frame_counter_interval =
output->backend->perf_page_flips_stats.frame_counter_interval;
drm_output_update_msc(output, frame);
if (output->state_cur->tear) {
@ -1939,9 +1797,6 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
weston_compositor_read_presentation_clock(ec, &now);
sec = now.tv_sec;
usec = now.tv_nsec / 1000;
/* Tearing does not have vsync nor hardware time. */
flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
}
drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
@ -1951,26 +1806,6 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
drm_output_update_complete(output, flags, sec, usec);
drm_debug(b, "[atomic][CRTC:%u] flip processing completed\n", crtc_id);
drm_debug(b, "[atomic][CRTC:%u] %.2f page flips computed in %d seconds\n",
crtc_id, page_flips_per_timer_interval, frame_counter_interval);
assert(device->atomic_completes_pending > 0);
device->atomic_completes_pending--;
/* We've just completed a recovery operation. */
if (!device->atomic_completes_pending &&
device->recovery_status == DRM_RECOVERY_APPLIED)
drm_device_recovery_complete(device);
/* We're in an invalid state but were waiting for outstanding flips
* to complete before we could begin the recovery process
*/
if (!device->atomic_completes_pending &&
device->recovery_status != DRM_RECOVERY_UNNECESSARY) {
assert(device->recovery_status == DRM_RECOVERY_WAIT_FOR_IDLE);
drm_device_recovery_schedule(device);
}
}
int
@ -1988,7 +1823,7 @@ on_drm_input(int fd, uint32_t mask, void *data)
* uses the KMS objects (CRTC, planes, etc) in use by the writeback. */
wl_list_for_each(crtc, &device->crtc_list, link) {
state = crtc->output ? crtc->output->wb_state : NULL;
if (state && !drm_writeback_try_complete(state))
if (state && drm_writeback_should_wait_completion(state))
wait_wb_completion = true;
}
if (wait_wb_completion)
@ -2012,9 +1847,9 @@ init_kms_caps(struct drm_device *device)
uint64_t cap;
int ret;
weston_log("using %s\n", device->kms_device->filename);
weston_log("using %s\n", device->drm.filename);
ret = drmGetCap(device->kms_device->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
if (ret != 0 || cap != 1) {
weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
return -1;
@ -2022,64 +1857,45 @@ init_kms_caps(struct drm_device *device)
b->base.supported_presentation_clocks = 1 << CLOCK_MONOTONIC;
ret = drmGetCap(device->kms_device->fd, DRM_CAP_CURSOR_WIDTH, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
if (ret == 0)
device->cursor_width = cap;
else
device->cursor_width = 64;
ret = drmGetCap(device->kms_device->fd, DRM_CAP_CURSOR_HEIGHT, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
if (ret == 0)
device->cursor_height = cap;
else
device->cursor_height = 64;
ret = drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret) {
weston_log("Error: drm card doesn't support universal planes!\n");
return -1;
}
ret = drmGetCap(device->kms_device->fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
if (ret != 0)
cap = 0;
/* Between Linux 3.16 and Linux 4.1 there was a bug that
* could result in a stale timestamp being returned.
*
* The workaround for this has can make it impossible
* to display images with precise timing.
*
* It's somewhat difficult to determine whether we need
* that workaround or not, but we know that the
* DRM_CAP_CRTC_IN_VBLANK_EVENT drm cap exists in 4.12
* and on. We'll use its presence to gate the workaround.
*/
if (!cap) {
weston_log("DRM Warning: stale timestamp workaround for Kernel older than 4.12\n");
device->backend->stale_timestamp_workaround = true;
} else {
device->backend->stale_timestamp_workaround = false;
}
if (!getenv("WESTON_DISABLE_ATOMIC")) {
ret = drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_ATOMIC, 1);
ret = drmGetCap(device->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
if (ret != 0)
cap = 0;
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
device->atomic_modeset = ((ret == 0) && (cap == 1));
}
weston_log("DRM: %s atomic modesetting\n",
device->atomic_modeset ? "supports" : "does not support");
if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
ret = drmGetCap(device->kms_device->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
if (ret == 0)
device->fb_modifiers = cap;
}
weston_log("DRM: %s GBM modifiers\n",
device->fb_modifiers ? "supports" : "does not support");
drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
ret = drmGetCap(device->kms_device->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap);
ret = drmGetCap(device->drm.fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap);
if (ret == 0)
device->tearing_supported = cap;
weston_log("DRM: %s Atomic async page flip\n",
@ -2094,9 +1910,9 @@ init_kms_caps(struct drm_device *device)
* enabled.
*/
if (!device->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
device->disable_client_buffer_scanout = true;
device->sprites_are_broken = true;
ret = drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
device->aspect_ratio_supported = (ret == 0);
weston_log("DRM: %s picture aspect ratio\n",
device->aspect_ratio_supported ? "supports" : "does not support");

View file

@ -64,7 +64,7 @@ static long backlight_get(struct backlight *backlight, char *node)
goto out;
}
ret = read(fd, buffer, sizeof(buffer));
ret = read(fd, &buffer, sizeof(buffer));
if (ret < 1) {
ret = -1;
goto out;
@ -119,6 +119,12 @@ long backlight_set_brightness(struct backlight *backlight, long brightness)
goto out;
}
ret = read(fd, &buffer, sizeof(buffer));
if (ret < 1) {
ret = -1;
goto out;
}
str_printf(&buffer, "%ld", brightness);
if (!buffer) {
ret = -1;
@ -234,7 +240,7 @@ struct backlight *backlight_init(struct udev_device *drm_device,
if (fd < 0)
goto out;
ret = read (fd, buffer, sizeof(buffer));
ret = read (fd, &buffer, sizeof(buffer));
close (fd);
if (ret < 1)

View file

@ -2,6 +2,20 @@ if not get_option('backend-drm')
subdir_done()
endif
dep_libdisplay_info = dependency(
'libdisplay-info',
version: ['>= 0.1.1', '< 0.3.0'],
fallback: ['display-info', 'di_dep'],
default_options: [
'werror=false',
],
required: true,
not_found_message: 'Required by DRM-backend.',
)
if dep_libdisplay_info.version().version_compare('>= 0.2.0')
config_h.set('HAVE_LIBDISPLAY_INFO_HIGH_LEVEL_COLORIMETRY', '1')
endif
lib_backlight = static_library(
'backlight',
'libbacklight.c',
@ -34,7 +48,6 @@ srcs_drm = [
deps_drm = [
dep_egl, # optional
dep_vulkan, # optional
dep_libm,
dep_libdl,
dep_libshared,
@ -56,16 +69,21 @@ if get_option('renderer-gl')
config_h.set('BUILD_DRM_GBM', '1')
endif
if get_option('renderer-vulkan')
if not dep_gbm.found()
error('drm-backend with Vulkan renderer requires gbm which was not found. Or, you can use \'-Drenderer-vulkan=false\'.')
endif
deps_drm += dep_gbm
srcs_drm += 'drm-gbm.c'
config_h.set('BUILD_DRM_GBM', '1')
if get_option('backend-drm-screencast-vaapi')
foreach name : [ 'libva', 'libva-drm' ]
d = dependency(name, version: '>= 0.34.0', required: false)
if not d.found()
error('VA-API recorder requires @0@ >= 0.34.0 which was not found. Or, you can use \'-Dbackend-drm-screencast-vaapi=false\'.'.format(name))
endif
deps_drm += d
endforeach
srcs_drm += 'vaapi-recorder.c'
deps_drm += dependency('threads')
config_h.set('BUILD_VAAPI_RECORDER', '1')
endif
if get_option('deprecated-remoting') or get_option('deprecated-pipewire')
if get_option('remoting') or get_option('pipewire')
if not get_option('renderer-gl')
error('DRM virtual requires renderer-gl.')
endif

View file

@ -31,8 +31,6 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libdisplay-info/cta.h>
#include <libdisplay-info/edid.h>
#include <libdisplay-info/info.h>
#include "drm-internal.h"
@ -53,10 +51,6 @@ struct drm_head_info {
* enum weston_colorimetry_mode bits.
*/
uint32_t colorimetry_mask;
/* The monitor supported color foramts, combination of
* enum_weston_color_format bits. */
uint32_t color_format_mask;
};
static void
@ -139,7 +133,7 @@ drm_mode_ensure_blob(struct drm_device *device, struct drm_mode *mode)
if (mode->blob_id)
return 0;
ret = drmModeCreatePropertyBlob(device->kms_device->fd,
ret = drmModeCreatePropertyBlob(device->drm.fd,
&mode->mode_info,
sizeof(mode->mode_info),
&mode->blob_id);
@ -233,6 +227,8 @@ parse_modeline(const char *s, drmModeModeInfo *mode)
return 0;
}
#ifdef HAVE_LIBDISPLAY_INFO_HIGH_LEVEL_COLORIMETRY
static uint32_t
get_eotf_mask(const struct di_info *info)
{
@ -288,76 +284,22 @@ get_colorimetry_mask(const struct di_info *info)
return mask;
}
static bool
has_yuv420_cap_map(const struct di_edid_cta *cta)
#else /* HAVE_LIBDISPLAY_INFO_HIGH_LEVEL_COLORIMETRY */
static uint32_t
get_eotf_mask(const struct di_info *info)
{
const struct di_cta_data_block *const *data_blocks;
enum di_cta_data_block_tag db_tag;
int i;
data_blocks = di_edid_cta_get_data_blocks(cta);
for (i = 0; data_blocks[i] != NULL; i++) {
db_tag = di_cta_data_block_get_tag(data_blocks[i]);
if (db_tag == DI_CTA_DATA_BLOCK_YCBCR420_CAP_MAP)
return true;
}
return false;
return WESTON_EOTF_MODE_SDR;
}
static uint32_t
get_color_format_mask(const struct di_info *info)
get_colorimetry_mask(const struct di_info *info)
{
const struct di_edid *edid = di_info_get_edid(info);
const struct di_edid_color_encoding_formats *fmts =
di_edid_get_color_encoding_formats(edid);
const struct di_edid_ext *const *exts = di_edid_get_extensions(edid);
uint32_t mask = WESTON_COLOR_FORMAT_AUTO;
int i;
if (fmts) {
if (fmts->rgb444)
mask |= WESTON_COLOR_FORMAT_RGB;
if (fmts->ycrcb444)
mask |= WESTON_COLOR_FORMAT_YUV444;
if (fmts->ycrcb422)
mask |= WESTON_COLOR_FORMAT_YUV422;
}
for (i = 0; exts[i] ; i++) {
const struct di_edid_cta *cta;
const struct di_edid_cta_flags *cta_flags;
switch (di_edid_ext_get_tag(exts[i])) {
case DI_EDID_EXT_CEA:
cta = di_edid_ext_get_cta(exts[i]);
cta_flags = di_edid_cta_get_flags(cta);
mask |= WESTON_COLOR_FORMAT_RGB;
if (cta_flags->ycc444)
mask |= WESTON_COLOR_FORMAT_YUV444;
if (cta_flags->ycc422)
mask |= WESTON_COLOR_FORMAT_YUV422;
/* FIXME: YUV420 detection is really complicated,
* do it properly at some point...
*/
if (has_yuv420_cap_map(cta))
mask |= WESTON_COLOR_FORMAT_YUV420;
break;
default:
break;
}
}
return mask;
return WESTON_COLORIMETRY_MODE_DEFAULT;
}
#endif /* HAVE_LIBDISPLAY_INFO_HIGH_LEVEL_COLORIMETRY */
static struct di_info *
drm_head_info_from_edid(struct drm_head_info *dhi,
const uint8_t *data,
@ -383,7 +325,6 @@ drm_head_info_from_edid(struct drm_head_info *dhi,
dhi->serial_number = di_info_get_serial(di_ctx);
dhi->eotf_mask = get_eotf_mask(di_ctx);
dhi->colorimetry_mask = get_colorimetry_mask(di_ctx);
dhi->color_format_mask = get_color_format_mask(di_ctx);
return di_ctx;
}
@ -428,7 +369,7 @@ drm_head_maybe_update_display_data(struct drm_head *head,
&head->connector.props[WDRM_CONNECTOR_EDID],
props, 0);
if (blob_id)
edid_blob = drmModeGetPropertyBlob(device->kms_device->fd, blob_id);
edid_blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (edid_blob && edid_blob->length > 0) {
if (!head->display_data ||
@ -553,7 +494,7 @@ static void
drm_output_destroy_mode(struct drm_device *device, struct drm_mode *mode)
{
if (mode->blob_id)
drmModeDestroyPropertyBlob(device->kms_device->fd, mode->blob_id);
drmModeDestroyPropertyBlob(device->drm.fd, mode->blob_id);
wl_list_remove(&mode->base.link);
free(mode);
}
@ -656,46 +597,26 @@ void
update_head_from_connector(struct drm_head *head)
{
struct drm_connector *connector = &head->connector;
struct drm_backend *b = head->connector.device->backend;
drmModeObjectProperties *props = connector->props_drm;
drmModeConnector *conn = connector->conn;
int vrr_capable;
uint32_t vrr_mode_mask = 0;
uint32_t conn_id = head->connector.connector_id;
bool ret;
ret = weston_head_set_non_desktop(&head->base,
weston_head_set_non_desktop(&head->base,
check_non_desktop(connector, props));
if (ret)
drm_debug(b, "\t[CONN:%d] non-desktop property changed\n", conn_id);
ret = weston_head_set_subpixel(&head->base,
weston_head_set_subpixel(&head->base,
drm_subpixel_to_wayland(conn->subpixel));
if (ret)
drm_debug(b, "\t[CONN:%d] subpixel property changed\n", conn_id);
ret = weston_head_set_physical_size(&head->base, conn->mmWidth, conn->mmHeight);
if (ret)
drm_debug(b, "\t[CONN:%d] physical size changed\n", conn_id);
weston_head_set_physical_size(&head->base, conn->mmWidth, conn->mmHeight);
ret = weston_head_set_transform(&head->base,
weston_head_set_transform(&head->base,
get_panel_orientation(connector, props));
if (ret)
drm_debug(b, "\t[CONN:%d] transform property changed\n", conn_id);
/* Unknown connection status is assumed disconnected. */
ret = weston_head_set_connection_status(&head->base,
weston_head_set_connection_status(&head->base,
conn->connection == DRM_MODE_CONNECTED);
if (ret)
drm_debug(b, "\t[CONN:%d] connection status changed\n", conn_id);
/* If EDID did not change, skip everything about it */
if (!drm_head_maybe_update_display_data(head, props)) {
if (!ret)
drm_debug(b, "\t[CONN:%d] Hot-plug event received "
"but no connector changes detected\n", conn_id);
if (!drm_head_maybe_update_display_data(head, props))
return;
}
struct drm_head_info dhi;
@ -709,18 +630,11 @@ update_head_from_connector(struct drm_head *head)
dhi.serial_number);
prune_eotf_modes_by_kms_support(head, &dhi.eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, dhi.eotf_mask);
dhi.colorimetry_mask &= drm_head_get_kms_colorimetry_modes(head);
weston_head_set_supported_colorimetry_mask(&head->base, dhi.colorimetry_mask);
vrr_capable = drm_property_get_value(&head->connector.props[WDRM_CONNECTOR_VRR_CAPABLE],
head->connector.props_drm, 0);
if (vrr_capable)
vrr_mode_mask = WESTON_VRR_MODE_GAME;
weston_head_set_supported_vrr_modes_mask(&head->base, vrr_mode_mask);
drm_head_info_fini(&dhi);
}

View file

@ -33,9 +33,7 @@
#include <xf86drmMode.h>
#include "drm-internal.h"
#include "shared/weston-assert.h"
#include "shared/weston-drm-fourcc.h"
#include "shared/xalloc.h"
/**
* Allocate a new, empty, plane state.
@ -49,7 +47,6 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
assert(state);
state->output_state = state_output;
state->plane = plane;
state->handle = NULL;
state->in_fence_fd = -1;
state->rotation = drm_rotation_from_output_transform(plane,
WL_OUTPUT_TRANSFORM_NORMAL);
@ -58,9 +55,6 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
state->alpha = (plane->alpha_max < DRM_PLANE_ALPHA_OPAQUE) ?
plane->alpha_max : DRM_PLANE_ALPHA_OPAQUE;
state->color_encoding = WDRM_PLANE_COLOR_ENCODING__COUNT;
state->color_range = WDRM_PLANE_COLOR_RANGE__COUNT;
/* Here we only add the plane state to the desired link, and not
* set the member. Having an output pointer set means that the
* plane will be displayed on the output; this won't be the case
@ -102,7 +96,7 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
if (state->damage_blob_id != 0) {
device = state->plane->device;
drmModeDestroyPropertyBlob(device->kms_device->fd,
drmModeDestroyPropertyBlob(device->drm.fd,
state->damage_blob_id);
state->damage_blob_id = 0;
}
@ -216,16 +210,16 @@ drm_plane_state_put_back(struct drm_plane_state *state)
}
/**
* Given a weston_paint_node, fill the drm_plane_state's co-ordinates to
* display on a given plane.
* Given a weston_view, fill the drm_plane_state's co-ordinates to display on
* a given plane.
*/
void
bool
drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
struct weston_paint_node *pnode,
struct weston_paint_node *node,
uint64_t zpos)
{
struct drm_output *output = state->handle->output;
struct weston_view *ev = pnode->view;
struct drm_output *output = state->output;
struct weston_view *ev = node->view;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
pixman_region32_t dest_rect;
pixman_box32_t *box;
@ -234,16 +228,16 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
uint16_t min_alpha = state->plane->alpha_min;
uint16_t max_alpha = state->plane->alpha_max;
/* The caller has already checked supported transforms when creating
* a list of candidate planes, so we should only ever get here with
* a supported transform.
*/
assert(drm_paint_node_transform_supported(pnode, state->plane));
if (!drm_paint_node_transform_supported(node, state->plane))
return false;
assert(pnode->valid_transform);
state->rotation = drm_rotation_from_output_transform(state->plane, pnode->transform);
assert(node->valid_transform);
state->rotation = drm_rotation_from_output_transform(state->plane, node->transform);
/* Update the base weston_plane co-ordinates. */
box = pixman_region32_extents(&ev->transform.boundingbox);
state->plane->base.x = box->x1;
state->plane->base.y = box->y1;
/* First calculate the destination co-ordinates by taking the
* area of the view which is visible on this output, performing any
@ -263,10 +257,10 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
/* Now calculate the source rectangle, by transforming the destination
* rectangle by the output to buffer matrix. */
corners[0] = weston_matrix_transform_coord(
&pnode->output_to_buffer_matrix,
&node->output_to_buffer_matrix,
weston_coord(box->x1, box->y1));
corners[1] = weston_matrix_transform_coord(
&pnode->output_to_buffer_matrix,
&node->output_to_buffer_matrix,
weston_coord(box->x2, box->y2));
sxf1 = corners[0].x;
syf1 = corners[0].y;
@ -315,10 +309,11 @@ drm_plane_state_coords_for_paint_node(struct drm_plane_state *state,
/* The alpha of the view is normalized to alpha value range
* [min_alpha, max_alpha] that got from drm. The alpha value would
* never exceed max_alpha if pnode->view_alpha <= 1.0.
* never exceed max_alpha if ev->alpha <= 1.0.
*/
state->alpha = min_alpha +
(uint16_t)round((max_alpha - min_alpha) * pnode->view_alpha);
state->alpha = min_alpha + (uint16_t)round((max_alpha - min_alpha) * ev->alpha);
return true;
}
/**
@ -403,12 +398,10 @@ drm_output_state_duplicate(struct drm_output_state *src,
struct drm_pending_state *pending_state,
enum drm_output_state_duplicate_mode plane_mode)
{
struct weston_compositor *compositor = src->output->base.compositor;
struct drm_output_state *dst = xmalloc(sizeof(*dst));
struct drm_output_state *dst = malloc(sizeof(*dst));
struct drm_plane_state *ps;
/* The reuse bit isn't stored in the state */
weston_assert_false(compositor, src->mode & DRM_OUTPUT_PROPOSE_STATE_REUSE);
assert(dst);
/* Copy the whole structure, then individually modify the
* pending_state, as well as the list link into our pending
@ -426,7 +419,7 @@ drm_output_state_duplicate(struct drm_output_state *src,
wl_list_for_each(ps, &src->plane_list, link) {
/* Don't carry planes which are now disabled; these should be
* free for other outputs to reuse. */
if (!ps->handle)
if (!ps->output)
continue;
if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more