Compare commits

...

614 Commits

Author SHA1 Message Date
mainnika 934dd7b904 Fix merge glitches 2024-07-20 21:48:33 +02:00
mainnika be9f5bd993 Revert "backend-wayland: Stop supporting wl_shell"
This reverts commit 7cae2a1fb0.
2024-07-20 21:37:58 +02:00
mainnika 419d6a9cf5 Revert "backend-wayland: restructure wayland_output_resize_surface()"
This reverts commit 9e1c96bce7.
2024-07-20 21:36:17 +02:00
mainnika 996dd5caa5 Revert "backend-wayland: fix pixman buffer size"
This reverts commit d4eafbaa98.
2024-07-20 21:35:30 +02:00
mainnika 0cc7369023 Merge tag '11.0.3' into dev
11.0.3
2024-07-20 21:35:16 +02:00
Marius Vlad 742ad74bc0 build: bump to version 11.0.3 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2023-08-02 18:48:58 +03:00
Marius Vlad 263702cf7d backend-drm/meson.build: Require at least mesa 21.1.1
We seem to be using at least mesa 21.1.1 since Weston 10, but we never
explicitly asked for it.

Fixes: #790

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 0713ea7ee6216e45ebdb67cef63bcef7961d1d4e)
2023-08-02 15:53:38 +03:00
Liu, Kai1 38eb0a96e0 xwm: WM_TRANSIENT_FOR should not point to override-redirect window
The override-redirect window will not be assigned a shell_surface
object. If it is used as a parent window, it will cause a crash
when calling the set_parent function.

The EWMH specification does not describe the behavior of an
override-redirect window as a parent window, so we should ignore
this case.

Signed-off-by: Liu, Kai1 <kai1.liu@intel.com>
(cherry picked from commit b468687dd2663240d1613bf4a917f049ef09af46)
2023-08-02 14:57:55 +03:00
Michael Tretter a5d52075a0 backend-drm: schedule connector disable for detached head
Currently, if a head is detached, the entire state of the device is invalidated
to make sure that the connector is disabled on the next atomic commit. Side
effect of the invalid state is that all planes are disabled on the next commit.
This includes planes that are used with a different head that is not part of the
next atomic commit. Disabling the planes of unrelated outputs causes a blanking
of these outputs until output is repainted and the plane is reenabled.

Store the detached heads in a list on the output and disable the connectors for
all heads in this list in the next atomic commit.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
(cherry picked from commit bcacd9ec5a924317416eabb65a6cd6767d5bfb94)
2023-07-13 11:02:22 +08:00
Marius Vlad 78852bd350 build: bump to version 11.0.2 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2023-05-17 12:19:47 +03:00
Sergio Gómez a627a4be50 libweston/input: Fix assert for valid confine region
We need only check that the region is not empty. If either the input region or
the constraint region have degenerate extents, the intersection from the
previous instruction will set confine_region->data to pixman_region_empty_data.

Fixes: b6423e59

Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
(cherry picked from commit 1ed88f60c0125988cf1d952f0dabf568bfd82a13)
2023-05-16 10:55:15 +03:00
Sergio Gómez 072c56723c libweston: Add assert for valid confine region in maybe_warp_confined_pointer()
Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
(cherry picked from commit b6423e59d9116d140e33e925d6dd9bf8324188a7)
2023-05-16 10:54:29 +03:00
Sergio Gómez 21e46364c0 libweston: Add view unmap listener to pointer constraints
Since the logic of pointer constraints assumes a valid view throughout, add a
signal to disable constraints when its current view is unmapped by Weston.

The assumption that a previously unmapped view is valid already leads to the
constraints code crashing. This can happen when attaching a NULL buffer to the
surface and commiting, which effectively unmaps the view with the side effect of
clearing the surface's input region, which is then assumed valid inside
maybe_warp_confined_pointer().

Fixes: #721

Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
(cherry picked from commit e3079393c400e3dc6498234d1d092f3072fa8b44)
2023-05-16 10:54:29 +03:00
Sergio Gómez 0bd68d9ad6 libweston/input: Remove redundant surface destroy listener in constraints
Currently, the surface destroy listener in pointer constraints is redundant,
since surface destruction already handles pointer constraints destruction (see
libweston/compositor.c:weston_surface_unref()).

Signed-off-by: Sergio Gómez <sergio.g.delreal@gmail.com>
(cherry picked from commit 64da736d37a7df8b3bd6fd43746ac513bae72748)
2023-05-16 10:54:29 +03:00
Michael Olbrich ff13a90eea desktop-shell: avoid crashes when a surface disappears during resize
The desktop_surface object is destroyed first so it can happen that the shsurf
still exists but desktop_surface is already NULL. So expand the check to make
sure the desktop_surface is still available in the resize callbacks.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
(cherry picked from commit 06365e602bd7599760a9a1414d12d6c26ca9c445)
2023-05-16 10:52:31 +03:00
Michael Olbrich 5ad870f505 libweston: clear parent_view when the parent view is destroyed
When a view is destroyed then the views of subsurfaces remain until the view
list is rebuilt for the next repaint.
During that time view->parent_view contains an invalid pointer and weston will
crash when it tries to access the view.

This happens for a surface with subsurfaces with views on two different outputs
with the ivi-shell:

When the surface is destroyed then the destroy handler of the ivi-shell
(shell_handle_surface_destroy()) may be called first. It will (indirectly)
destroy the view of the main surface with weston_view_destroy().
Next the surface destroy handler of the subsurfaces
(subsurface_handle_parent_destroy() is called. It will unmap the first view of
the subsurface. Here weston_surface_assign_output() is called which tries to
find the output of the second view and accesses the now invalid
view->parent_view in the process.

There are probably other ways to trigger similar crashes.

To avoid this, clear view->parent_view when the parent view is destroyed.

Fixes 0669d4de4f ("libweston: Skip views without a layer assignment in
      output_mask calculations")

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
(cherry picked from commit 39796f88e6ed4a33a42c74b743e999294b3e4651)
2023-05-16 10:51:40 +03:00
Alexandros Frantzis 2d66d01cf5 xwayland: Handle shell hint for client to choose dimensions
A config event with width == 0 or height == 0 from the shell is a hint
to the client to choose its own dimensions. Since X11 clients don't
support such hints we make a best guess by trying to use the last saved
dimensions or, as a fallback, the current dimensions.

This hint is mainly used by libweston/desktop shells when transitioning
to a normal state from maximized, fullscreen or after a resize [1].
Without support for this hint the aforementioned transition causes
xwayland surfaces to be configured to a 1x1 size.

To be able to use the last saved dimensions with xwayland surface, the
shell needs to first set the maximized/fullscreen state and only then
set the new size, which is currently the case for desktop-shell.
Otherwise, if the new size is set first, then the last saved dimensions
will be set to the fullscreen/maximized values and won't be useful when
restoring to a normal window size.

[1] Recently we've introduced ba82af938a87ff088b4aacff3b8ac1b6bb461be2
"desktop-shell: do not forget to reset pending config size after
resizes". As we were not handling the 0x0 size hint, resizing X
applications started to fail. This patch fixes that.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
Co-authored-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit 2acd2c74891cd0548c1ff410ccfe81952bed27b3)
2023-05-16 10:50:40 +03:00
Leandro Ribeiro d5a3ec5e58 desktop-shell: do not forget to reset pending config size after resizes
During interactive resizes, we progressively change the size of the
client surface and send config events with these sizes to the client.
After that, the toplevel->pending.size keeps the size of the last config
event that we've sent, i.e. the surface size after the resize is over.

Later, if the client spontaneously resize (by attaching a buffer with a
different size or setting the viewport destination, for instance), their
surface size will change, but toplevel->pending.size continues being
that old size from after the resize. If something happens and Weston
decides to send a config event, clients may re-allocate to that old
size, resulting in a sudden resize.

This does not happen when a client goes from fullscreen/maximized to
windowed mode because in such cases we are resetting
toplevel->pending.size to zero. So in the next config event that clients
receive they are allowed to attach buffers with the size that they
prefer.

So do the same after a resize: set the pending config size to zero.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
(cherry picked from commit ba82af938a87ff088b4aacff3b8ac1b6bb461be2)
2023-05-16 10:50:28 +03:00
Marius Vlad df70b81ed7 backend-drm: Do not overwrite plane's index when creating virtual plane
Starting with commit 4cde507be6 "backend-drm: fix plane sorting" the
plane list will have a descending order of the planes rather than ascending.

This reversed order had the side-effect of exposing the fact that we
don't set-up a plane index when creating the drm_plane using the DRM
virtual API. Without settting a plane index for that drm_plane we
effectively overwrite the plane index which has the 0 (zero) entry.

This wasn't an issue before commit 4cde507be6 "backend-drm: fix
plane sorting" as it seems we never picked up that plane index as
being a suitable one due to the fact that those were assigned to primary
planes, but after that commit, the cursor plane will be one getting
the 0 (zero) plane index.

Finally, this would trip over because we attempt to place a (cursor)
view on a primary plane (where it would've normally be a cursor
plane) and we end up with no framebuffer ref.

This is fixed trivially by assigning a plane index, different than the
ones already created by create_spirtes().

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 27ce9dadd8865b266f72f848b784d61aeaf8b228)
2023-05-16 10:49:17 +03:00
Marius Vlad 7047926834 pipewire-plugin: Check virtual outputs/remoting instance
Similarly to remoting plug-in in commit "Check virtual outputs/remoting
instance" this avoids touching the pipewire instance, and with it, the
pipewire output.

Includes a note to point up what should be done about by
checking out https://gitlab.freedesktop.org/wayland/weston/-/issues/591.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 6617deebec5586c4d8c61097b7e51dd53c4e4624)
2023-05-16 10:44:25 +03:00
Marius Vlad 0849a9b3c8 pipewire: Destroy the pipewire outputs at shutdown
Seems like we are missing destroying the pipewire outputs on the shutdown
path; this follow-ups with remoting plug-in as well.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 278fe4d7d47c7828d42047f4c910f1d815d32b80)
2023-05-16 10:44:25 +03:00
Marius Vlad 597437a096 pipewire: Fix memleak upon compositor shutdown
This happens when shutting the compositor, and follows-up with the
remoting plug-in.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit aa78da24659a97b82bcf1e28b985ea4f9fce4499)
2023-05-16 10:44:25 +03:00
Marius Vlad eaa777b914 pipewire: Follow-up with remoting pluging when releasing the head
Similarily to what the remoting plug-in does, explicitly call
weston_release_head() before removing the output list entry.

We do that to avoid lookup_pipewire_output() returning NULL and still
find out the pipewire_output.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 5db6d19e6bb4c72085104fcae9abf2f632d5f45a)
2023-05-16 10:44:25 +03:00
Marius Vlad 17f5a44f3b remoting-plugin: Check virtual outputs/remoting instance
With commit aab722bb, "backend-drm: prepare virtual output API for
heterogeneous outputs", we now call the virtual destroy function,
but when shutting the compositor we no longer have a remoting instance
available.

When searching out for a remoting output verify if the remoting instance is
still available before attempting to search for a remoting output.

Addresses the following crash at shutdown:

0x00007fd430a1d347 in lookup_remoted_output (output=0x557163d5dad0) at ../remoting/remoting-plugin.c:515
0x00007fd430a1d746 in remoting_output_destroy (output=0x557163d5dad0) at ../remoting/remoting-plugin.c:635
0x00007fd439e11ab9 in drm_virtual_output_destroy (base=0x557163d5dad0) at ../libweston/backend-drm/drm-virtual.c:265
0x00007fd43a8635d0 in weston_compositor_shutdown (ec=0x557163239530) at ../libweston/compositor.c:8271
0x00007fd439e029d4 in drm_destroy (backend=0x557163240ae0) at ../libweston/backend-drm/drm.c:2713
0x00007fd43a863e07 in weston_compositor_destroy (compositor=0x557163239530) at ../libweston/compositor.c:8626

Includes a note to point up what should be done about by
checking out https://gitlab.freedesktop.org/wayland/weston/-/issues/591.

Fixes aab722bb "backend-drm: prepare virtual output API for
heterogeneous outputs"

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit ca52c79c51088ca4c724b34e54c3bb97a9a51c67)
2023-05-16 10:44:25 +03:00
Marius Vlad 0ba5b694d3 remoting-plugin: Release and detach the head
This re-orders the disable/destroy shutdown sequence such that
lookup_remoted_output(), in remoting_output_disable(), would find a
remoting output.

Otherwise, without this, lookup_remoted_output() wouldn't find a
remoting output available when shutting down the compositor, ultimately
leading to a crash.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit c3270e887bc07bb9c7d0e58e25d25e3a65145d2e)
2023-05-16 10:44:25 +03:00
Marius Vlad 783b144f2e build: bump to version 11.0.1 for the point release
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-12-14 09:09:30 +02:00
Derek Foreman 995fb60fde xwm: Propagate selection ownership immediately
If we don't xcb_flush() when we set the selection owner, we end up with
a ridiculous corner case where we can run use a command line X client
like 'xclip -i -selection clipboard' to crash weston.

Start weston, ensure Xwayland is running (set a selection with xclip), set
the clipboard from a wayland client, then set the clipboard with xclip
again.

Since xclip doesn't do anything xwm notices except set the clipboard, it
won't provoke a flush on our selection ownership change. xclip will take
ownership, then we call xcb_convert_selection(), and THEN we flush, sending
out our pending ownership change and the xcb_convert_selection() request.

The ownership change takes place first, we attempt to get our own selection
and weston explodes in a mess.

Stop this from happening with a flush when changing selection ownership.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 11bcad116f5cc1eb76c2de83d8c39af0cdb71a81)
2022-12-12 13:18:46 +02:00
Derek Foreman f5fafa05fc xwm: Don't crash when setting selection with no seat
It's possible to set the clipboard with no seat present - one way is to
use the RDP backend and then run 'xclip -i -selection clipboard' locally
without making an RDP connection.

Check if seat is NULL to prevent this from crashing.

Fixes #698

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit bb993df236766178df95579217171bce5b166031)
2022-12-12 13:18:37 +02:00
Marius Vlad ac05950098 ivi-shell: Move out weston_desktop_shell at the end
To avoid the following UAF:

Invalid read of size 8
   at 0x4AE5EFF: weston_desktop_get_display (libweston-desktop.c:110)
   by 0x4AEB2C9: weston_desktop_xdg_surface_schedule_configure (xdg-shell.c:1160)
   by 0x4AEA77A: weston_desktop_xdg_toplevel_set_size (xdg-shell.c:711)
   by 0x4AE839D: weston_desktop_surface_set_size (surface.c:504)
   by 0x63F7D43: ivi_layout_surface_set_size (ivi-layout.c:1599)
   by 0x63F949F: transition_move_resize_view_destroy (ivi-layout-transition.c:311)
   by 0x63F9397: layout_transition_destroy (ivi-layout-transition.c:259)
   by 0x63F8E0B: ivi_layout_remove_all_surface_transitions (ivi-layout-transition.c:121)
   by 0x63F4BC1: ivi_layout_surface_destroy (ivi-layout.c:258)
   by 0x63F38AF: layout_surface_cleanup (ivi-shell.c:162)
   by 0x63F3D2D: shell_destroy (ivi-shell.c:359)
   by 0x4AF059A: weston_signal_emit_mutable (signal.c:62)
 Address 0x174202d0 is 0 bytes inside a block of size 152 free'd
   at 0x484617B: free (vg_replace_malloc.c:872)
   by 0x4AE5EDC: weston_desktop_destroy (libweston-desktop.c:97)
   by 0x63F3CF2: shell_destroy (ivi-shell.c:355)
   by 0x4AF059A: weston_signal_emit_mutable (signal.c:62)
   by 0x4ACBC2C: weston_compositor_destroy (compositor.c:8629)
   by 0x4864A4B: wet_main (main.c:3908)
   by 0x10915D: main (executable.c:33)

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit eb755cd81aad6f958629475a0429272aef3147b0)
2022-11-21 13:55:20 +02:00
Marius Vlad 097ed47292 hmi-controller: Add missing removal of destroy listener
Shutting down the compositor gives us:

Invalid write of size 8
   at 0x4B1AEDB: wl_list_remove (wayland-util.c:56)
   by 0x4AF05BF: weston_signal_emit_mutable (signal.c:66)
   by 0x4ACBC2C: weston_compositor_destroy (compositor.c:8629)
   by 0x4864A4B: wet_main (main.c:3908)
   by 0x10915D: main (executable.c:33)
 Address 0x17435f20 is 224 bytes inside a block of size 384 free'd
   at 0x484617B: free (vg_replace_malloc.c:872)
   by 0x17718C7E: hmi_controller_destroy (hmi-controller.c:761)
   by 0x4AF059A: weston_signal_emit_mutable (signal.c:62)
   by 0x4ACBC2C: weston_compositor_destroy (compositor.c:8629)
   by 0x4864A4B: wet_main (main.c:3908)
   by 0x10915D: main (executable.c:33)

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit cfbf2b0ab2ac7c50d8a1ea7645be3a9f3927825b)
2022-11-21 13:55:20 +02:00
Alexandros Frantzis ad7c5162bc kiosk-shell: Don't use a modifier for surface activation bindings
The mouse button and touch bindings to activate a surface shouldn't
use the binding modifier.

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

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
(cherry picked from commit 723709aa073fb740c3443fae8e370306d0738675)
2022-11-21 13:55:20 +02:00
Michael Tretter e7cf894fa2 ivi-shell: fix cleanup of desktop surfaces
The ivi-shell keeps track of its surfaces by adding them to the ivi_surface_list
to be able to remove them on shutdown. It also creates an ivi_layout_surface for
a desktop surface, but does not keep track of these surfaces.

During compositor shutdown, libweston prints the following message:

	BUG: finalizing a layer with views still on it.

Fix it by adding the created ivi_layout_surface to the ivi_surface_list to
remove the surfaces from the layer during shutdown.

Furthermore, remove the ivi_layout_surface from the desktop surface and free it
when the desktop surface is destroyed.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
(cherry picked from commit 266e2e1d4866ef7c39cff0b77f1e404d0dc96b55)

Resolved small conflict which arose due to commit cbf476f208fbdcefe.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-11-21 13:55:20 +02:00
Michael Tretter 72a6929467 ivi-shell: fix free in get_layers_under_surface
If a controller requests the layers under a surface that has no views attached,
Weston crashes since it tries to free the array that would be used to return the
found layers, but has not been allocated before.

Free the ppArray only if it was allocated in ivi_layout_get_layers_under_surface
before and no layers were found.

While at it, make it obvious that checking the length is an integer comparison
by comparing it to 0.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
(cherry picked from commit c56e69bc850540f243ebb87c5bcc38713ef1862a)
2022-11-21 13:55:20 +02:00
Alexandros Frantzis 7a8392d2fe kiosk-shell: Update view transform after activation.
The activation of a view implies, among other things, a change in the
associated view layer which is initially unset. In order for this change
to be reflected in the corresponding surface's output mask, and hence
allow surface damage to trigger output repaints, we need to update the
view transform.

Fixes #674

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
(cherry picked from commit 341d09d232d652c0001441cce55beb874fb3ba36)
2022-11-21 13:55:20 +02:00
Paul Kocialkowski 7678ec9209 screenshooter: Add SHM buffer destroy listener to avoid invalid memcpy
This adds a destroy listener on the SHM buffer provided by our client.
It will unregister the frame notify listener in case our buffer is
destroyed before the frame signal is emitted and thus avoid a memcpy
to invalid memory.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
(cherry picked from commit 0afd3428dc899c426d37650192f828541f70e390)
2022-11-21 13:55:20 +02:00
Derek Foreman 5517953ed0 xwm: Check size hints in weston_wm_window_is_positioned()
Currently we can't tell the difference between a window intentionally
created at 0,0 and a window that we can place anywhere.

Check the size hints to see if the flags indicating the placement
is intentional are present.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
(cherry picked from commit 1cb46994e3808e8000300ed9ae9dcaa0b76bff28)
2022-11-21 13:55:20 +02:00
Marius Vlad 00a78294b1 compositor/shared: Suppress write(2) warnings
Fixes the following warnings when building with _FORTIFY_SOURCE
and optimizations enabled:

../shared/xalloc.h:49:9: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
   49 |         write(STDERR_FILENO, oommsg, strlen(oommsg));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

or
../compositor/main.c:427:25: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
  427 |                         write(STDERR_FILENO, fail_seteuid,
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  428 |                               strlen(fail_seteuid));
      |                               ~~~~~~~~~~~~~~~~~~~~~
../compositor/main.c:434:25: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
  434 |                         write(STDERR_FILENO, fail_cloexec,
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  435 |                               strlen(fail_cloexec));
      |                               ~~~~~~~~~~~~~~~~~~~~~
../compositor/main.c:442:25: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
  442 |                         write(STDERR_FILENO, fail_exec, strlen(fail_exec));
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 8c4cdd782e17aa587bfccb6746998571ddc90dd7)
2022-11-21 13:55:20 +02:00
Marius Vlad 715eb67cd8 backend-rdp/rdpclip: Avoid printing negative index
As clipboard_find_supported_format_by_mime_type() can return -1 if it
can't find out an index avoid trying to print outside of the array.

Fixes the following warnings triggered when enabling FORTIFY_SOURCE
combined with optimizations (-O)

../libweston/backend-rdp/rdpclip.c:1114:17: error: array subscript -1 is below array bounds of ‘uint32_t[5]’ {aka ‘unsigned int[5]’} [-Werror=array-bounds]
 1114 |                 weston_log("RDP %s (%p:%s) specified format \"%s\" index:%d formatId:%d is not supported by client\n",
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1115 |                            __func__, source, clipboard_data_source_state_to_string(source),
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1116 |                            mime_type, index, source->client_format_id_table[index]);
      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../libweston/backend-rdp/rdpclip.c:131:18: note: while referencing ‘client_format_id_table’
  131 |         uint32_t client_format_id_table[RDP_NUM_CLIPBOARD_FORMATS];

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 9455ad7c7c07fdb8218330f449c97be73f695742)
2022-11-21 13:55:20 +02:00
Marius Vlad 0da83cc1d8 doc/sphinx: Make doxygen warn as error depend on meson werror flag
As seen previous times, with newer doxygen version we seem to be
generating warnings and with it to stop generating documentation
entirely as we have enabled warning as error in the doxygen
configuration file.

By default meson werror build option is not enabled, so users can still
generate documentation when building regularly, and when we'll update to
the same doxygen version we should be able to catch those errors up if
any of them will pile up in between.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
(cherry picked from commit 402d9a81c9a42b0dcfc457c80382c36f5cecc6e6)
2022-11-21 13:55:20 +02:00
vanfanel 24ee61445c Don't change the max_bpc connector prop if mode=current.
As things are, even when mode=current is specified on the .ini file,
a full modeset is needed (and done), which causes a very noticeable
screen blinking. That is because setting the max_bpc on a connector
needs full modesetting.
The idea here is that if mode=current on the .ini, no modesetting
should be done, so the current max_bpc is programmed into the
connector.
But if a custom max-bpc=... is specified, that will be used instead,
even if mode=current on the .ini

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

Signed-off-by: vanfanel <redwindwanderer@gmail.com>
(cherry picked from commit 3240ccc69d1488003c1cfc36d23750145d4f13f7)
2022-11-21 13:55:20 +02:00
Michael Olbrich 870db9703c backend-wayland: always propagate touch frame event
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
(cherry picked from commit 631b60b38bf03a41515c4cdc9294f5b21ca719a5)
2022-11-21 13:55:20 +02:00
Michael Olbrich cf1ca2c300 input: send touch frame event after up event
Currently the frame event gets lost: The touch focus is removed in the 'up'
event. So the focus is gone when the frame event arrives so it is never sent to
the clients.

To avoid this, keep the touch focus until the frame is handled.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
(cherry picked from commit 5448580111b5ff992ce2603cb6e99b9f54db7ad8)

This has undergone a change to avoid an ABI break, so rather than
hooking up a pending_touch boolean in weston_touch, keep a local list of
weston_touch_devices and have a pending_touch with each device to check
upon.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-11-21 13:54:48 +02:00
Simon Ser d23a69272f build: bump to version 11.0.0 for the official release 2022-09-22 18:16:14 +02:00
Simon Ser 3dc6a682e4 build: bump to version 10.0.94 for the RC2 release
Signed-off-by: Simon Ser <contact@emersion.fr>
2022-09-15 19:09:49 +02:00
Alexandros Frantzis 0669d4de4f libweston: Skip views without a layer assignment in output_mask calculations
Surface views that are not assigned to a layer are not going to be
rendered, and thus should not participate in determining the outputs the
surface is on.

There are other view properties that may determine if the view should be
considered in output_mask calculations, e.g., is_mapped, but checking
for this currently breaks tests. Such additional checks are left for
future fixes or reworkings of the view infrastructure.

Fixes #646

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
2022-09-14 17:08:09 +03:00
Marius Vlad b87418e4c4 clients/eventdemo: Remove duplicated param entries
Removes doxygen warning.

Fixes #664

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-09-14 16:46:24 +03:00
Pekka Paalanen 259bd17822 doc: remove directives deprecated in Doxygen 1.9.5
All these Doxygen configuration directives raise a deprecation warning
with Doxygen 1.9.5.

Since we have WARN_AS_ERROR = YES, this causes the build to fail.

Remove these deprecated directives.

I have checked the differences by first building from scratch without
this patch, and then building from scratch with this patch, and
in the latter builddir checking

$ diff -ru -x '*.md5' -x '*.pdf' ~/tmp/weston-doc-before doc

The only differences are the Doxygen config file and one .pickle file.
So it seems the generated docs are identical with Doxygen 1.9.1.

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

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-09-13 18:38:27 +03:00
Derek Foreman 11ba13d717 clients: Fix cursors when compositor gives wl_seat before wl_compositor
We have no guarantee that we can create a surface for the pointer at the
instant we receive a seat that will (probably eventually) need one.

Hold off until we receive an enter event before creating this - at that
point we know with certainty that wl_compositor is available, since we've
used it to create the surface that was entered.

Fixes #659

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-09-12 11:53:41 -05:00
Simon Ser a6b8f0f89c build: bump to version 10.0.93 for the RC1 release 2022-09-06 19:29:17 +02:00
Marius Vlad 1aa935e6d8 libweston/input: Assert if we're still having a notify listener installed
Tracking correctly previous events shouldn't corrupt the surface destroy
signal list. This enforces that by ensuring that we wouldn't have
a .notify wl_listener still being set (which shouldn't happen if we do
eventually get a focus_in event that clears it out).

Suggested-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-09-02 15:45:13 +03:00
Marius Vlad d6ab6da988 libweston/backend-x11: Tracking previous events over multiple calls
Rather than doing it with a local variable, track any previous events by
hanging it out of the x11 backend and use it to handle keymap notify
events.

In this way we avoid corrupting the surface destroy signal list, in
notify_keyboard_focus_out(), ultimately leading to a crash.

Fixes #649, #650

Suggested-by: Daniel Stone <daniel.stone@collabora.com>
Reported-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-09-02 15:45:11 +03:00
Michael Olbrich 4cde507be6 backend-drm: fix plane sorting
The planes in the plane_list must be sorted from largest zpos_max to smallest.

Currently the plane order is only correct when the planes are already ordered
and added starting with the smallest zpos_max. This works accidentally in most
cases because the primary plane is usually first and there is often only one
overlay plane or the zpos is sufficiantly configurable.

To fix this, insert a new plane before the first plane with a smaller zpos_max.
And if none is found, insert it at the end of the list.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-08-31 08:28:55 +02:00
Simon Ser 4990e28ff2 build: bump to version 10.0.92 for the beta release 2022-08-23 19:16:02 +02:00
Marius Vlad 32791eae1f simple-egl: Update buffer_size dimensions when starting as maximized
With commit 62ab6891db, 'clients/simple-egl: Handle buffer
scale and transform' we changed the way we resized the client, by
encapsulating the resize in update_buffer_geometry() function.

we didn't correct that when creating the EGL window, which might be
problematic if you attempt to start the window with different a
different state, like maximized.

Fixes 62ab6891db

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-22 18:22:57 +03:00
Erik Kurzinger 8f1ca8204a clients/simple-egl: call eglSwapInterval after eglMakeCurrent
If weston-simple-egl is run with the "-b" flag, it will attempt to set
the swap interval to 0 during create_surface. However, at that point, it
will not have made its EGLContext current yet, causing the
eglSwapInterval call to have no effect. To fix this, wait until the
EGLContext has been made current in init_gl before updating the swap
interval.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2022-08-12 08:22:26 -07:00
Derek Foreman 646cc1b389 clients: Set the hotspot with attach if we already have a valid cursor
We want atomic hotspot updates - this can't happen with
wl_pointer_set_cursor. So if we have a surface that already has a cursor
role, just update the hotspot when attaching new content.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-10 13:05:09 -05:00
Derek Foreman ebbe30df3c Revert "clients/window: atomically update pointer cursor"
This reverts commit 992ee045f1.

Recreating the surface for every cursor change causes flickering
cursors on some compositors, and is not the best way to achieve
atomic cursor updates

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-10 13:05:07 -05:00
Derek Foreman 8b0125d601 Revert "clients/window: Fix animated cursors"
This reverts commit f079f43658.

This only partially fixed a problem introduced in
992ee045f1

I'm reverting that commit in favor of a different fix, so this
broken fix needs to go first.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-10 13:04:27 -05:00
Simon Ser aa2b615d30 build: bump to version 10.0.91 for the alpha release
Signed-off-by: Simon Ser <contact@emersion.fr>
2022-08-09 21:59:31 +02:00
Marius Vlad c33e8d2c10 desktop-shell: Handle tiled orientation in various circumstances
This properly handles transition states to, and from, maximized,
fullscreen, surface movement and resizing.

Specifically for surface movement and resizing we unset any
(previously set) tiled information we might have. The same happens for
maximized and fullscreen but additionally we attempt re-install the
orientation if we had one previously.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-09 13:36:43 +03:00
Marius Vlad 5bcbe92d51 desktops-shell: Add tiled orientation support using key-bindings
Patch adds KEY_UP/KEY_DOWN for tiled top and bottom positioning,
KEY_LEFT/KEY_RIGHT correspondingly, for left and right positioning.

It also modifies the man page to include these new bindings, But also with
commit 'compositor: Remove desktop zoom' we no longer have zoom effects
so removed them.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-09 13:36:43 +03:00
Marius Vlad 37a3025d89 libweston/desktop/xdg-shell: Add tiled orientation states
With the help of a newly introduced function, weston_desktop_surface_set_orientation(),
this patch adds missing tiled states from the xdg-shell protocol.
The orientation state is passed on as a bitmask enumeration flag, which the
shell can set, allowing multiple tiling states at once.

These new states are incorporated the same way as the others, retaining
the set state, but also avoiding sending new configure events if nothing
changed since previously acked data.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-09 13:36:40 +03:00
Michael Olbrich 6275a0fb32 backend-drm: delay mode switches until the last commit is completed
Changing the mode will destoy the GBM surface for the output. As a result all
corresponding BOs are deleted regardless of the drm_fb refcount.

While a commit is pending, the last_state may contain a reference to such a BO.
So delay the mode switch until the commit is finished and the reference is
release.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-08-08 14:37:50 +00:00
Michael Tretter a2684005b6 doc: update and move IVI-shell README to doc
The README for the IVI-shell is completely outdated.

Update the documentation, add some more information on the IVI-shell use cases
and explain how to use and customize the IVI-shell. Also convert the file to rst
and move it to doc directory next to the kiosk-shell documentation.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-08-08 14:27:41 +00:00
Michael Tretter 7d16485efd ivi-shell: remove dysfunctional link
The at.projects.genivi.org domain redirects to wiki.covesa.global and the
referenced wiki entry does not exist anymore. Remove it from the comment.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-08-08 14:27:41 +00:00
Michael Tretter b282fe3a73 ivi-shell: remove unused definition ivi_layout_screen
The ivi_layout_screen is internal to the IVI shell and not used by any
controllers. Controllers use weston_output directly.

Remove it from the exported header to avoid confusion.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-08-08 14:27:41 +00:00
Marius Vlad 478b24cae0 desktops-shell: Re-use helper for modifier retrieval
As we now have a helper to retrieve the binding modifier, use it
in desktop-shell as well.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-08 14:22:31 +00:00
Marius Vlad f7ba35f5fc kiosk-shell: Enable debug keybindings
We are missing debug keybinds in kiosk-shell so install them. Adds
the binding-modifier like in desktop-shell in a helper.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-08-08 14:22:31 +00:00
Derek Foreman dac2f146ea xwm: Perform a roundtrip to send a deferred WM_TAKE_FOCUS
WM_TAKE_FOCUS requires a valid timestamp that isn't XCB_TIME_CURRENT. To
get one, we set a property on the window and wait for the notification
that it was set - this notification comes with a valid timestamp.

Once we have that timestamp, delete the property, and fire off the slightly
delayed WM_TAKE_FOCUS client request.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-08 12:43:34 +00:00
Derek Foreman ae4209978c xwayland: Don't focus an already focused xwayland window
We've been doing this when clicking on windows, even if they're
already activated. This leads to sending extra WM_TAKE_FOCUS events
as well as re-rendering the decor every mouse click.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-08 12:43:34 +00:00
Hideyuki Nagase 5afe6c5b39 xwm: Change event mask for WM_TAKE_FOCUS
This should be XCB_EVENT_MASK_NO_EVENT, but was not.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-08-08 12:43:34 +00:00
Hideyuki Nagase 55b2bf9393 xwayland: Respect client WM_TAKE_FOCUS setting
According to https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7 we should
send this focus notification only if a client has WM_TAKE_FOCUS set in
their WM_PROTOCOLS property. We've been sending it unconditionally.

Rather, we've been not-sending it unconditionally because the event mask
is wrong, but that will be fixed in a future commit. Fixing the event
mask first would break some clients (such as xterm).

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-08-08 12:43:34 +00:00
Thomas Petazzoni 6e529cb6ab compositor/main.c: use pixman renderer by default when gl-renderer not enabled
When the gl-renderer is not enabled, weston fails to start, as it
doesn't automatically fallback to the pixman renderer, which is
always enabled.

This commit changes the drm-backend to set by default the --use-pixman
option to true when the gl-renderer is disabled (BUILD_DRM_GBM is not
defined).

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
2022-08-05 10:05:21 +00:00
Derek Foreman 6ee486ff95 libweston: Don't send output_changed signal when moving disabled outputs
weston_output_set_position() currently assumes the output is enabled, but
we could be using weston_output_move() to configure an output that hasn't
yet been enabled.

If that's the case, we don't want to send signals or perform setup that
will eventually happen when the output is enabled anyway.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-05 06:08:30 +00:00
Derek Foreman 7e7198bd88 libweston: Check output placement
Make sure we don't enable an output that overlaps with other enabled
outputs.

We should probably do something similar when moving outputs, but we can't
realistically do that right now, so at least leave a comment explaining
why we're ignoring that case.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-05 06:08:30 +00:00
Derek Foreman 8409b74ec2 libweston: Don't move outputs during enable
This is pretty counter-intuitive, and should probably happen outside of
the core in the front end while configuring the outputs.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-05 06:08:30 +00:00
Michael Olbrich 3b3fdc52c3 backend-drm: improve atomic commit failure handling
When an atomic commit fails then the output will be stuck in
REPAINT_AWAITING_COMPLETION state. It is waiting for a vblank event that was
never scheduled.
If the error is EBUSY then it can be expected to be a transient error. So
propagate the error and schedule a new repaint in the core compositor.

This is necessary because there are some circumstances when the commit can fail
unexpectedly:
- With 'state_invalid == true' one commit will disable all planes. If another
  commit for a different output is triggered immediately afterwards, then this
  commit can temporarily fail with EBUSY because it tries to use the same
  planes.
- At least with i915, if one commit enables an output then a second commit for a
  different output immediately afterwards can temporarily fail with EBUSY. This
  is probably caused by some hardware interdependency.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-08-03 17:35:26 +02:00
Pekka Paalanen d4eafbaa98 backend-wayland: fix pixman buffer size
As wayland-backend is blitting the output decorations into the output
buffer itself, it pretends towards the pixman-renderer that there is no
decorations area. The pixman_image_create_bits() call wraps the
previously allocated buffer with an offset so that pixman-renderer will
paint in the right position.

The bug is that this pixman image was using the original buffer width
and height, instead of the composited area width and height. So the
pixman image looks too big to pixman-renderer, but the renderer didn't
care. The image being too big does risk access out of bounds in
pixman-renderer.

I found this when I was making renderers explicitly aware of the
frambuffer size and resizing, added asserts, and they surprisingly
failed. This fixes that.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-03 13:10:42 +00:00
Derek Foreman 214d48bbab compositor: Fix use after free at shutdown
Another case of forgetting to remove a listener from a list when
signal_emit_mutable fires.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-03 14:38:53 +03:00
Pekka Paalanen 851b16f00c gl-renderer: use pixel_format_info in read_pixels
The GL format and type are already recorded with pixel_format_info, use
that instead of a switch on Pixman formats.

Less special-casing, less dependency on Pixman formats.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-03 14:33:48 +03:00
Pekka Paalanen b966fd07ea libweston: change read_format to struct pixel_format_info
Everywhere we are standardising to drm_fourcc.h pixel format codes, and
using struct pixel_format_info as a general handle that allows us to
access the equivalent format in various APIs. In the name of
standardisation, convert weston_compositor::read_format to
pixel_format_info.

Pixman formats are defined CPU-endian, while DRM formats are defined
always little-endian. OpenGL has various definitions. Correctly mapping
between these when the CPU is big-endian is an extra chore we can
hopefully offload to pixel-formats.c.

GL-renderer read_format is still defined based on Pixman format, because
of the pecualiar way OpenGL defines a pixel format with
GL_UNSIGNED_BYTE. That matches the same Pixman format on big-endian but
not the same drm_fourcc.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-03 14:33:48 +03:00
Pekka Paalanen 03c229f4ce screen-share: use read_format consistently
This was using read_format for the read_pixels() call, and then using a
hardcoded format for interpreting the data received from read_pixels().
That works only by accident, read_format being the same as the hardcoded
format.

Use read_format for the interpreting too. This should guarantee the read
pixels are processed correctly.

Found by code inspection.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-03 14:33:48 +03:00
Pekka Paalanen d2aa62a074 libweston: add pixel_format_get_info_by_pixman()
Sometimes you will have a pixman_image_t and you need the corresponding
drm_fourcc format.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-03 14:33:48 +03:00
Derek Foreman 0aac3dd343 xwm: Don't send synthetic ConfigureNotify to windows that were mapped O-R
It's entirely possible, if ridiculous, for an X11 client to change a
window's override redirect flag while it's mapped. If this changes from
true to false we will start receiving Configure requests for the window.

That leads us to a crash when we try to query the window's current
position from the shell to send a configure notify event, as the shell
doesn't know about the surface.

Instead of trying to cleverly handle this, mostly go back to the behaviour
these clients would've seen before commit cf5aca5a and don't send them
a synthetic configure notify.

We also specifically check in weston_wm_handle_configure_request for
the same condition, and early return there, bypassing a couple of
other things we would've done previously.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-08-02 12:22:50 +00:00
Pekka Paalanen 3387afd56b fullscreen-shell: fix black output
Fullscreen-shell forgot to mark the weston_surface as mapped when
mapping the surface and view. With
f962b48958 that means no surface from
fullscreen-shell clients is eveer shown. Most notably this broke
screen-share plugin, which is maybe the only "real" user of
fullscreen-shell.

Fix this oversight. Now screen-share works again with RDP-backend.

Fixes: f962b48958
	"compositor: Only create paint nodes for mapped surfaces/views"
	(currently unreleased)

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-08-02 11:04:43 +03:00
Marius Vlad f9e52eb0d7 desktop-shell: Always update the shsurf's output to that of the view
In case shsurfs are migrated/moved or started on different outputs other
than the default one, it causes fullscreen views to never being demoted
to a lower stacking level, due to the fact we never update
the view's output whenever that has changed.

Synchronize the desktop shell output's with the view's output in the
transform_handler.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Daniel Stone <daniel.stone@collabora.com>
2022-08-01 15:35:00 +03:00
Pekka Paalanen aac8eefc44 backend-x11: use shorthand for current_mode
Pure refactoring to reduce statement lengths.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-29 08:54:21 +00:00
Pekka Paalanen 9e1c96bce7 backend-wayland: restructure wayland_output_resize_surface()
A following patch is going to need the introduced 'area' and 'fb_size'
variables. Until then though, a little hack is needed to avoid no-gl
builds failing with error: variable 'fb_size' set but not used.

While starting to use struct weston_geometry, convert also the input and
opaque regions to use it. This shortens and simplifies the code, as we
can drop the roughly duplicate code of doing stuff for with vs. without
a frame.

No change in behavior, this is pure refactoring.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-29 08:54:21 +00:00
Pekka Paalanen 8b6c3fe0ad backend-headless: choose pixel format by drm_fourcc
Pixman image formats are CPU-endianess dependent while drm_fourcc are
not. Standardise around drm_fourcc because DRM-backend uses them anyway.

This also makes Pixman-renderer use the same format as GL-renderer will
prefer on headless.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-29 08:54:21 +00:00
Pekka Paalanen dd706d5953 backend-headless: let pixman allocate the image
No need to manually allocate the storage, Pixman can do that.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-29 08:54:21 +00:00
Pekka Paalanen 7323ddec62 pixman-renderer: let pixman allocate shadow
There is no need for us to allocate the storage manually, Pixman can do
that for us.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-29 08:54:21 +00:00
Derek Foreman d6b112c857 xwayland: Only prevent focus change to inactive toplevels
Commit b18f788e2e76 broke motif applications by ensuring they could never
focus their menus - since then any attempt by an application to focus any
window would be met by the window manager immediately refocusing the
currently active toplevel window.

Later we loosened the restriction in 9e07d25a1b to allow clients that
received focus from a grab to do so - but motif applications like nedit
don't set focus in this way, and remain broken.

This patch further loosens our restrictions, now only reverting a focus
change to an inactive top level. This will hopefully prevent any
confusing input routing without breaking reasonable clients.

This restores functionality to motif menus.

Fixes #636
Fixes b18f788e2e

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-07-28 20:49:56 +00:00
Marius Vlad 8a610ffe41 compositor/text-backend: Avoid a potential UAF
The text_input_manager might be destroyed upon a compositor shutdown, so
verify if it's still set-up before attemping to use it to avoid a UAF.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-27 14:15:11 +03:00
Jonas Ådahl 5ffa1962a5 compositor: Add support for wl_surface.offset()
This allows for setting a buffer offset without having to make it part
of the wl_surface.attach request. This is useful for e.g. setting a DND
surface icon hotspot offset when using Vulkan; or doing the same with
EGL without having to use wl_egl_window_resize().

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
2022-07-26 17:43:01 +00:00
Derek Foreman 4564a40cb0 rdp: Move peer list from output to backend
In the future we'll have multiple output support, which makes storing
the peer list on an output rather tricky.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-07-26 17:34:20 +00:00
Michael Olbrich 27d2a4cfab libweston: don't reset the plane for views from other outputs
The paint_node_z_order_list contains all views, not just the ones visible on the
current output. So all views are moved to the primary plane when one output
does not support planes.

This will be relevant with multiple backends: When an output without plane
support is rendered then the views of all other outputs are removed from
the current planes and the corresponding outputs will be repainted
unnecessarily.

So only reset the plane if the view is actually on the current output.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-07-26 17:28:15 +00:00
Derek Foreman 2badd284a5 compositor: Load xwayland module first
This is so the systemd-notify module, if used, will notify readiness after
we're ready to accept X connections, instead of before.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-07-26 17:20:09 +00:00
Derek Foreman 0972c6b2da compositor: Remove deprecated xwayland loading method
This is awkward and long deprecated, and makes us load xwayland after all
the other modules so we know if we have to load it or not. Let's remove it.

We do still need to prevent loading the module the wrong way, though.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-07-26 17:20:09 +00:00
Marius Vlad 78ccc99d0a libweston: Remove runtime render switching
It is only enabled by a debug key binding, currently not tested at all,
and is seems it doesn't really work, so let's remove it. This also
removes it from the man page.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-26 13:40:43 +00:00
Marius Vlad 6744a6278e clients/window: Bump xdg-shell version to latest
It seems we've missed an update from 3 to 4 (bounds events). With it,
this updates to version 5 which sends the capabilities event. Stubs, as
we're not using them.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-26 16:17:43 +03:00
Daniel Stone a8048c5c1c libweston: Properly namespace solid_buffer_values
It's exported by libweston, so shouldn't leak unprefixed types.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-26 11:52:24 +01:00
Joshua Watt a09f02d43a libweston: Compute output protection when head is attached
A head may have its output protection set before it is attached to an
output. Recompute the output protection whenever a head is attached to
make sure it correctly set in output.

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
2022-07-26 13:03:23 +03:00
Daniel Stone b047f989a5 xdg-shell: Implement xdg-shell v5 capabilities event
This skips over xdg-shell v4, which can be implemented with no changes
as it's just another optional event.

v5 adds a capabilities event, which we send to inform clients of the
window manager's capabilities.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-26 12:09:04 +03:00
Daniel Stone 1541c44777 libweston-desktop: Add shell capability queries
Allow other components to query which window-management operations are
supported by the shell.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-26 12:09:04 +03:00
Daniel Stone 28caa08be6 Implement wp_single_pixel_buffer_v1 protocol
This protocol allows clients to create single-pixel RGBA buffers. Now
that we have proper support for these buffers internally within Weston,
we can expose them to clients.

This bumps the build container version, as we now depend on
wayland-protocols v1.26.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-26 10:26:55 +03:00
Daniel Stone 0dcd000b3a build: Separate unstable and version for wayland-protocols
We want to support staging protocols which have a version too, so don't
assume that anything versioned is unstable.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-26 10:26:55 +03:00
Pekka Paalanen 9358706743 README: establish no-malloc-failures policy
There are many reasons why trying to handle malloc() returning NULL by
any other way than calling abort() is not beneficial:

- Usually malloc() does not return NULL, thanks to memory overcommit.
  Instead, the program gets SIGSEGV signal when it tries to access the
  memory.

- Trying to handle NULL will create failure paths that are impractical
  to test. There is no way to be sure the compositor still works once
  such path is actually taken.

- Those failure path will clutter the code, increasing maintenance and
  development burden.

- Sometimes there just isn't a good way to handle the failure.

For more discussion, see the issue link below.

Closes: https://gitlab.freedesktop.org/wayland/weston/-/issues/631

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 13:07:22 +03:00
Pekka Paalanen fc26c749df shared/xalloc.h: do not rely on zalloc()
The definition of zalloc is trivial, so let's just have it here instead
of loading libweston/zalloc.h.

Now xalloc.h does not depend on any libweston header, which makes me
feel slightly better. It's more clean.

Who knows, maybe one day libweston/zalloc.h will be removed.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 12:47:11 +03:00
Pekka Paalanen c95feefbc0 clients/simple-touch: use xzalloc() for buffer
This file relied on shared/xalloc.h to include <libweston/zalloc.h>.
That would be a problem if xalloc.h stopped doing that.

Just use xzalloc().

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 12:45:04 +03:00
Pekka Paalanen 9229a45116 shared: rewrite fail_on_null() as abort_oom_if_null()
Recently I learnt that fprintf() is not async-signal-safe. Maybe it also
attempts to allocate memory sometimes. Hence, using it when we
presumably are out of memory is wishful thinking.

Therefore replace that with async-signal-safe code. If you have to check
pointers from traditional signal handlers, now you could do that too!

While doing this, we also lose the string formatting for line number. I
would argue that printing file and line number is not that useful, if
the system really is out of memory. If not out of memory, a core dump
would give us much more detailed information about what went wrong.

clients/window.c had some calls to fail_on_null() and these are simply
replaced. They were used for checking that creating new wl_proxy by
issuing a protocol request worked, and IIRC that only fails on
out-of-memory, so the same rationale applies here.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 12:44:12 +03:00
Pekka Paalanen cbbf0e59a5 ivi-shell: replace MEM_ALLOC() with mostly xcalloc()
Drop the even more home-grown alloc wrapper and use the xalloc.h
wrappers directly.

xcalloc() is added and used, because calloc() will detect integer
overflows in the size multiplication, while doing a simple
multiplication in the caller is subject to overflows which may result in
allocating not what was expected, subjecting to out-of-bounds access.

All MEM_ALLOC() calls that had a meaningful multiplication in them were
converted to xcalloc(), the rest to xzalloc().

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 12:12:22 +03:00
Pekka Paalanen 27cf50462b README: drop note about a cairo build option
That build option has been long gone. cairo-image is the only flavor used
nowadays.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-20 11:47:16 +03:00
Derek Foreman c79e1126b6 xwayland: give Xwayland its own session
If we leave xwayland in weston's process group, it can receive
signals from the controlling TTY intended for weston.

The easiest way to see this is to launch weston under gdb, start an
X client, and hit ctrl-c in the gdb session. The Xwayland server
will also catch the SIGINT, and the X client will be disconnected.

Instead, let's call setsid() when launching Xwayland, like we do
for launched clients.

Suggested-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-07-19 14:19:57 +00:00
Daniel Stone 53f895b476 wet_process: Do not weston_log() after fork()
[common equivalent of 77cf8cb006 in Xwayland from Pekka Paalanen; its
 commit message follows]

Between fork() and exec() in the child process it is only safe to use
async-signal-safe functions. weston_log() definitely is not one, it
allocates memory and does whatnot.

weston_log() is also inappropriate for other reasons: the child process
has its own stream buffers and flight-recorder. No-one looks into the
child process' flight recorder, so messages would be lost there. The
logging machinery might also attempt to write into debug streams,
meaning both parent and child could be writing simultaneously.

It seems that the best we can do is to pre-bake an error message and
only write() it out if exec() fails. There is no mention that even
strerror_r() might be safe to call, so we don't.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 9ab97ebd72 wet_process: Use custom_env when forking clients
Use the custom_env framework we added for Xwayland when forking to
execute clients. This avoids calling the unsafe getenv in between fork
and exec.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 8aa4571240 wet_process: Inline child_client_exec()
It was only a small function, and inlining it will allow us to make it
more safe without having to duplicate a ton of stuff.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone c0a76716c1 wet_process: Use fdstr when executing clients
This doesn't actually stop us from calling setenv() in between fork()
and exec() when starting clients, but gets us closer to Xwayland's safe
implementation by reusing one of the helpers it added.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone a3175727cb wet_process: Rearrange fork() if tree to case statement
Matches the safe Xwayland implementation more closely and makes it
easier to reuse it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 8b238905d7 xwayland: Use os_socketpair_cloexec()
We already have a helper for this; use it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 5dbe001661 xwayland: Use custom-env arg handling
Use the arg handling added in the previous commit so that the
environment is completely encapsulated inside the custom env.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 965d90cbaa desktop-shell: Use custom_env to launch panel clients
Rather than open-coding our own implementation of parsing a string to
construct an envp and an argp, just use custom_env's implementation.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 2cdb473690 custom-env: Add helper to parse combined env/arg strings
Users like desktop-shell want to parse a provided string containing a
combination of environment and arg, e.g.: ENV=stuff /path/to/thing --good

Add support to custom-env for parsing this, with tests, so we can delete
the custom implementation inside desktop-shell.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone e568a025e1 custom-env: Add support for argument array
execve() takes the same form for arguments as environment: an array of
constant pointers to mutable strings, terminated by a NULL.

To make it easier for users who want to build up their own argument
strings to pass to execve, add support for argument arrays to custom_env.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 2a9cae17d8 custom-env: Add tests for environment handling
Test the basic stuff: initialising from a known environment, setting a
new variable, overwriting a previous variable, and getting the resulting
array to pass to execve.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone fafe5f0fc2 custom-env: Prepare for handling args as well as environment
Rename the bits handling environment variables (currently, all of it),
so we have room to handle args as well.

No functional changes.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone 3af823b69b process-util: Assert we don't finalize twice
Make sure that we only try to finalize once.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Daniel Stone b685e075cd process-util: Move Xwayland fork helpers to shared
We'll want to reuse these inside desktop-shell as well as the Weston
frontend.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-19 14:12:37 +00:00
Marius Vlad 7fd22ae44d libweston/compositor: Check whether flushing is allowed
This patch acts as bandaid in the core compositor to avoid the renderer
doing a flush after the buffer has been released. Flushing after release
can happen due to problems in the internal damage tracking, is violating
the protocol, and causes visible glitches.

A more proper fix would be to handle compositor side damage correctly.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Acked-by: Daniel Stone <daniel.stone@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-15 12:55:30 +03:00
Marius Vlad 50f98b1006 backend-drm/state-propose: Amend an older comment
Since b38b735e20, 'backend-drm: Remove Pixman conditional
for keep_buffer' the Pixman renderer keeps its own reference to buffers
when attached to surfaces, rather than flipping keep_buffer variable for
the surface. Problem is that when switching from the Pixman render to
the GL would not work and could result in a crash upon first repaint.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-15 12:54:05 +03:00
Pekka Paalanen 764c2aff8f xwayland: do not check execve() return value
Simplifies the code a bit.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 1bd92dac01 xwayland: do not use setenv() after fork()
Between fork() and exec() in the child process it is only safe to use
async-signal-safe functions. Painfully, setenv() is not listed as such.

Therefore we must craft our own custom environment, and we get no help
from libc with that.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen d1b01ffb9a xwayland: use execv()
Constructing argv before-hand is a little easier to look at, but this is
mostly just anticipating more changes to how Weston spawns processes in
general.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen a3d7199bea xwayland: use pipe2()
We are already using pipe2() in many places, even in libweston, so let's
simplify the code here as well - not to mention avoid a theoretical
race.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 4c0bdbfde9 xwayland: do not snprintf() after fork()
Between fork() and exec() in the child process it is only safe to use
async-signal-safe functions. Surprisingly, snprintf() is not such
function. See e.g. https://stackoverflow.com/a/6771799 and how snprintf
is not listed in signal-safety(7) manual.

Therefore we must prepare the fd argument strings before fork(). That is
only possible if we also do not dup() fd in the child process. Hence we
remove the close-on-exec flag instead in the child process which has
copies of the parent's file descriptors. Fortunately fcntl() is safe.

struct fdstr is helping to reduce code clutter a bit.

Additionally, if fork() fails, we now clean up the fds we created.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 99b2b958f9 shared: introduce os_fd_clear_cloexec()
This function will be used between fork() and exec() to remove the
close-on-exec flag. The first user will be compositor/xwayland.c.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 0260b8a0b5 shared: fcntl uses int, not long
fcntl(2) manual says the return type is int, and that F_SETFD takes an
int. So use int.

Noticed by code inspection.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 77cf8cb006 xwayland: do not weston_log() after fork()
Between fork() and exec() in the child process it is only safe to use
async-signal-safe functions. weston_log() definitely is not one, it
allocates memory and does whatnot.

weston_log() is also inappropriate for other reasons: the child process
has its own stream buffers and flight-recorder. No-one looks into the
child process' flight recorder, so messages would be lost there. The
logging machinery might also attempt to write into debug streams,
meaning both parent and child could be writing simultaneously.

It seems that the best we can do is to pre-bake an error message and
only write() it out if exec() fails. There is no mention that even
strerror_r() might be safe to call, so we don't.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen 71b40fc76b xwayland: move config reading up
Doing any kind of memory allocation calls between fork() and exec() in
the child process is prone to deadlocks and explosions. In general, only
async-signal-safe functions are safe there.

Move the config access to the parent process before fork() to avoid
problems.

See also:
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/941#note_1457053

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen e88a622434 Revert "xwayland: Don't dup() displayfd pipe"
This reverts commit 4aa885d4af.

Turns out the problem was not about dupping fds at all, but calling
non-async-signal-safe functions like strdup() between fork() and exec()
in the child process.

For more discussion, see:
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/941#note_1457053

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-12 08:30:22 +00:00
Pekka Paalanen ff94ba33cd compositor: fix shutdown when xwayland failed to start
This patch fixes the following:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==528956==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x7fbc5d66bdd7 bp 0x7ffd465573c0 sp 0x7ffd46557398 T0)
==528956==The signal is caused by a WRITE memory access.
==528956==Hint: address points to the zero page.
    #0 0x7fbc5d66bdd7 in wl_list_remove ../../git/wayland/src/wayland-util.c:56
    #1 0x7fbc5cb8869e in wxw_compositor_destroy ../../git/weston/compositor/xwayland.c:357
    #2 0x7fbc5baf3ca6 in weston_signal_emit_mutable ../../git/weston/shared/signal.c:62
    #3 0x7fbc5ba4d6f9 in weston_compositor_destroy ../../git/weston/libweston/compositor.c:8639
    #4 0x7fbc5cb7a5f2 in wet_main ../../git/weston/compositor/main.c:3772
    #5 0x55bd13de2179 in main ../../git/weston/compositor/executable.c:33
    #6 0x7fbc5be61d09 in __libc_start_main ../csu/libc-start.c:308
    #7 0x55bd13de2099 in _start (/home/pq/local/bin/weston+0x1099)

The problem is triggered by configuring a bad path to Xwayland in
weston.ini, which causes exec() to fail. The fork() succeeded though,
which means the weston_process was already on the watch list, and the
watch can be handled, making sigchl_handler() leave the link
uninitialized.

Making sure the link remains removable fixes this.

Fixes: 18897253d4

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-08 11:56:04 +03:00
Pekka Paalanen 00641368e2 compositor: deprecate cms-static and cms-colord plugins
While developing the new color management, keeping these old plugins
working would require extra work. Let's deprecate these to see if anyone
cares about them, pending removal after the Weston 11.0.0 release.

CI will keep building these in the "Full build" configuration only. Doc
and no-GL builds are no different for these plugins, so there these are
no longer built.

See https://gitlab.freedesktop.org/wayland/weston/-/issues/634

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-06 10:38:44 +00:00
Daniel Stone 18897253d4 xwayland: Add compositor destroy listener to free allocation
Otherwise we just leak this into the void. Not good.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 13:25:37 +01:00
Daniel Stone 5b11f4066a xwayland: Allow for old WM_NORMAL_HINTS
There are two versions of WM_NORMAL_HINTS: the original pre-ICCCM
version (standardised by Xlib itself?) provides 15 elements of 32 bits
each, with the ICCCM v1 extending this by 3 additional elements.

Since the flags are enough to identify which elements are present, and
the structure is append-only, we only need to read the minimum length
between what the user provided and what we support.

Fixes a heap overrun found with ASan.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 13:25:37 +01:00
Daniel Stone 4aa885d4af xwayland: Don't dup() displayfd pipe
For some reason, this causes the reads to get completely lost sometimes
in CI.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 13:25:37 +01:00
Daniel Stone 23c8dc7b27 tests: Check requirements after setting up args
Setting up the arguments may consume some of the arguments, e.g. if we
provide a config file or extra modules, then the test harness is
expected to be responsible for freeing those arguments.

Checking the requirements and bailing first means that we never do that,
and thus skipped tests result in leaks. Flip the order so we set up the
args first and skip last, so we can consistently take ownership of all
the provided setup parameters.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:49 +01:00
Daniel Stone f52231660e tests: Use memstream for config-parser test
Using real files is unnecessarily heavy and error-prone. Fixes timeouts
seen on CI with ASan.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:49 +01:00
Daniel Stone 759712ba05 zuc: Delete support for forking tests
ZUC's default mode is to fork for every test case. Unfortunately on
AArch64, fork in an ASan-traced program usually takes around 3.6 entire
seconds. This was leading to the config-parser test timing out.

As none of our remaining ZUC tests even need to fork, just remove all
support for it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:49 +01:00
Daniel Stone 6c8ae362bb CI: Never unload llvmpipe DSO whilst testing
This commit is truly horrible.

We want to run ASan with leak checking enabled in CI so we can catch
memory leaks before they're introduced. This works well with Pixman, and
with NIR-only drivers like iris or Panfrost.

But when we run under llvmpipe - which we do under CI - we start failing
because:
  - Mesa pulls in llvmpipe via dlopen
  - llvmpipe pulls in LLVM itself via DT_NEEDED
  - initialising LLVM's global type/etc systems performs thread-local
    allocations
  - llvmpipe can't free those allocations since the application might
    also be using LLVM
  - Weston stops using GL and destroys all GL objects, leading to Mesa
    unloading llvmpipe like it should
  - with everything disappearing from the process's vmap, ASan can no
    longer keep track of still-reachable pointers
  - tests fail because LLVM is 'leaking'

Usually, an alternative is to LD_PRELOAD a shim which overrides
dlclose() to be a no-op. This is not usable here, because when
$LD_PRELOAD is not empty and ASan is not first in it, ASan immediately
errors out. Prepending ASan doesn't work, because we run our tests
through Meson (which also invokes Ninja), leading to LSan exploding
over CPython and Ninja, which is not what we're interested in.

It would be possible to inject _both_ ASan and a dlclose-does-nothing
shim DSO into the LD_PRELOAD environment for every test, but that seems
even worse, especially as Meson strongly discourages globbing for random
files in the root.

So, here we are, doing what we can: finding where swrast_dri.so (aka
llvmpipe) lives, stashing that in an environment variable, and
deliberately leaking a dlopen handle which we never close to ensure that
neither llvmpipe nor LLVM leave our process's address space before we
exit.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:49 +01:00
Daniel Stone c5ed892b1b CI: Disable ASan fast unwinding for suppressions
Unfortunately just adding suppressions isn't enough; the build of Expat
we have in our CI system does not have frame pointers, so ASan's fast
unwinder can't see through it. This means that the suppressions we've
added won't be taken into account.

For now, disable the fast unwinder for the Xwayland test only. Disabling
it globally is not practical as it massively increases the per-test
runtime, so here (to avoid polluting the build system), we use a
per-test wrapper to selectively choose the unwinder.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:48 +01:00
Daniel Stone 6a06a06980 CI: Skip certain fontconfig leaks
For some reason, the Debian CI setup leaks fontconfig allocations in a
way which it does not for me on Fedora. On the assumption that this has
been fixed between our older CI Debian and Fedora 36, suppress the leak
warning, because we do already call FcFini() which should free it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-05 10:15:38 +01:00
Michael Olbrich f5a4fb5abc backend-drm: make sure all buffers are released when an output is removed
When an output is destroyed then the output state is freed immediately. In this
case, the plane state is only partially destroyed because it is the currently
active state. This includes the buffer reference.

Without the output, the plane will not be updated any more until it is used by a
different output (if possible) or the output returns and the plane is used
again.
As a result, the buffer reference is kept for a long time. This will cause some
applications to stall because weston now keeps two buffers (the one here and
another one for a different output where the application is now displayed).

To avoid this, do a synchronous commit that disables the output. The output
needs to be disabled anyways and this way the current state contains no
buffers that would remain.

`device->state_invalid = true` in drm_output_detach_crtc() is no longer
needed, because drm_output_detach_crtc() is called only when initialization
failed and the crtc was not yet used or in drm_output_deinit() when the
crtc was already disabled with the new synchronous commit.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-07-04 18:42:48 +00:00
Michael Olbrich 158c3ef0dd compositor: destroy the layout after the compositor
This way the backends will the actual outputs. And at that point the backend
knows the compositor is shutting down so it can handle this differently if
necessary.
Afterwards wet_compositor_destroy_layout() just deletes the remaining
datastructures.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-07-04 18:42:48 +00:00
Daniel Stone b923802113 xwayland: Refactor argument string construction
Replace an oft-duplicated pattern with a trivial helper function. In
doing so, we observe that the one special case (displayfd 'didn't need
to be CLOEXEC') was wrong, because the X server does fork itself
internally, so there is nothing wrong with setting CLOEXEC.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-07-04 11:58:37 +00:00
Marius Vlad e5f6e512ce doc/sphinx/doxygen.ini.in: Remove CLASS_DIAGRAM
CLASS_DIAGRAM has been obsolete in newer version of doxygen, and
it's enabled if HAVE_DOT and CLASS_GRAPH are set.

This increase DOT_GRAPH_MAX_NODES to avoid dot complaning,
and include dot/graphviz for doxygen.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-01 17:20:49 +03:00
Marius Vlad afa494014f doc/sphinx/doxygen.ini.in: Remove DOCBOOK_PROGRAMLISTING
A newer version of doyxgen made it obsolete.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-01 17:20:18 +03:00
Marius Vlad bd50e257e6 doc/sphinx/doxygen.ini.in: Remove RTF generation
Same as LaTeX, RTF is being made obsolete in newer version of doxygen.
Also, we weren't really using it so there's no harm in removing it
entirely.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-01 17:20:18 +03:00
Marius Vlad c2c7644fd0 docs/sphinx/doxygen.ini.in: Remove LaTeX generation
LaTeX has become obsolete in newer doxygen version, and we weren't using
it at all so remove it entirely.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-01 17:20:18 +03:00
Marius Vlad 7932664b3b weston-log: Fix documentation for weston_log_subscription_create
Introduced with e0a858a5f2, commit 'weston-debug: Introduce
weston_log_subscription and weston_log_subscriber objects'. We don't
really return a weston_log_subscription so let's remove it.

Some newer doxygen detects this and we are treating warning as errors.

Fixes #594

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-07-01 17:20:18 +03:00
Pekka Paalanen aa4f7d3a63 tests/color-icc-output: add blending test
This is adding basically a copy of alpha-blending-test.c. The difference
is that here we use ICC files to set up the output color profile, and
then test light-linear blending only. BLOCK_WIDTH is set to 1 to fit
inside the output size used by the fixture setup, which is smaller than
in the original, but does not change the results.

The test is aimed at testing how color-lcms module succeeds in
linearizing the output of different ICC output profiles. Incorrect
linearization should cause changes in blending results.

The tolerance is taken from the currently achieved error statistics
(1.40908) and rounded up a little to achieve a suitable margin.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-01 07:46:02 +00:00
Pekka Paalanen 2c0ff9a3b4 tests/color_util: expose color_float_apply_curve()
I will be needing this in color-icc-output blending test.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-07-01 07:46:02 +00:00
Michel Dänzer 77fb2f56af clients/presentation-shm: Bind to xdg_wm_base version 1
It was binding to any advertised version, but it can't actually work
with version 4 (because it doesn't handle the new configure_bounds
event).

Other sample clients in the tree are hard-coding version 1, so do the
same here.

Fixes: 6d9fda7156 ("clients/presentation-shm: use xdg_shell instead of wl_shell")
Signed-off-by: Michel Dänzer <mdaenzer@redhat.com>
2022-06-30 15:16:46 +02:00
Pekka Paalanen b5467ba258 tests/color-icc-output: use two-norm tolerance
Switch from per-channel max error tolerance to max two-norm (Euclidean
distance) error. Geometrically this means that previously the accepted
volume was a +/- tolerance cube around the reference point, and now it
is a sphere with tolerance radius.

The real benefit is simplifying the code.

The error tolerance are also changed to float. Integers cannot represent
values between 1 and 2, and the jump from 1 to 2 would have been too
much. AdobeRGB tolerance gets relaxed a bit, while BT2020 tolerance
becomes stricter. The new tolerance values are the reported achieved
two-norm max errors plus a bit of margin.

Surprisingly the sRGB case tolerances remain strictly at zero, and
that's no bug in the test.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen 3acb1c4793 tests/color-icc-output: compare_float() to rgb_diff_stat
compare_float() was an ad hoc max error logger with optional debug
logging.

Now that we have rgb_diff_stat, we can get the same statistics and more
with less code. It looks like we would lose the pixel index x, but that
can be recovered from the dump file line number.

This patch takes care to keep the test condition exactly the same as it
was before. The statistics print-out has more details now.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen baf7ab5795 tests/alpha-blending: use two_norm tolerance
Switch from per-channel max error tolerance to max two-norm (Euclidean
distance) error. Geometrically this means that previously the accepted
volume was a +/- tolerance cube around the reference point, and now it
is a sphere with tolerance radius. This makes the check slightly
stricter.

The real benefit is simplifying the code.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen a0584e64cf tests/alpha-blending: replace compare_float() with rgb_diff_stat
compare_float() was an ad hoc max error logger with optional debug
logging.

Now that we have rgb_diff_stat, we can get the same statistics and more
with less code. It looks like we would lose the pixel index x, but that
can be recovered from the dump file line number.

This patch takes care to keep the test condition exactly the same as it
was before. The statistics print-out has more details now.

The recorded dump position is the foreground color as that varies while
the background color is constant.

An example Octave function is included to show how to visualize the
rgb_diff_stat dump.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen be281478dc tests/color_util: doc rgb_diff_stat and scalar_stat
Add documentation for test authors.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen e103ef4d0d tests: add rgb_diff_stat dumps
This is a special case of scalar_stat dumps to record all of two-norm
and RGB differences on the same line in the dump file.

This makes the dump file easier to handle when you want full RGB errors
recorded.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen 3f60542405 tests/color_util: make rgb_diff_stat pos explicit
The recently introduced rgb_diff_stat value dumping feature logs the
"position" where the value or error was measured. The reference value
was used as the position, but the problem with the reference value is
that it is an output value and not an input value. Therefore mapping
that back to which input values promoted the error is not easy.

Fix that problem by passing the position explicitly into
rgb_diff_stat_update(), just like it is already passed in to
scalar_stat_update().

Currently the only user simply passes the reference value as position,
because there the input value is also the reference value. This is not
true for future uses of rgb_diff_stat.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen 912ea2cb20 tests: add scalar_stat dumps
The new field in struct scalar_stat allows recording all tested values
into a file. This is intended to replace ad hoc dumping code like in
alpha-blending-test.c.

To make it easy to set up, also offer a helper to open a writable file
whose name consists of a custom prefix and test name.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen f31d26669d tests/color_util: constify *_stat_update()
These arguments are not meant to be changed, and a new test will need
this const.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen 9026293bff tests: change rgb_diff_stat printing
Seems it will be common to print all four min/max/avg sets of errors, so
move the printing code into a shared place.

While 0.0-1.0 is the natural range for color values, people are often
accustomed to working with 8-bit or even 10-bit pixel values. An error
of +/- 1 in 8-bit is more intuitive than +/- 0.004 in floating-point.
Hence 'scaling_bits' is added so the caller can determine the value
scaling. This will scale both the reported error numbers, and the
recorded error positions (rgb-tuples), so they are all comparable.

I'm happy to get rid of those two macros as well.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Pekka Paalanen 0d385ffacb tests/alpha-blending: move unpremult to color_util
More tests are going to need this.

The API is changed to work by copy in and copy out to match the other
color_util API. Hopefully this makes the caller code easier to read.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-30 09:08:32 +00:00
Daniel Stone 213195c4db tests: Don't leak args when skipping tests
We treat the argv we pass into the compositor as its to mangle, just as
it is free to do so for POSIX argv. To support this, we stash argv away
and free the saved copy later so as to not leak.

This works perfectly, except when we never call the compositor at all,
and have no saved array to free. Make sure we free the args in this
case, which can be seen as a leak of any generated args when a test
skips on preflight checks, e.g. drm-smoke when not running in CI.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:22 +01:00
Daniel Stone 2ebdf0a7f3 subsurface-shot-test: Don't leak replaced buffer
Destroy the buffer we've overwritten.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:22 +01:00
Daniel Stone 5374d55f6a safe-signal-test: Fix leak
Oops.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone c55a14206d cairo-util: Clean up more Cairo detritus; almost all of it
Pango, Cairo, and fontconfig, all want to leave thread-global data
hanging around in order to maintain a cache. Try to clean up as much of
it as we possibly can on exit, apart from the Pango language string
which appears to be unfreeable, so has been added to LSan suppressions.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone 29c3422e05 cairo-util: Don't leak Pango objects
Rework PangoCairo context initialisation, so we don't leak either the
Pango layout, or any of the derived objects it creates.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone d43931080e weston-terminal: Don't leak Cairo fonts
The docs say they're ours to unref.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone fc4fb9fb92 weston-terminal: Make exit path a little more obvious
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone f9e54ab2f8 weston-terminal: Fix some egregious memory leaks
Some of the Pango bits still leak, but this takes care of a lot of the
worst.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone 6bfbfb2e10 toytoolkit: Delete remnants of EGL support
This code was all dead, since neither cairo-glesv2 nor the sample nested
compositor ever made it to the Meson build.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone 01c57eca43 backend-drm: Don't leak drm_device on shutdown
This was introduced in a partial MR, where the later commits in the new
multi-GPU MR fully fix it, but the initially cherry-picked ones don't.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Daniel Stone 97f664815d backend-wayland: Don't leak parent output trackers
We were only destroying these when the parent display removed the output
global. Do it on shutdown too, so we can avoid leaking it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 14:33:21 +01:00
Derek Foreman cf5aca5a0d xwm: Generate more synthetic ConfigureNotify events
Many programs use this information to help position pop-ups properly, and
without it funny things happen. For example, nedit and tkinter apps will
position their menus incorrectly either all the time or after an initial
window move, firefox may position right-click pop-ups incorrectly
depending on other internal state.

https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5 has much detail on
how this should work, and the Advice to Implementors section shows that
common client practices will break in the face of our miserly handling
of ConfigureNotify events.

Instead of trying to send it only for configure requests received when a
client is in a fullscreen state, send them much more frequently.

Fixes #619

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-29 11:44:48 +00:00
Derek Foreman ea9a01f2e3 xwm: Prepare send_configurenotify for non-fullscreen use
Currently weston_wm_window_send_configurenotify is only called for
fullscreen clients, and it is written to be correct only in that case.

Fix it up to handle other cases properly so we can use it for them in a
later commit. Synthetic Configure Notify events are relative to the
root window, so this means adding our window co-ordinate when
necessary.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-29 11:44:48 +00:00
Derek Foreman 23e3a3285a libweston-desktop: Add get_position
Plumb the new weston_desktop_api_get_position() through to xwayland.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-29 11:44:48 +00:00
Derek Foreman d615abdffd shells: Add libweston-desktop API to query position and add to shells
We're going to need this to properly send xwayland events later, so add
API to get the current x,y co-ordinates of a shell surface and add it to
the kiosk and desktop shells.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-29 11:44:48 +00:00
Daniel Stone ed97387a4e tests: Use test-desktop-shell for devices-test
It doesn't need to be using desktop-shell; trying to use it is not
sensible as it will try to bind to all the devices we're repeatedly
creating and destroying, sometimes lose the race, and fail the test
because desktop-shell has died too early.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 11:38:36 +00:00
Daniel Stone 450ec38d79 noop-renderer: Make sure buffer access doesn't get optimised out
noop-renderer needs to actually access the buffer content, to ensure
that the bad-buffer test works. This was previously done using a
volatile variable, but clang rightly pointed out that the variable
access had no effect (since the volatile stack variable was never read
from, and the source is not volatile), so 9b0b5b57dd changed it to be
explicitly marked it as unused to suppress the compiler warning.

Unfortunately suppressing the warning still leaves the compiler free to
optimise out the access.

Replace the variable decorations with actually using the result of the
read, so we can be really sure that it's never going to be optimised
away.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 11:38:36 +00:00
Daniel Stone 19278569a3 noop-renderer: weston_buffer properties are set by the core
ca9bb01fe6 made it so that we already set shm_buffer, width, height,
etc, in the core. There's no need for the renderer to do this.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-29 11:38:36 +00:00
Hideyuki Nagase e4100f856d xwayland: Change layer for xwayland override redirect windows
Our positioning of override redirect windows falls apart when an
app is on the fullscreen layer, because we end up putting its
menus and tooltips beneath it. This patch raises the special
override redirect layer to be just below things like on-screen
keyboards (and, unfortunately, above things like panels).

There is no perfect way to deal with this problem, especially
for content like tooltips that don't come with transience hints.

In some cases override redirect menus could be better placed by
using the parenting/transience information provided with them
at map time, and we should probably do that at some point, but
that would still leave us with tooltips below full screen
applications, and the need for this layer change.

based on a patch
Co-authored-by: Hideyuki Nagase <hideyukn@microsoft.com>
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>

I changed the layer position and the comments, so:
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-28 11:37:54 +00:00
Derek Foreman 0df0dccc84 shared: Make xalloc.h stand alone
Make fail_on_null static inline and put it in xalloc.h so we can use the
header exclusively instead of having to link with the library for it.

This is so we can use xalloc in places (like the RDP backend) without
having to bring in libshared.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-28 10:43:39 +00:00
Daniel Stone 9336263d9b Move libweston-desktop into libweston
It's not really useful to have libweston without libweston-desktop. It's
also very little code.

Merging both into the same DSO will allow us to cut out a bunch of
indirection and pain.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-28 10:35:52 +00:00
Daniel Stone 3ed3700ca3 kiosk-shell: Don't link desktop-shell protocols
We don't need these.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-28 10:35:52 +00:00
Daniel Stone 0774a321c5 scene-graph: Print when surface/view is not mapped
A view shouldn't be mapped if a surface isn't mapped, and it shouldn't
be in the scene graph if it isn't mapped either. Print when this happens
so you can see more from the debug.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-28 10:35:52 +00:00
Michael Olbrich 10403a85ec libweston: disable a pending idle_repaint_source when the output is removed
Currently the idle_repaint_source is removed when the output is destroyed.
This covers the most common case: When a monitor is unplugged then the
corresponding DRM output is destroyed and not just disabled.

However, outputs can be explicitly disabled by the shell. In this case the
output is not removed and idle_repaint() may be called for a removed
output.

Remove the idle_repaint_source in weston_compositor_remove_output() to fix
this. And reset the variable to ensure that the source can be created
again.

Removing the source in weston_output_release() is now no longer necessary
since it calls weston_compositor_remove_output().

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-27 09:03:09 +00:00
Daniel Stone 61d8238874 desktop-shell: Remove multiple workspace support
It's not the most code ever, but it does make desktop-shell somewhat
more complicated for questionable (i.e. no) end-user benefit.

When desktop-shell is back in more healthy shape it could potentially be
reintroduced, but for now it's just making it more difficult to reason
about desktop-shell and fix it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-24 10:47:42 +03:00
Michael Olbrich 48e8c158ea compositor: only reflow the outputs if the shell did not move them
weston_compositor_reflow_outputs() assumes that all output are positioned from
left to right with no gaps in the same order in which they where created.

If the shell moves an output with weston_output_move() then this assumption is
no longer true. So stop reflowing the outputs in the case. The shell is now
responsible for positioning all outputs as needed.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-23 18:02:00 +00:00
Marius Vlad 59a72dcf63 shared/xcb-xwayland: Add missing atoms
Particularly important was _XWAYLAND_ALLOW_COMMITS atom which caused
some annoying flicker when resizing or hoovering over buttons.

This was introduced with 'shared/xcb-xwayland: Split into common
helpers' and somehow I missed those atoms.

Fixes 49d6532254

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-06-23 14:13:41 +00:00
Michael Olbrich 2929b6c483 backend-drm: check that outputs are in fact ours
This is another followup to ffc011d6a3
("backend-drm: check that outputs and heads are in fact ours") which missed
some places.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-23 14:00:04 +00:00
Derek Foreman af51618708 xwayland/window-manager: Add support for _NET_FRAME_EXTENTS
https://specifications.freedesktop.org/wm-spec/1.4/ar01s05.html says
"The Window Manager MUST set _NET_FRAME_EXTENTS to the extents of the
window's frame", so this is probably something we should be doing.

Some programs (such as some versions of Firefox) expect this to be present,
and will render popups in wrong locations if it's not.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-22 12:05:23 -05:00
Derek Foreman 769e4376c6 shared/frame: Provide a function to get decoration sizes and use it
We need these values to calculate frame extents to properly set
_NET_FRAME_EXTENTS, but we don't want to calculate them twice.

Break out these bits from frame_resize_inside, and update it to use
the new function.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-22 12:04:06 -05:00
Hideyuki Nagase d902088bfc xwayland: support minimizing
Allow minimizing xwayland windows.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-06-22 09:57:25 -05:00
Marius Vlad cc69dc447e clients/window: Defer closing of window
Instead of closing the window directly by calling close_handler() use a
deferred task to do that instead.

That way we avoid a potential invalid access on a link which was
previously removed, due to the fact both window_destroy() and
touch_handle_up() traverse the same list.

This is an alternative to 841.

Fixes: #607.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Reported-by: He Yong <hyyoxhk@163.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-06-22 15:29:05 +03:00
Pekka Paalanen 57d32722a2 gl-renderer: simplify main() in frag
By moving the application of view_alpha after pre-multiplication we can
simplify main() considerably.

The cost is that for straight-alpha input or color_pipeline() we might
be doing three multiplications more than before. However,

 a) the cost of running color_pipeline() probably dominates anyway, and
 b) to get straight-alpha input you have to use a future Wayland
   extension that probably won't be advertised without color management.

So we keep the optimization for the simple case (no color management)
while potentially incurring a small cost on the heavy case (with color
management).

Thanks to Pierre-Yves Mordred for the inspiration in
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/889#note_1411774

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-22 12:15:58 +00:00
Pekka Paalanen 932c374779 gl-renderer: move undo-premult to color_pipeline()
Now that we have the if-else ladder to call color_pipeline() only when
necessary, and since only color_pipeline() needs undo-premult, move
undo-premult into color_pipeline().

This is a small step towards improving code readability.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-22 12:15:58 +00:00
Pekka Paalanen 924b94bc94 gl-renderer: call it view_alpha in frag
We always talk about "view alpha", so the name variable in the fragment
shader the same. Now it's clear without the comments, making the code
easier to read overall.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-22 12:15:58 +00:00
Marius Vlad 49d6532254 shared/xcb-xwayland: Split into common helpers
Avoid duplication of atom retrieval. This is particuarly useful
if one would one to reuse atom retrival in other parts, like tests.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Daniel Stone <daniel.stone@collabora.com>
2022-06-22 08:08:41 +00:00
Derek Foreman 107d69f10c xwayland: Stop drawing shadows on maximized windows
This is especially weird on multi-head setups, but we shouldn't be doing
it in any cases.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-20 16:57:48 +00:00
Derek Foreman 8763f3800e xwayland: Update net_wm state when we change it.
According to the wm-spec we must keep the _NET_WM_STATE property updated
to reflect the current state of the window.

This has been biting me when firefox starts maximized, then I click the
maximize button to toggle to unmaximized state. The next time I mouse over
the maximize button (which causes the frame to be re-rendered with the
maximized button in a highlighted state) we re-read the window state and
weston then believes the window is maximized even though it is being
rendered in a not-maximized state.

Update the state when we change maximized status so this doesn't happen.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-20 16:57:48 +00:00
Derek Foreman 93b58c5648 xwayland: Don't move window in response to geometry change if state changed
When we leave fullscreen or maximized mode we restore a saved window
position. This is expected, but that saved position was saved when window
geometry was set to have shadows rendered.

Since we restore a saved position that had shadow geometry, we don't want
to move the window when we set geometry again, or we'll move away from the
intended saved position.

I guess this is a counter-proposal to !614

Fixes #454

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-20 16:57:48 +00:00
Derek Foreman 40e76fe19d xwayland: Set non zero default saved window size
If a client starts off maximized, clicking the unmaximize button would
result in a 0x0 window - basically a blob of decor with no content.

Instead, use 512x512 as a totally random default value.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-20 16:57:48 +00:00
Ivan Nikolaenko 0d3e438d08 build: fix possible race/error for some backends
There is missing dependency on linux-dmabuf-unstable-v1-server-protocol.h
header file in backend-headless, backend-drm and backend-x11. That files
do not depend on that header, in fact. But by this moment they've had
that implicit dependency due to linux-dmabuf.h header.

With specific set of meson configure options the protocol header is not
generated at the right time, what causes build error in 100% cases using
small amount of building threads (from -j1 to -j8).

Signed-off-by: Ivan Nikolaenko <ivan.nikolaenko@unikie.com>
2022-06-20 16:14:01 +03:00
Michael Olbrich 78933093a1 backend-drm: check that outputs are in fact ours
This is a followup to ffc011d6a3
("backend-drm: check that outputs and heads are in fact ours") which missed
some places.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-16 09:53:01 +00:00
Michael Olbrich 3e44a6eb3d backend-drm: don't try to disable planes on session deactivation
This uses the legacy DRM API it incomplete and no longer works anyways.
At this point, weston is no longer DRM master, so these calls fail with
"Permission denied".

So just remove the corresponding code.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-16 09:53:01 +00:00
Daniel Stone f962b48958 compositor: Only create paint nodes for mapped surfaces/views
If a surface or a view is not mapped, then we should not be trying to
paint it. Check if this is the case and ensure that we only insert
paint nodes for mapped surfaces & views.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Fixes: #621
2022-06-16 12:17:15 +03:00
Daniel Stone f1fe6ec776 xdg-shell: Mark xdg_popup surfaces as mapped
Keep the surface map state in sync with the buffer state: the surface
can be mapped it has a valid buffer, and not if it doesn't.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone c0ff9ed24a test-desktop-shell: Mark weston_curtain views as mapped
Make sure we're there when we need them.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone 19744a5207 weston-curtain: Always mark surface as mapped
The surface always has valid content, hence it can always be mapped.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone af7dcdddac desktop-shell: Map surfaces in map()
The only caller of map() then manually sets is_mapped = true. Just do it
in the function which makes you think that's what it would do.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone 0c69688aa2 libweston: Add weston_surface_map() wrapper
Change all instances of surface->is_mapped = true, to a specialised
function.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone 51fe874ad4 libweston: Use weston_surface_has_content() in core compositor
Used when taking the size from a buffer, as well as in subsurface
handling.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone dd6b5a190e data-device: Use weston_surface_has_content()
Now we've got a wrapper which tells us whether or not the surface has
valid content, use it.

The 'XXX' comment was removed because it's the same pattern as every
other surface-role implementor: if the surface is not mapped but does
have valid content, then map it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone 888d08d8a5 desktop-shell: Use weston_surface_has_content()
Now we've got a wrapper which can tell us whether or not a surface has
content, use it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone d211e3173c xdg-shell: Use weston_surface_has_content()
Now that we've got a wrapper telling us whether or not the surface has
content, just use it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Daniel Stone 13ead893e2 Add weston_surface_has_content()
Just a trivial wrapper to tell you whether or not the surface has valid
content.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-06-16 12:17:15 +03:00
Pekka Paalanen f212a703cf tests/alpha-blend: use image-iter.h
Simplify the code by using ready-made helpers.

No change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 67331be0cd tests/internal-screenshot: use image-iter.h
Simplify the code by using ready-made helpers.

This also change the loop to draw the image row by row rather than
column by column. Row by row is more natural as it is linear with the
memory layout. No other change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 884c5f80e8 tests/yuv-buffer: use image-iter.h for rgb_image
Make use of the shared code instead of open-coding everywhere. This
should make the code easier to read, and reduce the chance of typos if
changes are needed in the future.

No change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 94589497a1 tests/client-helper: use image_header_from() more
These are the last places in weston-test-client-helper.c where using
image_header_from() will reduce the code line count and simplify the
code a little.

No change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 791a6be216 tests: pass image_header to image_check_get_roi()
Make use of the new type to shorten the code.

No change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 4eb70a602b tests/client-helper: use image-iter.h
Replace private pixel iterator helpers with the shared ones.

No change in behaviour.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 9b82bfae9e tests/color-icc-output: extract image-iter.h
Move the struct image_header and get_image_prop() into a header where we
can share these useful helpers between more test code. While doing that,
drop the unused field 'depth', rename into image_header_from(), and
introduce a helper to get u32 pointer to the beginning of a row. These
helpers should make pixel iterating code easier to read and safer (less
room for mistakes in address computations, and asserts).

Use the shared 'struct image_header' instead of the local one. The
intention is to make the code easier to read by using the same helpers
everywhere.

Width, height and stride use type 'int' because Pixman API uses that
too.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-16 08:52:12 +00:00
Pekka Paalanen 8de94ec9c9 compositor: add weston.ini option max-bpc
For working around hardware limitations as explained in the man page.
Now added for completeness' sake without knowing if anyone will ever
need this.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-15 12:58:38 +00:00
Pekka Paalanen d24adbbe25 backend-drm: set connector max bpc
"max bpc" property is meant for working around faulty sink hardware.
Normally it should be set to the maximum possible value so that the
kernel driver has full freedom to choose the link bpc without being
artificially forced to lower color precision.

The default value is 16 because that is a nice round number and more
than any link technology I've heard is using today which would be 12.

Also offer an API set the value, so that weston.ini could be used in the
next patch for sink workaround purposes.

Closes: https://gitlab.freedesktop.org/wayland/weston/-/issues/612

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-15 12:58:38 +00:00
Pekka Paalanen 4d2ea5dd0b tests: move set_opaque_rect() to client helpers
I will be needing it in a new test, so let's share it.

For convenience, this also adds client back-pointer in struct surface so
that I don't need to pass client explicitly.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-15 12:36:05 +03:00
Pekka Paalanen b878357dfd tests: remove skip() as unused
skip() is a left-over from an old test harness design, the comment even
refers to automake. Calling skip() cannot do anything good anymore,
because it wouldn't print the skips in the TAP report, so it would
probably be considered a failure.

Delete this unused and nowadays incorrect function, so it doesn't
confuse people.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-15 12:36:05 +03:00
Robert Mader f7541d9e42 clients/simple-egl: Fix angle reset on benchmark interval
Commit 62ab6891db intended to change the angle calculation
so that the a time delta since the first frame would be used
instead of the absolute time. That was done in order to ensure
the angle would always start with the same value, allowing users
to differentiate left and right, which again is needed when
testing flipped transforms.

However, the `benchmark_time` variable is unsuitable for that
purpose as it gets reset on each benchmark interval, abruptly
changing the angle.

Thus introduce a dedicated variable.

Fixes 62ab6891db

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-06-14 13:11:59 +02:00
Hideyuki Nagase ae9643f729 build: enable configuration of RDP backend as a default
Add RDP to the list of backends we can set as default for use
when weston is launched without display/socket environment vars
set.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-06-10 10:57:22 +00:00
Pekka Paalanen 731a2fd45b tests/color-icc-output: move gen_ramp_rgb() in the file
Move gen_ramp_rgb() down in the file where the TEST() specific code
begins. This way we first have a big block of fixture setup code which
creates an ICC profile, and the next big block is the actual test client
code. gen_ramp_rgb() belongs with the latter.

This makes the file structure slightly more logical.

This is a pure code move, no changes at all.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-10 10:49:47 +00:00
Pekka Paalanen cb38c9c84d tests: rename shaper_matrix_and_cLUT to opaque_pixel_conversion
This name describes better what this test does. In the future another
TEST() for alpha blending will be added. Both of them will be using
matrix-shaper and cLUT output profiles.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-10 10:49:47 +00:00
Pekka Paalanen 6393e43357 tests: rename color-shaper-matrix-test.c to color-icc-output-test.c
The new name better matches the contents of the test.

Currently the test creates output ICC profiles with matrix-shaper and
cLUT forms, and tests that basic color conversion from input to output
color space is correct.

The common theme in this test program is to create ICC profiles to be
used as output profiles. In the future this can include more kinds of
testing, e.g. linear blending. OTOH, this test program will always be
limited to SDR because HDR testing probably will not use ICC files.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-10 10:49:47 +00:00
Philipp Zabel 4938f8f6e5 compositor: stop creating outputs without head
To support heterogeneous outputs, the output must be created by the
same backend as the head(s) it is created for. Solve this by always
creating an output with a first head to attach that determines the
backend to use. Skip already attached first heads in drm_try_attach().

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel c6e47d177a libweston: consolidate weston_compositor_create_output(_with_head)
Add a struct weston_head parameter to weston_compositor_create_output()
and fold weston_compositor_create_output_with_head() into it.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel 060ef82d93 backend-x11: check that outputs and heads are in fact ours
As a first step towards heterogeneous outputs, ignore other backends'
heads and outputs. This is done by checking the destroy callbacks for
heads and outputs.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel 69c4cec4f1 backend-wayland: check that outputs and heads are in fact ours
As a first step towards heterogeneous outputs, ignore other backends'
heads and outputs. This is done by checking the destroy callbacks for
heads and outputs.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel 5b41ffa9da backend-rdp: check that outputs and heads are in fact ours
As a first step towards heterogeneous outputs, ignore other backends'
heads and outputs. This is done by checking the destroy callbacks for
heads and outputs.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel 5159af0607 backend-headless: check that outputs and heads are in fact ours
As a first step towards heterogeneous outputs, ignore other backends'
heads and outputs. This is done by checking the destroy callbacks for
heads and outputs.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel ffc011d6a3 backend-drm: check that outputs and heads are in fact ours
As a first step towards heterogeneous outputs, ignore other backends'
heads and outputs. This is done by checking the destroy callbacks for
heads and outputs.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel aab722bb17 backend-drm: prepare virtual output API for heterogeneous outputs
Stop plugins from overwriting the struct weston_output::destroy vfunc,
as that will be used by backends to recognize their outputs.
Instead, pass a plugin-specific destroy callback when creating the
virtual output.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Philipp Zabel 54d7682ee8 libweston: add opaque backend_id pointer to struct weston_head
As a first step towards heterogeneous outputs, add an opaque pointer
weston_head::backend_id that will be used by backends to identify
their own heads.

See: https://gitlab.freedesktop.org/wayland/weston/-/issues/268

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2022-06-10 09:27:43 +00:00
Derek Foreman 982e59a942 rdp: Stop using deprecated functions
The get file descriptor functions are being deprecated and a two step
process of getting handles and then getting the descriptors for the
handles is being used instead.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-09 13:17:03 +00:00
Derek Foreman 5014eb03a3 rdp: Update to new FreeRDP structure layout
In an upcoming release the old style will be deprecated, so let's update
now.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-09 13:17:03 +00:00
Derek Foreman da386c827e rdp: Update to newer FreeRDP release
Update to a newer FreeRDP release so we can start cleaning up
some of our usage of things that will be deprecated in the next
major release.

For this, I've simply picked the newest version currently in
our CI images.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-09 13:17:03 +00:00
Derek Foreman 2afb812d1e shared/cairo-util: Hold onto our pattern reference until we're done
This doesn't actually fix a bug - cairo refcounts this. But I
really don't like the look of code that drops a reference then
continues to use it.

While we're here, set a different pattern when we're done so the
one we allocated loses its last reference.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-09 12:29:46 +00:00
Luigi Santivetti 8b654c47eb Revert "backend-drm: add HDR_OUTPUT_METADATA definitions"
This reverts commit 6914064066.

This is a follow-up change of b623fd2a ("drm-backend: stop parsing IN_FORMATS
blobs, use libdrm instead"). Weston now has a hard-requirement on libdrm
2.4.108, clean up remaining and unnecessary conditional code. Change 69140640
("backend-drm: add HDR_OUTPUT_METADATA definitions") is no longer needed
and stop including libdrm-updates.h from kms-color.c.

Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
2022-06-07 09:35:14 +01:00
Luigi Santivetti a62bf5ff48 drm-backend: stop parsing IN_FORMATS blobs, use libdrm instead
Before this change the drm-backend in Weston did the work of parsing DRM
blobs in order to query IN_FORMATS data, if available. This is also the
case for other DRM/KMS clients that use IN_FORMATS (i.e. X).

libdrm 2.4.108 with e641e2a6 ("xf86drm: add iterator API for DRM/KMS
IN_FORMATS blobs") introduced a dedicated API for querying IN_FORMATS data.

Bump the minimum required version to 2.4.108, stop parsing IN_FORMATS in
Weston and start using DRM iterators. In addition, remove fallback code for
libdrm <2.4.107.

Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
2022-06-07 09:35:14 +01:00
Luigi Santivetti 08a821f291 gitlab-ci: build libdrm version 2.4.108 from source
libdrm with version 2.4.108 provides new functionality for parsing
IN_FORMATS blobs. Weston can make use of it and avoid implementing
its own logic. At present CI uses Debian 11 (bullseye) which comes
with an older version (2.4.104), so we build it from source.

Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
2022-06-07 09:34:54 +01:00
Derek Foreman 0f4b411091 ci: Fix cobertura syntax
This has somehow stopped working. Copied different syntax from a gitlab
example.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-06 13:56:19 -05:00
Marius Vlad 7ceda8cbba gl-renderer: Ensure gl_buffer_state is present for direct-display
This patch makes sure we have a gl_buffer_state present when using
direct-display protocol extensions (which forbids any GL imports, and
assumes a direct path with the display unit to perform a KMS import).

Without this patch we would basically have no gl_buffer_state at repaint
time because we never manged to create one, as direct-display code path
will return much early.

Partially fixes gitlab.freedesktop.org/wayland/weston/-/issues/621.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-06-03 14:46:37 +03:00
Vitaly Prosyak 0c5860fafb tests/color-shaper-matrix: add creation and usage cLUT profiles
Added cLUT profile creation to validate linearization algorithm
for DToB3 tag (direction dev to PCS). The 3DLUT is
built by using raw matrix conversion from dev to XYZ and reverse
(XYZ to device).

The test uses floating point pipeline, known as unbounded mode of LCMS.
The details are described in ICCSpecRevision_02_11_06_Float.pdf

The purpose of these new test cases is to keep the GL-renderer 3D LUT
path tested even after color-lcms and GL-renderer start using
specialized matrix-shaper paths.

These also exercise build_eotf_from_clut_profile() in color-lcms, but do
not actually verify it. These cases only test that the recovered EOTF
and its inverse produce an identity mapping together.

BT.2020 is not used in these tests, because the RGB-XYZ conversion
matrix does not stay inside [0.0, 1.0] in either direction, which would
be a problem for the 3D LUT element in the multiProcessingElement
pipelines. Handling that would have been possible, but testing with
AdobeRGB color space should suffice while keeping the test code from
being even more complicated.

roundtrip_verification() tests that we succeed in creating cms
pipelines correctly in both directions so that the resulting ICC file is
better behaved. The Weston test itself only cares about the BToD
direction.

Credits to:
Vladimir  Lachine <vladimir.lachine@amd.com>
Graeme Gill <graeme@argyllcms.com>
Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 276d1ae024 tests/color-shaper-matrix: add ref image index
This makes it easy to re-use existing reference images for further test
cases.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Vitaly Prosyak 6478859b4f tests/color-shaper-matrix: prepare for cLUT type profiles
We will want to run the same color spaces with different types of ICC
profiles. To help with that:

1. Let struct lcms_pipeline define the test color space and
   transformations and move the tolerance into a new per test case
   structure.

2. Added profile type: PTYPE_MATRIX_SHAPER, PTYPE_CLUT.
   PTYPE_MATRIX_SHAPER is the previously implemented type.

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 062b6646ff tests/color-shaper-matrix: fix realpath() leak
Found with ASan.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 5921a00b38 tests/lcms_util: add SetTextTags()
This function sets some basic text tags to make an ICC file better
formed.

The code is taken from LittleCMS, https://github.com/mm2/Little-CMS.git
git revision
lcms2.13.1-28-g6ae2e99 (6ae2e99a3535417ca5c95b602eb61fdd29d294d0)
file src/cmsvirt.c.

Suggested-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 44c3079567 tests: add lcms-util with MPE curves
This adds a new test helper library that depends on LittleCMS 2.

For starters, the library implements conversion from enum transfer_fn to
ICC multiProcessingElements compatible LittleCMS curve object.

That conversion allows encoding transfer funtions in ICC files and
LittleCMS pipelines with full float32 precision instead of forcing a
conversion to a 1D LUT which for power-type curves is surprisingly
imprecise.

This also adds CI tests to make sure the conversion matches our
hand-coded transfer functions.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 0225453fb1 tests/color_util: add transfer_fn_name()
This helps reporting test results, then you can print the fn by name.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 142d8e5125 tests/color_util: add RGB diff stat
These helpers allow collecting color difference statistics easily.

To be used in color-shaper-matrix-test.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen c76e4abb60 tests/color_util: add lcmsMAT3_invert()
Needed to invert device-to-PCS color transformation matrices.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 141cd3021e tests/color_util: add transfer_fn_invert()
When defining a color space with a transfer function, this looks up the
inverse transfer function without needing to store that separately.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen fa477d2407 tests/color_util: add TRANSFER_FN_IDENTITY
This will be useful to make a curve in a color pipeline pass-through
without needing to special-case skipping the curve.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 6fa7ab5d5f tests/color_util: prettify arr_curves
Fix up whitespace and document what this array is for.

For the sake of slightly better readability.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 8adbd3d802 tests/color_util: streamline sRGB_linearize/delinearize
Re-use color_float_apply_curve() instead of open-coding it.

Maybe makes reading the code a little easier.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 53b1268018 tests/color_util: refactor into color_float_apply_matrix()
Make process_pixel_using_pipeline() slightly easier to read by
extracting a meaningful function.

Pure refactoring, no behavioral changes.

Compared to previous, flip the scalar multiplication around, so that it
matches the mathematical order of matrix-vector multiplication.

Also document the layout conventions for lcmsVEC3 and lcmsMAT3. These
follow the convention used in LittleCMS for cmsVEC3 and cmsMAT3, and are
necessary to understand to review the matrix-vector multiplication for
correctness.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen c8195289a7 tests/color_util: refactor into color_float_apply_curve()
Make process_pixel_using_pipeline() slightly easier to read by
extracting a meaningful function.

Pure refactoring, no changes.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 85738af912 tests/color_util: protect header from re-reading
Looks like this was forgotten, and I managed to get compiler errors
about redeclaring all enums.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 7fa9b15348 build: consolidate lcms2 dependencies
It's bad form to set the same variable in multiple places, and not all
of them were even equivalent.

Move lcms2 finding to the root level build file only. It is still an
optional dependency like before, and the if-not-found checks are still
in place where actually needed.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 10:22:25 +00:00
Pekka Paalanen 6234cb98d1 gl-renderer: fix performance regression in frag
When color management is disabled, the fragment shader was still first
ensuring straight alpha and then immediately just going back to
pre-multiplied. This is near-impossible for a shader compiler to
optimize out, I guess because of the if-statement to handle division by
zero. Having view alpha applied in between certainly didn't make it
easier.

That causes extra fragment computations that are unnecessary. In the
issue report this was found to cause a notable performance regression.

Fix the performance regression by introducing special-case paths for
when straight alpha is not needed. This skips the unnecessary
computations.

Fixes: https://gitlab.freedesktop.org/wayland/weston/-/issues/623
Fixes: 9a6a4e7032

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-03 09:38:10 +00:00
Michael Olbrich 81912dc2a6 compositor: improve opacity handling for scaled surfaces
Currently, the opaque is discarded for all transformations other than a simple
translation, because correctly transforming the opaque area is not possible in
general.
However, there is one simple case that is probably the most common one: A fully
opaque surface that is translated and scaled. In this case the opaque area is
simply the new bounding box. So set the transformed opaque area accordingly.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-03 08:19:29 +00:00
Michael Olbrich e2426960d4 compositor: set transform.opaque for surfaces without alpha channel
If surface->is_opaque is set then we can assume that the whole surface is
opaque. In the trivial case (no transformation or translation only) this means
that transform.boundingbox is exactly the view area and is fully opaque. So it
can be used for transform.opaque.

This is important because damage calculation uses transform.opaque. Without
this, anything underneath a surface without an explicit opaque region but a
pixel format without alpha channel is drawn unnecessarily.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-06-03 08:19:29 +00:00
Michael Tretter dfceb60274 backend-drm: explicitly pass device to initialization
The drm_device is initialized as a side effect of the (badly named)
drm_device_is_kms function. Explicitly pass the drm_device to be able to
initialize kms devices that are not the main drm device of the drm backend.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:18:12 +02:00
Michael Tretter deebfd99e3 backend-drm: get the drm device from the output
If we have multiple drm devices, we cannot use the drm device from the backend,
because we would only get the primary device and not the device of the output.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:17:49 +02:00
Michael Tretter 6e36787dfd backend-drm: handle hotplug events per drm device
If Weston receives a hotplug event, it has to check if the hotplug device
actually belongs to the drm device before updating the heads of the device. The
hotplug event should only remove heads that belong to the device and must not
change heads of other devices.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:17:32 +02:00
Michael Tretter d990c6a939 backend-drm: ignore heads from other devices
The compositor lists the heads from all devices, but we must only disable the
connectors that belong to the current device. Therefore, other heads must be
ignored.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:17:16 +02:00
Michael Tretter 345e705e33 backend-drm: move drm objects from backend to drm device
The outputs, heads, crtcs, and connectors are specific to a drm device and not
the backend in general.

Link them to the device that they belong to to be able to retrieve the
respective device.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:17:15 +02:00
Michael Tretter c4685d9463 backend-drm: attach device to pending state
The commits happen per device instead of per backend. The pending state is
therefore per device as well. Allow to retrieve the device from the pending
state.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:14:11 +02:00
Michael Tretter 615a37dc88 backend-drm: make dma-buf feedback device specific
The scanout format for the dma-buf feedback are specific to the kms device that
is used for scanout. Therefore, we have to pass the device of the output when
retrieving the scanout formats.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:13:55 +02:00
Michael Tretter 101c0f6b8b backend-drm: get the fb using the device instead of the backend
The fbs are specific to the device on which they will be displayed. Therefore,
we have to tell which device shall be used when we are creating the fb.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:13:40 +02:00
Michael Tretter d89fcf10cb backend-drm: pass device through atomic commit handler
The atomic commit is device specific. If we have multiple kms devices, we need
to know which device was used for the atomic commit.

Pass the device instead of the backend through the atomic commit.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:13:23 +02:00
Michael Tretter 0d967bd7f4 backend-drm: extract device from backend
Extract the kms device from the backend to allow a better separation of the
backend and the kms device. This will allow to handle multiple kms devices with
a single drm backend.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:12:57 +02:00
Michael Tretter 2860933ded backend-drm: cleanup debugging
Get the backend at the beginning of the function instead of retrieving it from
another object in the debug statement. This simplifies refactoring, as the debug
statement is not affected by changes how the backend is retrieved.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:04:29 +02:00
Michael Tretter 00b74293e8 backend-drm: use pixel format to print gbm format
The gbm_format is the same as the drm format used by the pixel format.

Print the format name using the pixel format in the error message to make the
error message easier to understand for humans.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:04:29 +02:00
Michael Olbrich 83d1eafd81 backend-drm: virtual: use the DRM fd from the fb
The fb already contains a DRM fd for later use. So just use that one instead of
fetching it from the backend.

This is necessary if the fbs are allocated on different devices, since otherwise
the wrong device might be used to get the fd of the passed fb.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-06-03 09:04:29 +02:00
Derek Foreman c0cafde80f drm: Remove destroy listener from list when fired
Looks like we missed this one during the conversion to
weston_signal_emit_mutable.

Found by running weston under valgrind and running/killing
weston-simple-dmabuf-egl

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-03 09:58:09 +03:00
Derek Foreman cc924e8131 libweston-desktop/xwayland: Use correct geometry
Looks like a copy and paste error.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-06-03 09:53:26 +03:00
Pekka Paalanen fb7b1a4125 Revert "build: add test-gl-renderer option"
This reverts commit 1618697dc3.

The original commit was a workaround for
https://gitlab.freedesktop.org/mesa/mesa/-/issues/2219 which was fixed
in Mesa:
- c7617d8908a970124321ce731b43d5996c3c5775 released as 20.1.0-rc1
- a0e6341fe4417e41cda0b19e4fa7f8bbe4e1dba1 released as 19.3.5
- f27e5d9df5bc9c85d45c2cb1f2a4997b453365fe released as 20.0.0

This workaround should not be necessary anymore, we don't use it in our
CI, and it was manual to begin with. Therefore remove it.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-02 08:37:36 +00:00
Hideyuki Nagase 8508f93f2b rdp: Update cursor position on most mouse messages
The RDP spec says we can trust x, y position on all messages except
PTR_FLAGS_WHEEL and PTR_FLAGS_HWHEEL, so let's do that to ensure
proper sync with the RDP client.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-06-01 12:16:37 +00:00
Pekka Paalanen ee085015d0 build: drop unused option rdp-thread-check
Clean up leftovers from 2df71c6dd7.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-06-01 14:40:44 +03:00
Marius Vlad b0257e0ffc backend-drm: Add GBM_BO_HANDLE as a failure reason
And use it to get a feedback event for when adding scanout tranche.

With this change, I get back a feedback event for dmabuf-feedback
on VC4:

���� tranche: target device /dev/dri/card0, scanout
�   ���� format ABGR2101010, modifier LINEAR (0x0)
�   ���� format XBGR2101010, modifier LINEAR (0x0)
�   ���� format ARGB8888, modifier LINEAR (0x0)
�   ���� format ABGR8888, modifier LINEAR (0x0)
�   ���� format XRGB8888, modifier LINEAR (0x0)
�   ���� format XBGR8888, modifier LINEAR (0x0)
�   ���� format RGB565, modifier LINEAR (0x0)
�   ���� format YUV420, modifier LINEAR (0x0)
�   ���� format YUV422, modifier LINEAR (0x0)
�   ���� format YVU420, modifier LINEAR (0x0)
�   ���� format YVU422, modifier LINEAR (0x0)
�   ���� format NV12, modifier LINEAR (0x0)
�   ���� format NV12, modifier BROADCOM_SAND128 (0x700000000000004)
�   ���� format NV16, modifier LINEAR (0x0)
�   ���� end of tranche

Besides that, it can place a fullscreen state of simple-egl on the
primary plane, which without this change wasn't possible.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-06-01 07:38:17 +00:00
Derek Foreman aa507417c2 xwm: Fix pasting in some cases
I guess this reverts commit 73bdc0ce85
"xwm: Fix fd leak in weston_wm_send_data()"

That commit closes the send half of a pipe in weston_wm_send_data,
claiming that it's dup()licated later, and we'll leak the fd if
we don't close it.

That may have been true at the time? But currently that fd is only
duplicated by wl_event_loop_add_fd() in its normal operation, and
closing our original before that fd handler ever fires results
in an EBADF on write, and the data never reaching its intended
destination.

Worse, by the time that handler is called there might be another
use for that fd, and we could push data into it and close it.

To provoke the problem, launch an app like FireFox over Xwayland,
cut something to the clipboard, then close the app (this is the
path where the wm has stored the clipboard contents and the
app has gone away). relaunch it and paste the clipboard content
back in. clipboard_client_data() will EBADF on write, and the
data won't be pasted.

Reported-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-05-31 17:57:03 +00:00
Pekka Paalanen 892421a93e tests: add matrix-test for CI
This a new matrix inversion test written from scratch to be suitable for
running in CI: quick to run and automatically detects success/failure.

This all is a result of what I learnt while working on
https://gitlab.freedesktop.org/pq/fourbyfour

Computing the residual error with infinity norm comes straight from
fourbyfour documentation on how to evaluate matrix inversion error.

Most of the hard-coded test matrices have been generated with fourbyfour
project as well, as it contains the generator code. The matrices are
hard-coded here also to make testing faster, but primarily because the
generator code needs BLAS and LAPACK, and having those as Weston
dependencies would be far too much just for this.

Now, if someone wants to modify weston_matrix stuff, we should at least
detect matrix inversion and multiplication bugs.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-31 12:26:09 +00:00
Pekka Paalanen 8bbd1a995b libweston: remove UNIT_TEST
This #define was used only by the matrix-test program, which was removed
in the previous commit.

Remove it as unused and fold away MATRIX_TEST_EXPORT.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-31 12:26:09 +00:00
Pekka Paalanen a1e5d46d91 tests: delete the manual matrix-test
This test program was useful a decade ago when weston_matrix_invert()
was being developed. It was a manual test program that ran for a certain
number of seconds and required human interpretation of numbers to see if
results were acceptable or not. Hence it was foundamentally unsuitable
for CI.

The way it generated random matrices for inversion testing was also very
naive, and it used the determinant value to determine invertability
which is completely bogus. This made it also a bad test for correctness.

Much better speed and correctness testing is implemented in

    https://gitlab.freedesktop.org/pq/fourbyfour

with documented testing procedures. It has a copy of the weston_matrix
implementation.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-31 12:26:09 +00:00
Robert Mader 62ab6891db clients/simple-egl: Handle buffer scale and transform
Buffer scale is common enough in the modern desktop space to
expect average GL clients to handle it. Thus lets include it into
our main example client.

While on it, also handle buffer transforms. It's essentially free
for GL clients in terms of computing power but may increase the
chance that Wayland compositors are able to hit scanout fast paths.
Thus having an example client for it is likely valueabel for client
and compositor developers.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-31 12:08:06 +00:00
Robert Mader 0b2369bb4a clients/simple-egl: Rename geometry to buffer_size
To reflect more clearly that we use it for `wl_buffer` coordinates.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-31 12:08:06 +00:00
Robert Mader 009625c297 clients/simple-egl: Rename buffer_size to buffer_bpp
`buffer_size` usually refers to `wl_buffer` size in the Wayland world.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-31 12:08:06 +00:00
Robert Mader 4090f0eb6f clients/simple-egl: Use INT32_MAX for opaque region
Setting the opaque region correctly is common source of error for
clients that simply want to express that a whole surface is opaque.
This is especially true once buffer_scale and buffer_transform come
into play, as unlike for damage, where buffer_damage is the
encouraged and user friendly way today, opaque regions are always
in logical coordinates.

As faulty opaque regions don't have a visual impact in these cases
but only increase resource consumption, these errors often remain
for long times. See
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/1e2bc681712d62081f49e8e74723a596d1578a34
for one of many examples.

Give an easy example how to set the opaque region in a conformant
and reliable way.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-31 12:08:06 +00:00
Pekka Paalanen e67a0cb57c gl-renderer: fix double-alloc of gl_buffer_state
Obviously the first allocation is always leaked, there is a second
zalloc() right below. Fix the leak.

Found by code inspection.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-31 13:08:01 +03:00
Marius Vlad 7412a01437 backend-drm: Retrieve reason if dmabuf import failed
As we could have situations where dmabuf import failed when attempting
to figure it the framebuffer is scanout-capable, make sure we also have
a way to store that information. Otherwise, we could end up
NULL-dereferencing, as we don't provide a valid storage for it.

Further more, with this, we also print out the reason why it failed, to
aid in further debugging.

Observed on platforms where GBM_BO_HANDLE failed + in combination w/
direct-display proto extension.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-30 16:22:35 +03:00
Pekka Paalanen 8ebebb20ef drm-backend: add color_outcome / HDR metadata serial
Output color profile may be changed in flight. Output basic color
characteristics and EOTF mode cannot yet be changed in flight, but it is
reasonable to assume they could in the future. Therefore the color
outcome data may change in flight as well, which is the basis for HDR
metadata, which needs to be updated as well.

Track the changes to color outcome data with a serial number.
DRM-backend checks the serial number to see if it needs to re-create the
HDR metadata blob. This allows the changes to propagate all the way to
KMS.

The code added here is more of a reminder of what should happen than a
tested path.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen c217453c85 backend-drm: forward HDR metadata
Forward the HDR Static Metadata Type 1 to the video sink. This makes the
sink aware of our video content parameters and may be able to produce a
better picture. This type of metadata is used only with the ST 2084 HDR
mode a.k.a PQ.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen c4fedd503f backend-drm: move code to kms-color.c
This creates a new file for KMS related color code, to avoid making
drm.c even longer.

The moved code was just added in 5151f9fe9e
so the new file copyrights are written based on that.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen ccb4c383d7 tests: add color-metadata-errors test
'color_characteristics_config_error' test ensures that all code paths in
parse_color_characteristics() and wet_output_set_color_characteristics()
get exercised.  The return value and logged error messages are checked.

Other cases test the weston_hdr_metadata_type1 validation.

These are for the sake of test coverage, but also an example of how to
test a function from main.c, and how to capture messages from
weston_log().

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen e13e64c4e0 tests: add color-metadata-parsing
Check that weston.ini settings to eotf-mode and basic color
characteristics are correctly parsed.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen e108c1a2fe color-lcms: color characteristics into HDR metadata
This is the beginnings of creating composited content HDR metadata for
the ST2084 HDR mode. The immediate goal is to allow essentially setting
the HDR metadata from weston.ini, so that it can be experimented with.

Setting an output ICC profile will stop weston.ini metadata from taking
effect, but using an ICC profile in HDR mode is an open question anyway.

maxDML, maxCLL, and minDML are set based on the assumption that we want
to make use of the full sink/monitor dynamic range.

This also adds several TODOs about how we should handle output profiles,
basic output color characteristics, and HDR metadata. Implementing these
properly will take more thought and effort.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen cea53a90d4 libweston: add HDR metadata to weston_output
This adds hdr_meta field in weston_output_color_outcome. This field is
intended to be set by color manager modules, and read by backends which
will send the information to the video sink in SMPTE ST 2084 mode a.k.a
Perceptual Quantizer HDR system.

Such metadata is essential in ST 2084 mode for the video sink to produce
a good picture.

The validation of the data and the group split is based on the HDR
Static Metata Type 1 definition in CTA-861-G specification.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen 518d72a37b compositor: add color_characteristics weston.ini option
This adds an option to program basic display color characteristics from
weston.ini. In the future there will be a way to set this information
from EDID, but because EDID is unreliable that will probably not be the
default. An ICC profile will likely override most or all of this. The
main reason to add this option is to be able to characterise HDR
monitors.

An 'output' section can have a key 'color_characteristics' (string)
set to a name. The name refers to any 'color_characteristics' section
with 'name' set to the same string.

The 'name' key of a 'color_characteristics' section cannot contain a
colon ':'. Names with colon in 'output' section key
'color_characteristics' value are reserved for future use, e.g. to
indicate that the metadata is to be taken from EDID instead of a
weston.ini section.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Pekka Paalanen 3696d9b6a1 libweston: add basic output color characteristics API
This adds color_chracteristics field in weston_output. This field is
intended to be set by compositor frontends and read by color managers.
Color managers can use this information when choosing the output color
space and dynamic range, particularly when no ICC profile has been set.

This is most useful for HDR outputs, where the HDR static metadata for
PQ mode or the display luminance parameters for HLG mode can be based on
color_characteristics.

The fields of weston_color_characteristics mirror the information
available in EDID. However, using EDID information as-is has several
caveats, so the decision to use EDID for this is left for the frontend
and ultimately to the end user.

There are no defined ranges or validity checks for this data. The color
manager will have to validate the values against whatever it is using
them for.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-27 10:30:35 +00:00
Derek Foreman c8db957a0b rdp: Add audio support
Allow the front end to register audio setup and teardown functions. These
functions should use FreeRDP's rdpsnd_server_context or
audin_server_context and set up their own handler threads.

The backend remains mostly ignorant to any audio details beyond setting up
and tearing down.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-05-26 19:06:19 +00:00
Derek Foreman f8ca784737 rdp: Fix some accidental style errors in new clipboard code
I missed a few things when this was initially merged.

No functional changes.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-05-26 12:43:18 -05:00
Derek Foreman 2df71c6dd7 rdp: Make thread checks unconfigurable
Instead of a meson option or hidden define, just run these checks always.

It is not Weston's style to add build options for specific asserts, and
currently weston's codebase is expected to always run with asserts
enabled.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-05-24 07:29:45 -05:00
Robert Mader 572ad2d8a9 clients/simple-dmabuf-*: Use gbm_bo_create_with_modifiers2
It is used in Mesa. Lets switch to it as well in order to provide
good examples and encourage proper API usage.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-23 13:25:34 +00:00
Robert Mader 46a6b5b448 clients/simple-dmabuf-feedback: Support multi-tranche feedbacks
Compositors may choose to send multiple scanout or non-scanout
tranches. So instead of assuming that the first respective tranche
contains the format/modifier we're looking for, check all tranches.

While on it, make sure that in case a compositor sends scanout
tranches on the initial feedback, `pick_format_from_scanout_tranche()`
does not unintentionally pick `INITIAL_BUFFER_FORMAT`.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-23 13:21:38 +00:00
Daniel Stone a55bd6798e clients: Delete gears
It doesn't and can't build, because it depends on cairo-gl. We already
have simple-egl which shows how to use EGL/GLESv2 on Wayland.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-23 13:45:57 +01:00
Daniel Stone dfaba9f107 gl-renderer: Use common value for maximum plane index
Most everything else only supports 3 planes, and we don't support any
four-plane YUV formats, so.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone c3d84293b9 gl-renderer: Fix plane count for legacy YUV420 images
It's three planes, not two.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Fixes: 8b167a1703 ("gl-renderer: Store EGL buffer state in weston_buffer")
2022-05-20 11:24:41 +00:00
Daniel Stone f36d77a199 gl-renderer: Don't use TEXTURE_EXTERNAL for multi-planar formats
There's just no good reason to do this.

The query entrypoints already tell us if we need to use
GL_TEXTURE_EXTERNAL_OES for a particular format/modifier. We also have
RGB -> YUV fallbacks which should be able to work well with TEXTURE_2D.

TEXTURE_EXTERNAL pessimises quite hard, forcing GPU-side reloads as well
as bad filtering. Allowing multi-planar formats to use TEXTURE_2D should
thus result in performance and quality improvements.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 67fc71214d gl-renderer: Add comment for yuv_format_descriptor
Try to describe this and yuv_plane_descriptor as well, since they're not
blindingly obvious.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 18a31a6af8 gl-renderer: Remove special-cased YUV SHM formats
Now that we can pull everything we need from pixel-formats, go one step
further and reuse the same YUV format descriptors we use to emulate
dmabuf/EGLImage imports for SHM.

This eliminates all special-case YUV/SHM handling.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 1a86963d51 gl-renderer: Get YUV subsampling from pixel-formats
We already have the subsampling levels in pixel-formats - no need to
type it out again here.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 1654813903 gl-renderer: Get YUV plane count from pixel-formats
We already have this elsewhere.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 727c4ef6fb pixel-formats: Add R8 and GR88
These formats are used within gl-renderer to do YUV -> RGB colourspace
conversion.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 1db2fbef61 pixel-formats: Add internal-only format flag
Add a new hide_from_clients flag which, if set, specifies that the
format is only for internal information and processing, and should not
be advertised for clients.

This will be used for formats like R8 and GR88, which are not useful for
client buffers, but are used internally to implement YUV -> RGB
conversion.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 32ee42d261 gl-renderer: Remove useless texture_type enum
This was just a duplicate of shader variants, for historical reasons.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 820f3ae866 gl-renderer: Add support for WL_SHM_FORMAT_YUV444
We support this as an explicit YUV fallback path in gl-renderer's dmabuf
EGLImage import path, so might as well support it in the SHM path, given
it's just YUV420 with no subsampling.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone c2cfadfce9 gl-renderer: Use hsub and vsub from pixel-formats
No need to open-code everything here.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 742f10f32c gl-renderer: Use vsub for y offset in SHM
If we're doing partial uploads from SHM buffers, we need to use the
vertical subsampling factor rather than the horizontal for secondary
planes.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 4161948da9 pixel-formats: Add hsub and vsub helpers
We already had these with effective width and height, but they're useful
externally as well. Pull them out to a helper.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone e08df66bd3 gl-renderer: Use pixel-formats data for RGB formats
No need to open-code bits per pixel and shader variants.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 2ade128ae2 pixel-formats: Fill in bpp everywhere
Doing this allows us to get rid of some open-coded per-format
calculations inside gl-renderer.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone c54eace91d pixel-formats: Rename addfb_legacy_depth
'depth' isn't actually used to determine the bit depth of meaningful
components generally, but specifically to determine whether we can use
the legacy drmModeAddFB (pre-AddFB2) with those formats.

Rename the member to make it more clear what it's used for.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone d37d73a9a0 gl-renderer: Use DRM format codes instead of SHM
Since the buffer now has a pixel_format hook, just use that consistently
instead of the SHM code.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 2c40260397 gl-renderer: Remove unsupported-SHM-format fallback
Clients can't reach this because libwayland-server already checks
whether the format is supported.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone badd774c28 gl-renderer: Use pixel-formats GL format for single-planar formats
pixel-formats already stores the gl_format, at least for single-planar
formats; use that instead of storing our own copies.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 38f933dd46 gl-renderer: Move GL compatibility workarounds out of per-format
Instead of checking for each format whether we need compatibility
workarounds for GL implementations not supporting ES3.x or when
GL_EXT_texture_rg isn't present, have each format declare the ideal case
and fix it up later.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 2e6827d70e gl-renderer: Ensure SHM buffer format stays the same
Rather than checking all the pixel-format components which are currently
duplicated inside gl-renderer, just check for equality of the pixel
format itself, which will become useful as we remove some of the
duplicate content.

This means that the texture storage will now be reallocated when clients
switch between pixel formats which could've had compatible GL storage
(e.g. XRGB <-> ARGB) on the same surface. However this does not seem
like a case worth optimising, and simplifies the code somewhat.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone d696f8df1f gl-renderer: Use ARRAY_COPY for buffer state
We've got a nice shiny ARRAY_COPY macro, so use it rather than memcpy or
hand-unrolled assignments.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Daniel Stone 89d0d90306 pixel-formats: Add GL types for 16bpc formats
Carried over from gl-renderer's equivalent code.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-20 11:24:41 +00:00
Hideyuki Nagase 297ad403d6 rdp: Add clipboard redirection support
Allow clipboard pasting in and out of an RDP session.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-05-19 14:31:59 +00:00
Hideyuki Nagase 252771d9aa rdp: add virtual channel support
RDP exposes certain features (audio, clipboard, RAIL) through a facility
called "virtual channels". Set up the communications framework for using
these.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-05-19 14:31:59 +00:00
Hideyuki Nagase 3bdc29b934 rdp: Add cross thread work queues
FreeRDP has some features that start new threads and run
callback functions in them.

We need a way to punt work from these threads back to the
compositor thread.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-05-19 14:31:59 +00:00
Pekka Paalanen e884e7c7b8 gl_renderer: log EGL features
Log EGL features similar to how GL ES features are logged: listing just
the ones weston tests for.

This replaces some log messages from gl-renderer.c that become
redundant or belong with EGL better.

has_native_fence_sync and has_wait_sync are not logged, because missing
them already logs warnings.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 14:18:53 +03:00
Pekka Paalanen 2f115047de gl-renderer: log rendering device
Feels like this might be nice to log.

The failure case is not fatal, so say it's a warning only.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 14:18:53 +03:00
Pekka Paalanen f3bf7a0d5a gl-renderer: add error messages for missing EGL platforms
Found by inspection, looks like these cases could use an explicit error
message.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 14:18:53 +03:00
Pekka Paalanen b383f52d31 gl_renderer: print more GL ES feature flags
This is a human readable replacement for printing out the list of all
available GL extensions that doesn't happen anymore by default.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 14:18:53 +03:00
Pekka Paalanen 092115786e gl-renderer: move extension lists away from log
Print all EGL and OpenGL extension lists into a new log scope
"gl-renderer" instead of the usual log.

These lists cluttered the log while they were very rarely actually
useful. Sometimes they might be interesting, so make them still
available through the new log scope.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 13:45:53 +03:00
Pekka Paalanen ccb0d4f7ce gl-renderer: pass gr to gl_renderer_log_extensions()
Plumb struct gl_renderer all the way through to
gl_renderer_log_extensions(). In the future, the extension lists will be
printed into a debug scope specifically, and it will get the debug scope
from gr.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-18 13:45:53 +03:00
Marius Vlad 2327daf96b desktop-shell: Handle weston_curtain destruction
This fixes the following leaks for
weston_curtain/weston_buffer_create_solid_rgba when shutting down the
compositor:

        #0 0x7f9170372987 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f915bfeb8b7 in zalloc ../include/libweston/zalloc.h:38
        #2 0x7f915bfec71d in weston_curtain_create ../shell-utils/shell-utils.c:150
        #3 0x7f915bfd9e51 in shell_ensure_fullscreen_black_view ../desktop-shell/shell.c:2082
        #4 0x7f915bfda2a9 in shell_configure_fullscreen ../desktop-shell/shell.c:2118
        #5 0x7f915bfdc72d in desktop_surface_committed ../desktop-shell/shell.c:2538
        #6 0x7f915bfa3ef5 in weston_desktop_api_committed ../libweston-desktop/libweston-desktop.c:159
        #7 0x7f915bfae778 in weston_desktop_xdg_toplevel_committed ../libweston-desktop/xdg-shell.c:746
        #8 0x7f915bfb0d45 in weston_desktop_xdg_surface_committed ../libweston-desktop/xdg-shell.c:1374
        #9 0x7f915bfa7382 in weston_desktop_surface_surface_committed ../libweston-desktop/surface.c:174
        #10 0x7f916fe628a6 in wl_signal_emit /home/mvlad/install-amd64/include/wayland-server-core.h:481
        #11 0x7f916fe7c0e2 in weston_surface_commit_state ../libweston/compositor.c:4062
        #12 0x7f916fe7c161 in weston_surface_commit ../libweston/compositor.c:4068
        #13 0x7f916fe7c6ef in surface_commit ../libweston/compositor.c:4146
        #14 0x7f916fc847e9  (/usr/lib/x86_64-linux-gnu/libffi.so.8+0x77e9)

        #0 0x7f9170372987 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
        #1 0x7f916fe62aa3 in zalloc ../include/libweston/zalloc.h:38
        #2 0x7f916fe7398d in weston_buffer_create_solid_rgba ../libweston/compositor.c:2603
        #3 0x7f915bfec879 in weston_curtain_create ../shell-utils/shell-utils.c:162
        #4 0x7f915bfd9e51 in shell_ensure_fullscreen_black_view ../desktop-shell/shell.c:2082
        #5 0x7f915bfda2a9 in shell_configure_fullscreen ../desktop-shell/shell.c:2118
        #6 0x7f915bfdc72d in desktop_surface_committed ../desktop-shell/shell.c:2538
        #7 0x7f915bfa3ef5 in weston_desktop_api_committed ../libweston-desktop/libweston-desktop.c:159
        #8 0x7f915bfae778 in weston_desktop_xdg_toplevel_committed ../libweston-desktop/xdg-shell.c:746
        #9 0x7f915bfb0d45 in weston_desktop_xdg_surface_committed ../libweston-desktop/xdg-shell.c:1374
        #10 0x7f915bfa7382 in weston_desktop_surface_surface_committed ../libweston-desktop/surface.c:174
        #11 0x7f916fe628a6 in wl_signal_emit /home/mvlad/install-amd64/include/wayland-server-core.h:481
        #12 0x7f916fe7c0e2 in weston_surface_commit_state ../libweston/compositor.c:4062
        #13 0x7f916fe7c161 in weston_surface_commit ../libweston/compositor.c:4068
        #14 0x7f916fe7c6ef in surface_commit ../libweston/compositor.c:4146
        #15 0x7f916fc847e9  (/usr/lib/x86_64-linux-gnu/libffi.so.8+0x77e9)

We do not migrate the weston_curtain destruction from
desktop_surface_removed() to desktop_shell_destroy_surface() because
we'd want have the curtain removed before the animation starts.

If we were to move the black view destruction, *and* only handle it from
desktop_shell_destroy_surface() the animation runs but the black curtain
will be removed right at the end, effectively diminishing the effect of
the animations.

To this end, we keep both of the two worlds, if the client terminates on
its own, we keep the same animation effect, but if the compositor is
shutting down we destroy it immediately.

We remove wl_list_for_each_safe() and instead loop each time to avoid
using a stale pointer iterator which could cause a UAF as the shsurf
would be free'ed.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-18 09:46:37 +03:00
Daniel Stone 4815936630 gl-renderer: Allocate textures per-buffer, not per-surface
Now that the gl_buffer_state owns everything related to buffers, move
the textures from there rather than living on the surface, to join the
EGLImage and/or SHM params.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 62c0f1621c gl-renderer: Delete egl_image wrapper
Now that EGLImages are strongly associated with a gl_buffer_state, which
has a lifetime strictly bounded by a weston_buffer, we don't need to
have an egl_image wrapper having its own separate refcounting anymore.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 3297d10287 gl-renderer: Cache gl_buffer_state on the weston_buffer
... apart from SHM.

EGL and dmabuf buffers already have a gl_buffer_state created for them
when we first attach the weston_buffer. By turning
gl_surface_state::buffer into a pointer, we can just reference rather
than inline the gl_buffer_state.

SHM buffers are special, in that we don't keep individual copies of them
within the GL renderer. Instead, the GL surface has a texture allocated
with a shadow copy of the most up-to-date surface content. Handle this
by allocating and destroying gl_buffer_state every time we need to
respecify textures or somehow meaningfully change the parameters.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone acc3762506 gl-renderer: Store dmabuf buffer state in weston_buffer
Similarly to EGL buffers, store the gl_buffer_state for a dmabuf buffer
inside weston_buffer, rather than on the linux_dmabuf_buffer. This
slightly simplifies our gl_buffer_state handling, and will be used later
to eliminate the egl_image refcounting.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 56dc4b8aaa gl-renderer: Remove unused dmabuf import_type
We don't need this now we don't try to reimport them on attach.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 8b167a1703 gl-renderer: Store EGL buffer state in weston_buffer
Introduce a renderer_private hook for weston_buffer, and use this to
store a copy of the gl_buffer_state for EGL buffers (i.e. non-dmabuf, via
EGL_WL_bind_wayland_display).

As part of this, we create the EGLImage along with the weston_buffer
information, and just take a reference to it each time it is attached.
If you have bisected a failure to update surface content to this commit,
it very likely means that your EGL implementation requires images to be
recreated rather than only rebound in order to have their content
updated, which is contrary to specification.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 8544a4d09b weston_buffer: Move direct_display out of gl-renderer
Just make it a generic buffer attribute, not hidden away in GL.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 57c34139d3 gl-renderer: Don't modify buffer_state in attach
At the moment, attach_shm() will modify the gl_buffer_state in place,
then compare it and see if it differs enough to require a new one. That
rather mixes up the old and new worlds, so quite explicitly build up a
shadow gl_buffer_state with variables first before we change the one
which already exists.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone c9253c0012 renderer: Set surface->is_opaque in the core
No need for the renderers to do this now that we know what all of the
formats are.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:42 +01:00
Daniel Stone 193de3c2cf renderer: Remove get_content_size hook
Now that we can reliably access buffer dimensions from weston_buffer,
and gl-renderer isn't doing strange things with buffer widths, just use
that. The renderer interface is now unused and can be deleted.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:41 +01:00
Daniel Stone 21c65d7c9b gl-renderer: Remove gl_buffer_state.buffer_type
We can just get this from the weston_buffer.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:25 +01:00
Daniel Stone 5fdb5fdd90 gl-renderer: Don't match texture width to input pitch
This was only used for what was presumably an attempt at an
optimisation, to force the texture's pitch in pixels to match the SHM
buffer. This is really unlikely to have ever made a difference, given
the alignments GPUs demand.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 907c9d1ffd gl-renderer: Clarify comment
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 90dbf4522d gl-renderer: Remove gl_buffer_state.y_inverted
It's just a shadow of weston_buffer.buffer_origin, which also has a
slightly more descriptive name.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone c6af9c8581 gl-renderer: Remove gl_buffer_state.height
Low-hanging fruit: just get this from the weston_buffer.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 70874428d6 gl-renderer: Make attach_shm return early on cache hit
If we can reuse the textures we already have, just return early, rather
than putting all the work in a large indented body.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 1a65c1b8b1 gl-renderer: Shift buffer reference later in attach
Allow the various attach handlers to access the existing buffer, only
referencing the new buffer when they have successfully attached.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 77e1a04220 gl-renderer: Remove extraneous parameters from attach
The handlers can chase the details of the buffers themselves.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 0cdf576c92 gl-renderer: Convert attach to flat-return style
Deduplicate the no-buffer and the import-fail case, and try to fall
through where we can. This will make it easier to shift the buffer
reference change later, so the attach subhandlers can reference the old
buffer when checking for compatibility.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 428ae215e8 gl-renderer: Add return value to attach handlers
It's good to know if we succeeded or failed to import our buffers. This
will also later make for a more smooth transition when we start
returning a gl_buffer_state from them.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone bb624754f1 gl-renderer: Don't leak EGLImages on import fail
This only happens for the legacy renderer, but still, might as well
clean up after ourselves when we can't import a secondary plane.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 4519461439 gl-renderer: Move EGL buffer error checks into attach_egl
Makes it more consistent with the others, and also easier to return
success/fail.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 8f56743590 gl-renderer: Change surface_set_color to attach_solid
No functional change.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 72fc647a96 gl-renderer: Split buffer state away from surface state
gl_surface_state has a bunch of members which are tied to the input
buffer, rather than the surface per se.

Split them out into a separate gl_buffer_state member as a first step
towards sanitising its use and lifetime.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Daniel Stone 0c65b23848 libweston: Move renderer interface to internal header
No-one should be implementing an external renderer, so move the
interface out of the public header.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-05-16 13:51:00 +01:00
Robert Mader 564828fb96 rdp: Silence compiler warning
This value is always `NULL`.

Silences:
`warning: ‘%s’ directive argument is null [-Wformat-overflow=]`

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-16 09:41:29 +00:00
Robert Mader 2a2eeb6a33 libweston: Silence compiler warning
Silences:
`warning: ‘fourcc’ may be used uninitialized [-Wmaybe-uninitialized]`

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-16 09:41:29 +00:00
Marius Vlad ab42159bf3 desktop-shell: Add missing weston_view_destroy()
This fixes the following weston_view leak at compositor shutdown:

    #0 0x7f4250247987 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
    #1 0x7f424fd37aa3 in zalloc ../include/libweston/zalloc.h:38
    #2 0x7f424fd3a05f in weston_view_create ../libweston/compositor.c:386
    #3 0x7f423be7be6a in weston_desktop_surface_create_desktop_view ../libweston-desktop/surface.c:364
    #4 0x7f423be7c0a8 in weston_desktop_surface_create_view ../libweston-desktop/surface.c:404
    #5 0x7f423beae91d in desktop_surface_added ../desktop-shell/shell.c:2273
    #6 0x7f423be77db1 in weston_desktop_api_surface_added ../libweston-desktop/libweston-desktop.c:138
    #7 0x7f423be80c73 in weston_desktop_xdg_toplevel_ensure_added ../libweston-desktop/xdg-shell.c:362
    #8 0x7f423be8207a in weston_desktop_xdg_toplevel_committed ../libweston-desktop/xdg-shell.c:697
    #9 0x7f423be84d45 in weston_desktop_xdg_surface_committed ../libweston-desktop/xdg-shell.c:1374
    #10 0x7f423be7b382 in weston_desktop_surface_surface_committed ../libweston-desktop/surface.c:174
    #11 0x7f424fd378a6 in wl_signal_emit /home/mvlad/install-amd64/include/wayland-server-core.h:481
    #12 0x7f424fd510e2 in weston_surface_commit_state ../libweston/compositor.c:4062
    #13 0x7f424fd51161 in weston_surface_commit ../libweston/compositor.c:4068
    #14 0x7f424fd516ef in surface_commit ../libweston/compositor.c:4146
    #15 0x7f424fb597e9  (/usr/lib/x86_64-linux-gnu/libffi.so.8+0x77e9)

With commit 'libweston, desktop-shell: Add a wrapper for weston_surface
reference' we've removed an explicit weston_view_destroy() call due to a
UAF which would've happen if we had close animations enabled, upon
terminating a client. In that patch I've incorrectly wrote this happened
when animations are off, but in fact it happened when they're on, see the
following trace:

READ of size 8 at 0x616000026498 thread T0
    #0 0x7f757fba8797 in weston_signal_emit_mutable ../shared/signal.c:52
    #1 0x7f757fb4bba1 in weston_view_destroy ../libweston/compositor.c:2269
    #2 0x7f756bca89c0 in desktop_shell_destroy_surface ../desktop-shell/shell.c:275
    #3 0x7f756bcb379e in fade_out_done_idle_cb ../desktop-shell/shell.c:2228
    #4 0x7f757faec1da in wl_event_loop_dispatch_idle ../src/event-loop.c:969
    #5 0x7f757faec31d in wl_event_loop_dispatch ../src/event-loop.c:1032
    #6 0x7f757faea114 in wl_display_run ../src/wayland-server.c:1408
    #7 0x7f757ff777ba in wet_main ../compositor/main.c:3589
    #8 0x55f765c8d17d in main ../compositor/executable.c:33
    #9 0x7f757fd997fc in __libc_start_main ../csu/libc-start.c:332
    #10 0x55f765c8d099 in _start (/home/mvlad/install-amd64/bin/weston+0x1099)

0x616000026498 is located 24 bytes inside of 608-byte region [0x616000026480,0x6160000266e0)
freed by thread T0 here:
    #0 0x7f758004c4d7 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x7f757fb4bdc8 in weston_view_destroy ../libweston/compositor.c:2295
    #2 0x7f757fb4c14d in weston_surface_unref ../libweston/compositor.c:2334
    #3 0x7f756bca898b in desktop_shell_destroy_surface ../desktop-shell/shell.c:273
    #4 0x7f756bcb379e in fade_out_done_idle_cb ../desktop-shell/shell.c:2228
    #5 0x7f757faec1da in wl_event_loop_dispatch_idle ../src/event-loop.c:969

This patch re-introduces it to avoid leaking the view upon compositor
shutdown, but it does it in tandem with weston_desktop_surface_unlink_view(),
(which was added in a later patch) and before weston_surface_unref() call.

This way we should be safe to terminate/close  clients with additional views
created by libweston-desktop (pop-ups), but also in other different situations.

Verified it in the following circumstances:

- terminating a client with close animation on
- terminating a client with close animations off
- shutting down the compositor with clients running, with and
  without close animations
- terminating top-level clients with additional pop-ups with both with
  and without close animations

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-16 08:59:11 +00:00
Marius Vlad 9b0b5b57dd noop-renderer: Remove volatile and use compiler attribute
clang-13 complains about bitwise xor assigments like the following:

../libweston/noop-renderer.c:62:25: warning: variable 'unused' set but
not used [-Wunused-but-set-variable] volatile unsigned char unused = 0;

Use the __attribute__((unused)) instead.

Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-16 08:24:59 +00:00
Derek Foreman db06aea171 desktop-shell: Check height instead of checking width a second time
Fix an apparent copy and paste error in resize code. I'm not sure anything
sets the relevant callback that would lead to height being different than
width, so there's no easy way to demonstrate a bug, but this change
appears to rectify the intent of the code.

Reported-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-05-13 08:17:02 -05:00
Marius Vlad 299f87f073 desktop-shell: Clarify weston_view destruction at tear down
This documents the fact that other views are handled implictly by
libweston-desktop, and we shouldn't attempt to destroy indiscriminately
views that aren't created by desktop-shell.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:55 +03:00
Marius Vlad d03f01377a desktop-shell: Check for a valid desktop_surface
This patch fixes the following trace:

    #0 0x7f07d1bcecfa in weston_desktop_surface_get_surface ../libweston-desktop/surface.c:585
    #1 0x7f07d1bfc9b8 in move_grab_motion ../desktop-shell/shell.c:1499
    #2 0x7f07e539f841 in notify_motion ../libweston/input.c:1794
    #3 0x7f07e1e8ace4 in handle_pointer_motion ../libweston/libinput-device.c:132
    #4 0x7f07e1e8cad5 in evdev_device_process_event ../libweston/libinput-device.c:535
    #5 0x7f07e1e89311 in udev_input_process_event ../libweston/libinput-seat.c:208
    #6 0x7f07e1e8932f in process_event ../libweston/libinput-seat.c:218
    #7 0x7f07e1e8935f in process_events ../libweston/libinput-seat.c:228
    #8 0x7f07e1e8940a in udev_input_dispatch ../libweston/libinput-seat.c:239
    #9 0x7f07e1e89437 in libinput_source_dispatch ../libweston/libinput-seat.c:249
    #10 0x7f07e53122b1 in wl_event_loop_dispatch ../src/event-loop.c:1027
    #11 0x7f07e5310114 in wl_display_run ../src/wayland-server.c:1408
    #12 0x7f07e579c7ba in wet_main ../compositor/main.c:3589
    #13 0x555611d6b17d in main ../compositor/executable.c:33
    #14 0x7f07e55be7fc in __libc_start_main ../csu/libc-start.c:332
    #15 0x555611d6b099 in _start (/home/mvlad/install-amd64/bin/weston+0x1099)

A highly unlikely, but still valid operation, is to close/destroy the
window while still having it grabbed and moved around, basically having
an in-flight destruction of grabbed moving window. Another situation
would be that the client terminates abruptly (crashing for instance),
while being dragged which might take down the compositor.

This could happen for both touch/pointer grab operations and could cause
a NULL pointer access while accessing desktop_surface when being used
to retrieve the underlying weston_surface.

With this patch we check for a valid desktop_surface and return early
if that's not the case.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:55 +03:00
Marius Vlad c41cdcabb4 desktop-shell: Migrate surface_unlink_view
Moving weston_desktop_surface_unlink_view() to
desktop_shell_destroy_surface() makes sure we don't leak the underlying
weston_desktop_view when tearing/shutting down the compositor.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:55 +03:00
Marius Vlad be5b6f9cdc desktop-shell: Rename destroy_layer functions
No functional change. Makes it obvious that we also call
weston_layer_fini().

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:55 +03:00
Marius Vlad 9cf602840d desktop-shell: Create a distinct view for the fade-out close anim
Creates a distinct view, separated from the one created by
libweston-desktop, in order to avoid a potential ownership fight with
libweston-desktop upon destroying the view. Upon weston_desktop_surface
destruction, libweston-desktop inflicts damage on the view it creates,
so we need the view to be alive at that time.

This wasn't such an issue before because we had different destruction paths but
with commit 'desktop-shell: Do not leave views in layers upon shell
destruction' all of the destruction paths now land in the same spot
+ handle compositor tear down.

Note as we still use the same weston_surface we'll keep the previous
construct where we were taking a reference to keep it alive.

The original view is destroyed when releasing the ownership, while for
the view created in this patch we handle the destruction directly upon
compositor tear down.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:55 +03:00
Marius Vlad bd8314078d libweston, desktop-shell: Add a wrapper for weston_surface reference
Similar to how we do it with drm_fb ref counts, increase a reference
count and return the same object.

Plug-in in desktop-shell when we map up the view in order to survive a
weston_surface destruction.

Astute readers will notice that this patch removes weston_view_destroy()
while keeping the balance between removing and adding a
weston_surface_unref() call in desktop_shell_destroy_surface().

The reason is to let weston_surface_unref() handle destruction on its
own. If multiple references are taken, then weston_surface_unref()
doesn't destroy the view, it just decreases the reference, with
a latter call to weston_surface_unref() to determine if the view
should be destroyed as well.  This situation happens if we have
close animation enabled, were we have more than one reference taken: one
when mapping the view/surface and when when the surface itself was created,
(what we call, a weak reference).

If only a single reference is taken (for instance if we don't have close
animations enabled) then this weston_surface_unref()
call is inert as that reference is not set-up, leaving libweston to
handle the view destruction.

Following that with a weston_view_destroy() explicit call would cause a
UAF as the view was previous destroyed by a weston_surface_unref() call.

A side-effect of not keeping the weston_view_destroy() call would
happen when tearing down the compositor. If close animations are enabled,
weston_surface_unref() would not destroy the view, and because
weston_view_destroy() no longer exists, we would still have the
view in the other layers by the time we check-up if layers
have views present.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:53:34 +03:00
Marius Vlad d3ed2eb345 libweston: Assert if ref-count balance is wrong
Calling weston_surface_unref() one time too many could be a sign we
haven't correctly increased the ref count for it.

Also, if we don't have a surface being passed, do no attempt to
use it.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:46:32 +03:00
Marius Vlad 0d8e94af61 libweston: Rename weston_surface_destroy() to weston_surface_unref()
Make it obvious that weston_surface has a reference counting happening
and destruction of the weston_surface happens when the last
weston_surface reference has been accounted for.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-12 16:46:31 +03:00
Robert Mader 53a221ccaa libweston/linux-dmabuf: create surface feedback on demand
Unconditionally creating a surface feedback for each surface
creates unnecessary overhead and noise in the logs. Thus
create it when the first surface feedback resource for a
surface is requested and delete it again once all those
resources have been destroyed.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-12 11:53:04 +00:00
Robert Mader 34f7e01c2b clients/simple-dmabuf-feedback: use time instead of redraws
Weston uses a timeout of 2 seconds before it sends scanout
tranches to clients in order to not trigger excessive buffer
reallocations in clients.
`simple-dmabuf-feedback` in turn counts redraws (200) before
exiting. That doesn't work on e.g. 144Hz screens, thus use a
timer here as well.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-12 11:53:04 +00:00
Robert Mader 29d480813a backend-drm: Add failure reasons for failing gbm_bo_import
And add it to the list of failures triggering a resend of
dmabuf feedback scanout tranches.

Closes https://gitlab.freedesktop.org/wayland/weston/-/issues/614

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-05-12 11:53:04 +00:00
Marius Vlad 70353dace3 desktop-shell: Refuse to set a surface to maximized
For a surface that is already fullscreen making it maximized means to
exit fullscreen then set to it maximized. Instead of doing it, refuse to
do anything until the user explicitly performs that operation.

With this approach we follow other DE (desktop environments) which would
not perform any operation until the user exits fullscreen state.

Fixes #321

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-05-10 12:13:28 +00:00
Erik Faye-Lund fed2ee51f2 simple-egl: clean up unused callback
Unused since 45ee1f9ef7, which itself
removes code that was unused since
1e65840b61.

Signed-off-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
2022-05-10 08:03:27 +00:00
Hideyuki Nagase 8a776be925 rdp: Add US international keyboard layout
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-05-09 08:56:23 -05:00
Hideyuki Nagase e3b95f2d27 rdp: Add hebrew standard layout
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-05-09 08:56:23 -05:00
Pekka Paalanen e3b6d04017 color-lcms: refactor away setup_seach_param()
To me, the use of setup_search_param() makes the code harder to
understand than it needs to be. Replacing that function with open-coding
the struct cmlcms_color_transform_search_param initialization makes it
more clear that:

- get_surface_color_transform is the only one that actually uses a
  surface to initialize it

- get_blend_to_output does not use an input profile at all

- get_sRGB_to_output and get_sRGB_to_blend hardcode the sRGB profile
  like they should

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-06 09:33:35 +00:00
Pekka Paalanen dfba19abde color: simplify color manager API with weston_output_color_outcome
I am going to need to add yet another output property to be set by a
color manager: HDR Static Metadata Type 1. With the old color manager
API design, I would have needed to add the fourth function pointer to be
called always in the same group as the previous three. This seemed more
convoluted than it needs to be.

Therefore collapse the three existing function pointers in the API into
just one that is resposible for setting up all three things.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-06 09:33:35 +00:00
Pekka Paalanen 6c0524fd80 libweston: add struct weston_output_color_outcome
This new struct collects all the things that a color manager needs to
set up when any colorimetry aspect of an output changes. The intention
is to make the color manager API less verbose.

In this first step, the new struct is added and replaces the fields in
weston_output.

The intention is for the following color manager API changes to
dynamically allocate this structure. Unfortunately, until that actually
happens, we need a temporary way to allocate it. That is
weston_output::colorout_, which will be removed in the next patch. This
keeps the patches more palatable for review at the cost of some
back-and-forth in code changes.

This is a pure refactoring, no functional changes.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-06 09:33:35 +00:00
Simon Ser 6122765203 clients/simple-dmabuf-feedback: prettify output
- Use more consistent style, e.g. the tree structure uses
  the same indentation level throughout
- Swap format name and code for consistency with modifiers
- Use constants for ASCII art (taken from drm_info)

Signed-off-by: Simon Ser <contact@emersion.fr>
2022-05-02 19:36:07 +02:00
Pekka Paalanen e6a9e3c4ee backend-drm: default to XRGB2101010 for HDR
Trying to do HDR with XRGB8888 is a bit like using RGB565 on SDR: you
get visible color quantization and banding in gradients (without dithering
which Weston does not implement yet, and might not work too well for HDR
anyway).

Therefore, on any HDR mode, default output framebuffer format to 10 bpc
instead of 8 bpc.

Ideally we'd also optionally try 16F or 16 bpc formats, but automatic
fallbacks for those are more complicated to arrange. You can still
configure 16F or 16 bpc manually.

This patch also moves the default format setting from
drm_output_set_gbm_format() to drm_output_enable(), because setting the
default now requires eotf_mode. Frontends may call set_gbm_format()
first and set eotf_mode next. This does create an awkward situation for
outputs that a frontend disables and re-enables. This patch here makes
sure that the old output configuration remains, but changing eotf_mode
may not change the default format. One needs to call
set_gbm_format(NULL) to re-evaluate the default format. Resetting the
format on drm_output_deinit() would lose the current setting.

DRM_FORMAT_INVALID was introduced in libdrm 2.4.95 which we already
hard-depend on.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 33d553f833 compositor: add eotf-mode weston.ini option
This per-output option allows to choose one of the HDR video modes.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 5151f9fe9e backend-drm: program HDR_OUTPUT_METADATA
Program the connector property HDR_OUTPUT_METADATA based on the EOTF
mode of the output.

For now, this changes only the EOTF. The colorimetry and luminance are
left undefined, to be filled in by later patches. This should still be
enough to put a video sink into HDR mode, albeit the response is
probably unknown.

drm_output keeps track of the currently existing blob id. If the blob
contents need to be re-created, this blob would be destroyed and the
field set to zero. In this patch, there is no provision for runtime
changing of HDR metadata, so there is no code doing that.

Destroying the blob at arbitrary times is not a problem, because the
kernel keeps a reference to the data as long as the blob id remains with
KMS.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 1d17e4991f backend-drm: check for HDR_OUTPUT_METADATA
Check whether HDR_OUTPUT_METADATA property exists on a KMS connector. If
yes, pretend that EDID claims support for all EOTF modes and update the
head supported EOTFs mask accordingly. If not, then only SDR is
possible.

Parsing EDID to take monitor capabilities into account is left for
later.

HDR mode cannot be set without HDR_OUTPUT_METADATA.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 6914064066 backend-drm: add HDR_OUTPUT_METADATA definitions
These are fallback definitions in case libdrm is not new enough.
They are copied from libdrm 2.4.107.

struct hdr_output_metadata defines the contents of the blob to be used
with the connector property "HDR_OUTPUT_METADATA".

This is needed for programming a HDR mode in KMS.

This headers need to be excluded from Doxygen, because Doxygen chokes on
the kerneldoc markup.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 271c11e9dc color-lcms: todo for eotf_mode
A reminder that this variable needs to be taken into account when
crafting color transformations.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 46c0383c14 color-noop: supports only SDR EOTF mode
The no-op color manager will not support any other EOTF mode than SDR.
Other modes would require it to set up color transformations.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 1e9b1a1047 backend-headless: support all EOTF modes
The headless backend does not display to anything, so it doesn't care
what the EOTF mode is. To allow testing compositor internal behavior,
claim to support all EOTF modes.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Pekka Paalanen 5f9b68d68f libweston: introduce weston_eotf_mode
This is the switch to turn HDR mode on.

The values in the enumeration come straight from CTA-861-G standard.
Monitors advertise support for some of the HDR modes in their EDID, and
I am not aware of any other way to detect if a HDR mode actually works
or not. Different monitors may support different and multiple modes.
Different modes may look different. Therefore the high-level choice of
how to drive a HDR video sink is left for the Weston frontend to decide.

All the details like what HDR metadata to use are left for the color
manager.

This commit adds the libweston API for backends to advertise support and
for frontends to choose a mode. Backend and frontend implementations
follow in other commits.

The frontend API does not limit the EOTF mode to the supported ones to
allow experimentation and overriding EDID.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-05-02 12:19:24 +00:00
Marius Vlad 054aaa5a8b simple-egl: Move set_fullscreen/set_maximized before initial commit
Rather than setting the fullscreen/maximized before initial
wl_surface.commit, make it part of the initial window state.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-04-29 12:42:46 +03:00
Marius Vlad 0277046a1d simple-egl: Defer EGL surface/window creation
Rather than creating the wl_egl_window at the same time as wl_surface,
do it after we get the first configure event.

With it, we also defer eglMakeCurrent() as according to the spec, the
first time a OpenGL or OpenGL ES context is made current, the viewport
and scissor dimensions are set to the size of the draw surface.

This is particulary important when attempting to start simple-egl either
as fullscreen or as maximized, as not doing so will either incorrectly
commit a buffer with the original dimensions, and later on to resize to
the correct dimensions (which is the case for fullscreen), or it will
terminate the wayland connection abruptly due to xdg-shell protocol
violation, with a mismatch for the client's geometry (the case for
maximized).

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Daniel Stone <daniel.stone@collabora.com>
2022-04-29 12:34:51 +03:00
Marius Vlad c15699b7f8 simple-egl: Remove uneeded check
display->wm_base is checked right after handling registry object, and
with it the globals, so there's no to perform and additional check for
xwm_base.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-29 12:34:36 +03:00
Marius Vlad cc877d4b77 libweston-desktop: Replace buffer with geometry
A previous patch modified this for fullscreen, but missed out the
maximized state. As we check the geometry rather than the buffer
dimensions use the same terminology.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-29 12:34:36 +03:00
Marius Vlad 01ef3746a2 simple-egl: Add start as maximized
Just like start as fullscreen, let us add a start as maximized as well.
It tests out the maximized state and with clients geometry checks.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-29 12:34:36 +03:00
Marius Vlad 69a59359fa pixman-renderer: Unref the pixman image when wl_shm_buffer is gone
Even if the weston_buffer_reference is still alive in situations like
when we have closing animations, the underyling buffer (wl_shm_buffer)
is no longer available. Call the appropriate destroy handler to
invalidate the pixman image and avoid touch the shm_buffer.

Fixes: #613

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-29 11:48:08 +03:00
Hideyuki Nagase b6fc6b2a8d rdp: sync keylocks on synchronize event
Synchronize events carry keylock status, so we should update it.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase 6515df1333 rdp: Support using Japanese layouts with US keyboards
When RDP indicates that a Japanese keyboard layout is used without
a Japanese 106/109 keyboard (keyboard type 7), use the "us" layout,
since the "jp" layout in xkb expects the Japanese 106/109 keyboard
layout.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase 5d939bc636 rdp: Korean keyboard support
Korean keyboards are keyboard type 8:
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardtype

While type 8 is not explicitly mentioned in the RDP documentation,
it can be sent over the wire. Let's support the variants we can.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase 4d5605b3a0 rdp: refactor xkbRuleNames code
This code will eventually be used by RAIL as well, so let's
split it out now.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase a29bcb7031 rdp: change japanese keyboard input from kana to alphabetical
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase e3a4552ecc rdp: Fix Farsi keyboard map
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase 08f5edfe78 rdp: Fix Brazilian keyboard map
Use the common abnt2 variant, instead of the niche nativo one.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Hideyuki Nagase d2a8165bb6 rdp: Add Persian keyboard map
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 15:33:57 +00:00
Daniel Stone 06472fb136 desktop-shell: Delete Exposay
Exposay was done as a showcase for what we could do with Weston and an
efficient compositing pipeline. This was mostly with the old
vendor-specific Raspberry Pi backend which could actually process that
many surfaces bypassing the GPU.

Given enough bitrot, Exposay is now pretty exemplary as what _not_ to do
in a Weston shell - particularly the way it manipulates existing
weston_views rather than create its own non-destructive stack.

As it's annoying technical debt, a terrible example to others, and not a
very compelling showcase in 2022, just delete it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-28 15:19:06 +00:00
Derek Foreman 2eb5912960 rdp: Don't bother trying to pick an optimal keyboard model name
Nothing actually cares about this string, and pc105 will do just
fine.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-28 13:19:10 +00:00
Hideyuki Nagase 806e824809 rdp: Add horizontal scroll support
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 12:39:35 +00:00
Hideyuki Nagase 4e907a67e5 rdp: Add high precision scrolling
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 12:39:35 +00:00
Hideyuki Nagase ce09c7835c rdp: refactor scrollwheel code
We move this into a function for when we add horizontal wheel support
later.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 12:39:35 +00:00
Hideyuki Nagase cf5ddd05cb rdp: Allow configuring the refresh rate
We currently hardcode a 60Hz update rate for the rdp backend.

In some cases it may be useful to override this to increase the rate
for a faster monitor, or to decrease it to reduce network traffic.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 07:35:57 -05:00
Hideyuki Nagase bd214edf26 rdp: Calculate frame times from mode refresh rate
Instead of hard coding a 16ms refresh interval, use the refresh rate
from the current mode to determine when the next frame should be.

Currently, we still hard code the refresh rate, so this will end up
with roughly the same value we've been using, but in the future
we'll allow setting it via command line.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 07:35:04 -05:00
Brenton DeGeer 2f9319cef6 rdp: Allow specifying a listener fd on the command line
We already have a way for a single RDP client connection to be
passed from a parent process to a child using a combination
of environment variable (RDP_FD) and env var (--env-socket)

This patch allows a bound socket fd (as opposed to a client
connection) to be established in a parent process and provided
to the rdp backend. WSLg uses this to set up an AF_VSOCK
socket for communication between a Windows RDP client and a
weston compositor running under a hypervisor.

Co-authored-by: Hideyuki Nagase <hideyukn@microsoft.com>
Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-28 12:27:56 +00:00
Hideyuki Nagase 13e62c9d18 rdp: validate button state
Discard and log duplicate release or press events. Log and discard
invalid button ids.

This prevents buggy clients from causing problems in weston's internal
state - like breaking idle inhibition button counting.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-27 13:57:42 +00:00
Hideyuki Nagase 873ec15412 rdp: Fix up xf_extendedMouseEvent
These events carry the 4th and 5th mouse buttons, so
we should propagate them. We also need to use pointer
frames to ensure the buttons are properly paired with
the pointer co-ordinates.

Unfortunately, there is no way in RDP to determine if
a mouse event and an extended mouse event should be in
the same pointer frame, so this is the best we can do.

We also enable extended mouse events so they'll be used.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-27 13:57:42 +00:00
Hideyuki Nagase 7f10997d92 rdp: add mouse input debug
Add extremely verbose mouse input debugging.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-27 13:57:42 +00:00
Simon Ser 778c0683c0 clients/simple-dmabuf-feedback: use presentation-time
Print a message when presentation switches to/from zero-copy mode.
This makes it easier to understand whether the compositor DMA-BUF
feedback was effective.

Signed-off-by: Simon Ser <contact@emersion.fr>
2022-04-27 14:21:55 +02:00
Leandro Ribeiro 7724c5ea38 clients/simple-dmabuf-feedback: do not use buffer before compositor's response
This fixes an issue when running simple-dmabuf-feedback:
"wl_display@1: error 1: invalid arguments for wl_surface@3.attach".

As we are not using create_immed request from zwp_linux_dmabuf_v1, we
can't start to use a dma-buf buffer before we process compositor's event
telling us that the creation succeeded.

This was causing problems in the following scenario:

1. buffer is marked to be recreated (because of dma-buf feedback);
2. in buffer_release() event, we destroy the buffer and recreate it;
3. after we recreate it, roundtrip is not called, as we don't want to
   block during the drawing loop;
4. buffer status is not being properly tracked, so we are trying to
   use a buffer before receiving the event from the compositor telling
   us that the creation succeeded.

To fix this, this patch improves buffer status tracking. Now we only
pick a buffer in the drawing loop when it is available. Also, if we have
no buffers available we perform a roundtrip and try again, as we may
have recreated all of them but still didn't have the chance to process
compositor's events telling us that creation succeeded.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
2022-04-27 11:52:00 +00:00
Marius Vlad 509398dc25 desktop-shell: Avoid spurious configure events for xdg-shell activation
This is a minor re-work of how we de-activate and activate the surfaces
in desktop-shell. As activate() is being used for handling keyboard
input events, this basically rectifies that such that  activation
happens only if the passed surface is different from the currently
focused surface.

Fixes: #593

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-26 15:59:29 +00:00
Daniel Stone b5605ccd26 libweston: Remove weston_surface_set_color
Don't do this; instead, create a solid-colour buffer and attach it to
the surface explicitly.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 4d426ab6b1 shell: Explicitly use solid weston_buffers
Rather than punching through to set the surface as a solid colour,
attach an actual weston_buffer to it instead.

This becomes the first user of attaching non-client-generated buffers
to a weston_surface. As a result, it is necessary to introduce a
function which will allow compositors and shells to attach a buffer to a
surface. weston_surface_attach_solid() is therefore introduced as a
special-purpose helper which will attach a solid buffer to a
weston_surface.

It is not intended as a general-purpose mechanism to allow compositors
to attach client-generated buffers to surfaces, as doing so would have
unknown effects on this core part of the compositor itself.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 82b646728c backend-drm: Handle solid-colour buffers in state propose
When we're checking to see if a view is suitable to go on a plane, check
for (and reject) solid-colour buffers.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone b38b735e20 backend-drm: Remove Pixman conditional for keep_buffer
The Pixman renderer keeps its own reference to buffers when attached to
surfaces, through its surface state: just use that instead.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 493a4c013e noop-render: Allow solid-color buffers
Refactor the buffer-type check slightly so we can handle solid-color
buffers, which we do exactly nothing with.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone d82d74e713 pixman-renderer: Support solid-colour weston_buffers
Just implemented via the same mechanism as surface_set_color.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 465f4a250c gl-renderer: Support solid-colour weston_buffers
Same as surface_set_color.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 43715ff0c0 weston_buffer: Add solid buffer type
Currently solid-colour displays (e.g. the background for fullscreen
views) is implemented by a special-case weston_surface which has no
buffer attached, with a special punch-through renderer callback to set
the colour.

Replace this with a weston_buffer type explicitly specifying the solid
colour, which helps us eliminate yet more special cases in renderers and
backends.

This is not handled yet in any renderer or backend, however it is also
not used by anything yet. Following commits add support to the renderers
and backends.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 7a27f6cbe4 compositor: Downgrade rather than drop buffer reference when copied
When the renderer/backend indicate that they do not need a surface's
buffer content to be preserved, most often because they have copied it,
simply downgrade the buffer reference to 'will not access', rather than
drop the buffer reference altogether.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone a42908204f weston_buffer: Separate buffer release from lifetime
In the original conception, a weston_buffer_reference indicated that the
underlying contents of the wl_buffer would or could be accessed, so
wl_buffer.release must not be sent until the last reference was
released, as the compositor may still use it.

This meant that renderers or backends which copied the buffer content -
such as the GL renderer with SHM buffers - could only send a buffer
release event to the client by 'losing' the buffer reference altogether.
The main side effect is that `weston-debug scene-graph` could not show
any information at all about SHM buffers when using the GL renderer, but
it also meant that renderers and backends grew increasingly exotic
structures to cache information about the buffer.

Now that we have an additional buffer-reference mode (still referring to
the weston_buffer/wl_buffer, but not going to access its content), we
can allow the weston_buffer_reference and weston_buffer to live as long
as the buffer itself, even if we do send a release event.

This will enable a bunch of backend and renderer deduplication, as well
as finally making scene-graph more useful.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone fdc7b9c352 weston_buffer: Add mode to weston_buffer_reference
Add a mode argument to weston_buffer_reference which indicates whether a
buffer's storage may/will be accessed, or whether the underlying storage
will no longer be accessed, e.g. because it has been copied. This will
be used to retain a pointer to the weston_buffer whilst being able to
send a release event to the client.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 7e90433079 weston_buffer: Hold lifetime for resource/backend usage
Keep the weston_buffer alive for as long as at least one of the
underlying wl_buffer or a backend usage exists.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone d2a858e879 gl-renderer: Prepare for buffer to outlive resource
Make sure we don't die if we're asked to flush the damage on a SHM
buffer which has subsequently been destroyed.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 7b3efabd88 weston_buffer: Prepare for buffer to outlive resource
We currently allow a weston_buffer to outlive the underlying wl_buffer
iff the renderer/backend has cached it. Currently the 'is this buffer
valid?' test relies on looking for the validity of the weston_buffer
itself; shift these tests to looking at the validity of the underlying
resource.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone e9c792ed64 backend-drm: More failure reasons
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 231a67ff8c drm-backend: Refactor unpleasant keep_buffer if tree
Break a giant if statement out into a more legible grouping.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 2dcfe723be backend-drm: Make use of weston_buffer format and type
Just pull it from the structure rather than pulling it in externally.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 1d9c62b50d weston_buffer: Print more buffer information in scene-graph
Try to print out as much information as we can about the buffer.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 0a8802404c scene-graph: Use weston_buffer's format/modifier info to print
Now that we have this generically available, use it rather than calling
into per-buffer getters.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 7506cf5240 gl-renderer: Simplify surface->is_opaque
We already have the format; no need to go chasing it again.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 4f88b2655e weston_buffer: Change y_inverted to explicit origin enum
y_inverted meant that the buffer's origin was (0,0), and non-inverted
meant that the buffer's origin was (0,height). In practice, every buffer
was 'inverted' into our natural co-ordinate space that we use
everywhere.

Switch to using an explicit origin enum to make this more clear.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 6dcf3eac1f weston_buffer: Add pixel format and modifier info
Promote these to weston_buffer rather than burying them in the renderers
and backends.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone fef8bb275c weston_buffer: Make use of weston_buffer->type
Rather than calling accessors (wl_shm_buffer_get etc) to figure out
which type our buffer is, just look in the structure.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 34cd0d114f weston_buffer: Add type field
Rather than open-coding various resource -> type accessors, just stick a
type enum in the buffer struct.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 1d5f8af82e gl-renderer: Add hook to fill weston_buffer for EGL
Rather than only filling weston_buffer information when we first come to
use it, add an explicit hook so we can fill the dimensions the first
time the buffer's attached.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone f49d6f47f3 gl-renderer: Reject unknown-format dmabufs
Make sure we only import dmabufs where the underlying pixel_format is
known: if we can't reason about the buffer content, we're not entirely
likely to be able to display it well.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone ca9bb01fe6 renderers: Set buffer properties earlier
When we first see a buffer attached, we create a weston_buffer for it.
The weston_buffer doesn't contain any useful information in and of
itself; that's left to renderers to populate later.

Switch this to doing it in the core at the first opportunity, at least
for SHM and dmabuf buffers; EGL buffers will follow in the next commit.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone fec0400886 gl-renderer: Drop unnecessary NULL check
All the callers of flush_damage guarantee we'll have a buffer.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone 12675ed19f renderer: Add buffer to flush_damage
We already have the buffer in the caller, and every no-op implementation
will want to access the buffer. So might as well pass it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Daniel Stone f8ac6f940f gl-renderer: Remove outdated comment
The comment about needing to have destroyed images is somewhat less true
now that we actively avoid doing so.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Fixes: 0b51b02c5e ("gl-renderer: Don't re-import dmabufs")
2022-04-25 14:27:08 +00:00
Daniel Stone efd6aae915 gl-renderer: Remove unnecessary dmabuf conditional
We can't try to attach a dmabuf that we never imported.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-04-25 14:27:08 +00:00
Hideyuki Nagase 6129cbd880 rdp: Improved rdp logging infrastructure
Add some logging helper functions along with two log scopes for debug
and extremely verbose debugging information.

Also add tangentially related logging for the synchronize event, so
the debug stream isn't empty right now. The vast majority of verbose
usage will come later.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-21 07:33:27 -05:00
Derek Foreman 04e0558327 rdp: Allow disabling RemoteFX codec
There are currently compatibility issues between FreeRDP's implementation
of the RemoteFX codec and Microsoft's implementation.

Perhaps this will be fixed in the future and this option can go away,
but for now it's necessary to have a way to disable the codec if the
windows client is going to be connecting to a weston server.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-21 07:20:59 -05:00
Simon Ser 4887f1a7aa build: add Meson fallback for wayland-protocols
This allows easily co-developing a Wayland protocol and Weston.
Example setup:

    ln -s subprojects/wayland-protocols /path/to/wayland-protocols
    meson configure build/ --force-fallback-for=wayland-protocols

Signed-off-by: Simon Ser <contact@emersion.fr>
2022-04-21 11:29:48 +03:00
Marius Vlad 0a8e3cbc4a screen-share: Document that --no-config option should be passed
With commit 'screen-share: Add option to start screen sharing on weston
star' an section option has been added to start screen-sharing by
default on all outputs. This has the side-effect of attempting to start
screen-share on the same (RDP) output performing the screen-share. That
happens due to re-loading the screen-share module once more.

This patch recommends users to use --no-config option or alternatively,
use a different configuration file to avoid that.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-20 19:45:28 +03:00
Marius Vlad af18a0c4c9 screen-share: Avoid bit-shifting large values
Found while running with b_sanitize=undefined, which yields:

runtime error: shift exponent 909199186 is too large for 32-bit type 'int'

Converts the shm_formats to a boolean and checks for the correct pixel
format it directly, instead of trying to gather them all in an array and
then later on to do the check.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-20 19:45:28 +03:00
Marius Vlad 08ee337e4d screen-share: Add a compositor destroy listener
Trivial fix to clean itself on compositor tear-down. While at it
properly free the command string.

Fixes #298

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-20 19:45:28 +03:00
Marius Vlad 9e20730e04 screen-share: Start screen sharing even if no pointer is found
With commit e825fe38, we no longer display the pointer if no movement is
detected, which will cause screen share to fail to start if that is the
case. There could be also legitimate cases where there's no pointer, so
let's allow screen share to function in those cases as well. Makes uses
of previous helper methods to find a proper output to share in case we
don't have an pointer.

Re-uses the shell utils functions.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-20 19:45:25 +03:00
Marius Vlad 3bedb70454 touch-calibration: Clean-up if touch calibrator has been enabled
Seems that we're still missing layer clean-ups, with the touch
calibrator being one of them. Call the appropriate function when
shutting down the compositor instance.

Fixes: #603

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-04-20 08:27:17 +00:00
Hideyuki Nagase 8aa1c30bf1 xwayland: Honour the XCURSOR_THEME environment variable
Toy toolkit apps already do this since commit 807cd2e589

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-20 08:23:19 +00:00
Weng Xuetian e99ed2ad36 Defer launch input method with wl_event_loop_add_idle.
Input method process may also be a XIM server which requires the correct
DISPLAY to be set after xwayland start up. This helps input method to
work for both wayland and Xwayland.

Signed-off-by: Weng Xuetian <wengxt@gmail.com>
2022-04-19 07:06:30 -07:00
Hideyuki Nagase 8fb529bc31 input: Fix bug in idle inhibition
Server generated key repeats are ignored - and they don't generate
matching release events. We early return to avoid generating events
for them.

We also need to push the idle inhibition counting after that early
return to prevent breaking idle inhibition with unmatched events.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-18 12:10:20 +00:00
Dominique Martinet c2f4201ed2 xwayland: use -displayfd instead of USR1 to signal readiness
We want to wait for Xwayland to be ready before issuing it blocking
requests, but relying on USR1 is a bit unsafe:
 - we can't ascertain the signal originated from Xwayland
 - if weston is started as PID1 (e.g. in its own container), then
   Xwayland will not send SIGUSR1 and X11 connections will be stuck
   forever: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1312

Creating a pipe and using -displayfd, even if we don't care about the
display value itself, is safe and works for all cases

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
2022-04-18 12:46:04 +03:00
Pekka Paalanen e1a111e1b7 man: add section delimiters in weston.ini
These added lines are comments (do not affect output) that make it
easier to browse this file and find the section headings.

Removal of the preceding empty lines on two of the section headers
remove a blank line from PDF output. The blank line was kind of nice,
but presumably .SH should add any necessary blanks before a new section
heading. Now all the section headings have the same vertical space to
the preceding content in PDF.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-04-18 12:43:00 +03:00
Pekka Paalanen 9203910b9a man: clean up weston.ini mark-up
Try to reduce the cargo-culted directives that do not seem to have any
effect on the output.

I verified that are no changes by doing before this patch

	$ man -Tpdf man/weston.ini.5 > ref.pdf

and then after this patch

	$ ninja && man -Tpdf man/weston.ini.5 > test.pdf

and looking at

	$ diffpdf ref.pdf test.pdf

I used PDF as the format for comparisons, because it can express much
more typesetting features than plain text.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-04-18 12:43:00 +03:00
Michael Olbrich 924e79f4f2 ivi-shell: emit created notification earlier for desktop surfaces
Without this, the earliest signal the ivi controller receives for a new surface
is configure_desktop_changed signal. And this is not emitted until the surface
has the first buffer attached.
By emitting the signal during surface creation, the controller is able to set
the initial width and height for the first configure.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-04-14 13:10:04 +00:00
Maciej Pijanowski cd7801aa95 screen-share: use compositor->read_format with renderer->read_pixels()
The pixel format was hardcoded to PIXMAN_a8r8g8b8. All other
renderer->read_pixels() calls in weston use dynamic format selection via
the compositor->read_format instead.

The problem was spotted on the ARM devices with Mali-400 GPU. The visual
effect of the problem was black screen on the remote display, when using
screen-share with the VNC or RDP backends. Related wayland-devel thread:
https://lists.freedesktop.org/archives/wayland-devel/2020-September/041624.html

Signed-off-by: Maciej Pijanowski <maciej.pijanowski@3mdeb.com>
2022-04-14 12:16:19 +00:00
shierote f2d6d21eec libweston: correct argument name in the handler of wl_data_source.accept
Signed-off-by: Taishi Eguchi <taishi2060@gmail.com>
2022-04-14 12:05:57 +00:00
Hideyuki Nagase 87bded8b54 rdp: split off rdp.h
Refactor some of rdp.c into a header file.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-14 12:02:12 +00:00
Hideyuki Nagase 516d2c0207 rdp: fix leak when listener implantation fails
We've already allocated the listener by the time we hit this failure,
so we must exit through the path that frees it.

Co-authored-by: Steve Pronovost <spronovo@microsoft.com>
Co-authored-by: Brenton DeGeer <brdegeer@microsoft.com>
Signed-off-by: Hideyuki Nagase <hideyukn@microsoft.com>
Signed-off-by: Steve Pronovost <spronovo@microsoft.com>
Signed-off-by: Brenton DeGeer <brdegeer@microsoft.com>
2022-04-14 11:57:29 +00:00
James Hilliard 23205b6b56 protocol/meson.build: install content-protection protocol xml
Since this is expected to be used by applications outside of weston
we should install it.

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2022-04-14 11:52:33 +00:00
Derek Foreman ca979aa219 desktop-shell: Fix incorrect use of black_surface_get_label
By some dark magic this accidentally doesn't crash because there are
zeroes in the right places at startup, but black_surface_get_label()
very much expects surface_private to be a view.

Let's hand craft a new bespoke label function for this use.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-14 07:39:25 +00:00
Derek Foreman bb1d19dc5e compositor: Launch clients in their own session
When we launch clients they currently stay in the same session as
weston, and share its controlling terminal. This means hitting ctrl-c
in weston's controlling terminal will send SIGINT to the clients as
well. It also means SIGHUP will be propagated to our launched clients
if weston's controlling terminal is closed.

While generally not harmful, this behaviour is not beneficial, and
is present by default and not by design.

Problems arise when launching weston in a debugger, as a ctrl-c sent to
the debugger will be propagated not only to the debugger, but all the child
processes sharing weston's session. This results in weston-desktop-shell
being killed by the ctrl-c that was intended to stop weston for debugging.

If weston-desktop-shell is killed within 30 second of startup, it will
result weston performing a clean shutdown. This clean shutdown can
make debugging a little too surprising.

Ostensibly, clients launched via weston_client_launch will be wayland
clients that terminate cleanly on their own if weston is killed, so
there should be no need for them to remain in weston's session to
catch ctrl-c from its controlling terminal. Nor should they need a
controlling terminal for their general operation.

Use setsid() to move them to their own session, devoid of controlling
terminal, to make using a debugger a little less confusing in some
cases.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-13 08:56:48 +00:00
Derek Foreman f32bcfef42 compositor: Use sigaction to trap SIGINT
signalfd interacts badly with gdb's signal trapping - when hitting
ctrl-c in a debugger attached to weston, weston will receive the
signal. This results in weston exiting cleanly when the intent
was to use gdb to interfere with its operation.

Trapping SIGINT was introduced in commit 50dc6989 which ensured we
would call wl_display_terminate() on SIGINT or SIGTERM to clean
up our socket.

Killing weston with SIGINT is quite common for several developers,
so it's important to preserve this clean shutdown behaviour, so
we can't naively stop trapping SIGINT entirely.

Instead, use the sigaction() function to trap SIGINT, and have
the SIGINT handler send weston SIGUSR2 (SIGUSR1 is already
used by xwayland). SIGUSR2 can be trapped in the proper wayland
way via wl_event_loop_add_signal(). This way we can properly
break our event loop and clean up on SIGINT, but we can also
have gdb intercept SIGINT.

There are other ways around this, but I'm hoping this one allows
people to continue using ctrl-c to stop weston, and doesn't
require additional project specific gdb knowledge.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-13 08:56:48 +00:00
Derek Foreman 2f71b3c3de compositor: Stop trapping SIGQUIT
We've been trapping SIGQUIT for a "clean shutdown" since commit 3cad436a

However, sources such as:
http://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
indicate we probably shouldn't be trapping it at all, as the intent of
SIGQUIT is to leave a core file and debug artifacts from the run.

We should perform the minimal amount of clean up to ensure the system isn't
left in an unusable state - but these days that's performed by other
software such as logind.

We can safely stop trapping SIGQUIT entirely.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-13 08:56:48 +00:00
Derek Foreman 0ff4e478cd rdp: Fix comment regarding meaning of 120
This URL has changed

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-12 09:26:13 -05:00
Derek Foreman 869cab4938 xwayland: Simplify HAVE_XWAYLAND_LISTENFD usage
We can use it just once to define a string instead of having preprocessor
conditionals sprinkled about the code.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-04-11 08:45:19 +03:00
Sören Meier edef874696 libbacklight: Fix backlight never gets initialized
In 913d7c15f7 stricter error checking was
introduced to the strtol call, which broke reading backlight values.
Since every sysfs backlight file ends with a newline.

As noted in a comment in the previous MR to prevent damaged pointers
after calling asprintf, replace every asprintf call with str_printf.

Previous-MR: https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/543

Signed-off-by: Sören Meier <soerenmeier@livgood.ch>
2022-04-11 08:38:00 +03:00
Michael Tretter 6ee6e76a0c compositor: remove repaint_data from compositor
The repaint_data is entirely backend specific. Moreover, it is only used by the
drm backend, while other backends ignore the repaint data.

There will always be only one repaint active, thus, there is no need to pass the
repaint data from the outside.

The repaint_data breaks with the multi-backend series, which calls repaint begin
for all backends to get the repaint_data. The repaint_data of the last backend
will then be passed to all other backend. At the moment, this works, because the
drm backend is the only backend that implements the begin_repaint call.

Another option would be to track the repaint data per backend in the compositor,
but actually, it the backend needs to track state across the calls, it's its own
responsibility.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-04-06 12:47:05 +02:00
Michael Tretter c448b938f7 backend-drm: always get pending_state from backend
The pending_state is already stored in the backend and can be directly retrieved
from there.

This avoids involving the compositor in passing state between the repaint
phases for a single backend.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
2022-04-06 12:47:05 +02:00
Daniel Stone c3415aed23 fullscreen-shell: Use weston_curtain for black view
Use the common helper provided by the shell-utils helper dependency,
rather than rolling our own.

This commit currently introduces no functional change to
fullscreen-shell, as the 'curtain' provided by shell-utils behaves
identically to the previous solid-color surface created by
fullscreen-shell, given the parameters provided to
weston_curtain_create().

However, now that a common weston_curtain implementation is being used
rather than an open-coded variant, future changes to the implementation
of weston_curtain will result in changes to this code called by
fullscreen-shell, although it is intended that these will not result in
any user-visible behavioural changes.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone b94d69b926 fullscreen-shell: Link with shell-utils helpers
Unlike desktop-shell and kiosk-shell, the fullscreen-shell does not link
with the common shell-utils helpers. This is largely because
fullscreen-shell is largely in 'maintenance mode', seeing little more
than occasional bug fixes or changes required to accommodate new
interfaces.

This commit adds a dependency from fullscreen-shell to use the
shell-utils helper, in order to allow fullscreen-shell to use the new
weston_curtain infrastructure, rather than continuing to open-code the
common pattern of creating a surface and view consisting only of a solid
colour for the background of fullscreen surfaces which do not wholly
cover the output.

In doing this, the 'surface_subsurfaces_boundingbox()' function is
removed, as this has been duplicated between the fullscreen-shell and
the common helper 'library'.

There is no functional change within this commit, as the two functions
were identical, other than a change to the comment which identifies a
known bug within this helper.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 577a832f41 test/desktop-shell: Use weston_curtain
Use the helper we have for these, rather than open-coding.

This commit is not believed to result in any functional changes.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 6cb2526b67 Move shell-utils to its own directory
shell-utils contains a number of helpers which are currently in use by
both desktop-shell and kiosk-shell. In order to extend this use to
fullscreen-shell as well (which can benefit from reusing the
weston_curtain infrastructure to be able to create solid-colour views
which may or may not be opaque, as well as one function within
fullscreen-shell which was copied wholesale to shell-utils), we need to
create a separate Meson dependency object, and avoid the existing
pattern of including the source from shared/ within the source list for
each shell.

This requires creating a new top-level directory for these shared helper
functions which are required by each shell, but are not part of
libweston in and of itself.

shell-utils depends on libweston-desktop; libweston-desktop depends on
libweston; libweston depends on shared.

Thus it is not possible to expose a dependency object from the shared/
directory which declares a dependency on the libweston-desktop
dependency, as Meson processes directories in order and resolves
variable references as they are parsed.

In order to break this deadlock, this commit creates a new top-level
directory called 'shell-utils' containing only this file, which can be
parsed by Meson after libweston-desktop (making the libweston-desktop
Meson dependency variable available to the build file to declare a
dependency on that), but before the shells (making the new Meson
depenendency object available to each shell which wishes to use it).

This commit contains no functional changes to any observable code.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 15a553053a desktop-shell: Reuse curtains for fades
Use the common infrastructure we have, rather than open-coding again.

In changing to the common weston_curtain infrastructure which was
introduced in a previous commit, there are two small functional
derivations.

After adding the view to a layer, we explicitly call
weston_view_geometry_dirty(). This is believed to have no functional
impact, as weston_views have their geometry-dirty flag set when they are
created.

weston_surface_damage() is also called to ensure that the surface is
scheduled for a repaint. As there is currently no good common mechanic
in the common code to ensure that output repaint will occur, due to the
damage propagating outwards from the weston_surface, we are forced to
call this to predictably ensure that the output will be repainted after
we have made this change to the scene graph which should result in the
user observing the new content being repainted.

It is possible that these changes are not strictly required in order for
the correct behaviour to occur. However, it is felt that explicitly
adding these calls is perhaps the least fragile way to ensure that the
behaviour continues to be correct and breakage is not observed,
especially with both view mapping and surface damage identified as areas
for future work which could be beneficial to Weston. If it is felt that
these calls can be removed, then this is certainly possible at a later
stage.

Lastly, there are many users within desktop-shell of the common pattern
of creating a weston_curtain and inserting it into the scene graph to be
painted. These users have been an area of both theoretical concern and
real-life observed fragility and breakage recently. By making each user
follow a common and predictable pattern of usage, each user is no longer
its own special case. This should make it easier to make the
desktop-shell codebase more robust, not only simplifying the codebase,
but improving observed behaviour.

In doing this, it is hoped that future structural and interface changes
become easier to make, allowing us to improve some of the more difficult
corners of the libweston API.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone dc0f73bcac shell: Encapsulate weston_curtain in its own struct
This will allow us to create a solid weston_buffer as well, since we
need to store that separately.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone e031397e09 desktop-shell: Reuse curtains for focus animations
Just as we do for fullscreen backgrounds, reuse the curtain infrastructure
for focus animations.

This introduces a small functional change, in that the surface's output
is no longer directly assigned. Instead, we call
weston_view_set_output() ourselves. As setting the weston_view's
position (done from the common helper function of weston_curtain_create
which has been introduced in previous commits) will call
weston_view_set_position(), the view's geometry will be dirtied as a
result.

When the geometry of a weston_view is dirty, it is marked to be updated,
which will occur whilst traversing the view list during output repaint.
This occurs for every view which is currently assigned to a layer; when
building the view list, any view reachable through the view list whose
geometry is dirty will have its position recalculated and an output
assigned. Doing so results in the surface's current output being
updated.

It is believed that there is no functional impact from the
weston_surface not having a primary output assigned between creation and
output repaint being called.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone bd9b0676dd shell: Make input capture optional for curtains
desktop-shell's focus surfaces want to reuse this, but they don't want
to capture the input, instead allowing it to fall through.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 64ef87554b desktop-shell: Clean up fullscreen black view code
Rationalise it a little bit so we don't need pre-declarations of static
functions, and the order of creation more closely matches the others,
including making the same calls to explicitly set the output.

Doing this makes the behaviour match the other users of the same code
pattern. In making them the same, we make desktop-shell code a little
less magically divergent where people might wonder what the correct
pattern is to use. After we have moved all users to a uniform pattern,
later commits are then able to migrate these users to common helper
code, which reduces code duplication, improves code clarity as it is no
longer necessary to wonder about the exact semantics of every
special-case user of this common pattern, and makes it easier to make
interface changes which improve and clarify the patterns which are
prevalent throughout the desktop-shell code.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone de0cd53264 desktop-shell: Remove redundant geometry dirty call
Dirtying the geometry only sets a flag on the view saying that the
geometry is dirty, so we don't need to do it twice back-to-back.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 791e8b1c5f desktop-shell: Fix opaque region co-ordinate confusion
Opaque regions are in surface co-ordinate space, not global co-ordinate
space, so the region should be anchored to (0,0).

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone e81b8d7cc9 shell: Add alpha to weston_curtain_create
Not all solid-colour views want to be opaque: sometimes we use them with
non-opaque alpha values in order to shade views underneath them.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone d21563360a shell: Move weston_curtain_create params into the struct
Given that we have a struct for argument params, we might as well use it
rather than have them split between the struct and native params. For
consistency between the implementations, this also includes a shift from
float to int positioning for the base offset within the compositor's
global co-ordinate space.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 3a298b0b05 shell: Rename weston_solid_color_surface to weston_curtain_params
The name implied that it was a surface in and of itself, rather than
parameters used by a helper to create a surface and view.

Rename it now that we have weston_curtain as a name, and clean up
initialisers.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone b77c2374ee shell: Rename solid_color_surface to weston_curtain
create_solid_color_surface actually returns a weston_view that it
creates internally. Since weston_solid_color_view is long and dull,
rename it to weston_curtain.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone 7059ec7807 desktop-shell: Explicitly destroy black views on shutdown
desktop_shell_removed() won't get called when we shut down, so
explicitly destroy the fullscreen black view.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone c8a2fb7a40 pixel-formats: Add XYUV8888 format
XYUV8888 support was added to gl-renderer in 30104bd89a, but not to
pixel-formats. Oops.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
Daniel Stone f48cf18a16 compositor: Fix harmless potential buffer overflow
We could overflow a local buffer if there were more than ten million
concurrently active displays within the current user's session. This
seems vanishingly unlikely, and harmless, but does at least squash a
compiler warning emitted by gcc 12+.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-03-31 17:15:55 +00:00
nerdopolis cdfe94b105 launcher-logind: Don't check wl->vtnr before returning it.
Signed-off-by: n3rdopolis <bluescreen_avenger@verizon.net>
2022-03-16 13:12:20 +00:00
Pekka Paalanen b3ba1becba libweston: remove fbdev backend
Fbdev backend was deprecated in the Weston 10.0.0 release with
6338dbd581. Before that, I suggested
already in 2019 to remove it, but it was too soon then. Now it seems the
final voices asking for fbdev to be kept have been satisfied, see the
linked issue.

Fbdev-backend uses a kernel graphics UAPI (fbdev) which is sub-par for a
Wayland compositor: you cannot do GPU accelerated graphics in any
reasonable way, no hotplug support, multi-output support is tedious, and
so on. Most importantly, Linux has deprecated fbdev a long time ago due
to the UAPI fitting modern systems and use cases very poorly, but cannot
get rid of it if any users remain. Let's do here what we can to reduce
fbdev usage.

I am doing color management related additions to libweston which require
adding checks to every backend. One backend less is less churn to write
and review.

Libweston major version has already been bumped to 11, so the next
release will be Weston 11, without fbdev. enum weston_compositor_backend
entries change their numerical values.

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

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-15 11:32:46 +02:00
Pekka Paalanen 18df9108ea man: replace tablet shell with kiosk shell
Tablet shell was removed in 873b515aee in
2013. Time to remove the hopefully last reference to it.

We also gained kiosk shell in the mean time, so mention that instead.
Yes, it's a bit of a lie, because we also have ivi-shell and
fullscreen-shell, but I heard they might be on their way out, so I
didn't add them here.

Would be nice to add kiosk-shell in the SHELLS section too, but in this
patch I am only concerned about dropping the tablet shell reference.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 19:42:33 +02:00
Pekka Paalanen bfefe8e8d4 man: add gbm-format in output section
Looks like at least from 2016 onwards the gbm-format option has also
been recognized in an output section.

Time to document that.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 19:42:33 +02:00
Pekka Paalanen ce059cffdb man: expand on gbm-format
Since 62a9436417 the gbm-format option has
recognized all pixel formats listed in libweston/pixel-formats.c.

Clarify what pixel formats can be used.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 19:42:33 +02:00
Pekka Paalanen 1f5e19fab3 man: move pageflip-timeout from weston.ini(5) to weston-drm(7)
This option is used only with the DRM-backend. Options in weston.ini(5)
should be either generic or for backends that do not have their own man
page yet.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 19:42:33 +02:00
Pekka Paalanen 79f73d2247 man: move gbm-format from weston.ini(5) to weston-drm(7)
This option is used only with the DRM-backend. Options in weston.ini(5)
should be either generic or for backends that do not have their own man
page yet.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 19:42:33 +02:00
Marius Vlad d284ab0322 pipewire,remoting,tests: Replace asprintf w/ str_printf
We have a string helper which wraps asprintf(). Uses that one because it
clears out the destination string, but also it won't return the number
of bytes unlinke asprintf().

Fixes warnings like:
warning: ignoring return value of ‘asprintf’ declared with attribute
‘warn_unused_result’.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-03-14 15:51:09 +02:00
Pekka Paalanen 3e94836a63 tests: add get_double in config-parser tests
weston_config_section_get_double() was not covered with tests before.

This patch follows the testing style already present in the file.

Cannot use ZUC_ASSERT_EQ() here, because that would convert the values
to integers before comparison. Luckily, simple strict equality
comparison works here, because we are testing conversion to float, not
the results of lossy calculations.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 08:50:30 +00:00
Pekka Paalanen 0a38fc7e75 shared: fix WL_EXPORT style in config-parser.c
This was the only file in Weston using WL_EXPORT on its own line. Fix
the style to follow everything else.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 08:50:30 +00:00
Pekka Paalanen f58a3a7e1d include: drop unused config-parser.h types
Apparently these are not used anywhere. Garbage-collect them, and trim
some empty lines.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-14 08:50:30 +00:00
Robert Mader 2669853562 clients/simple-dmabuf-feedback: Add fallback print method for unknown formats
Using `pixel_format_get_info()` can result in formats being
reported as `UNKNOWN` when used on compositors other than Weston.

As `weston-simple-dmabuf-feedback` somewhat succeeds `wayland-info`
as tool for `zwp_linux_dmabuf_v1` debugging from version 4 on, copy
the approach from the later for these cases.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-03-11 13:56:17 +01:00
Robert Mader f81aacdf2f pixel-formats: Add support for 64bbp float RGB formats
These are supported by some other compositors already.
Add them to the list so `weston-simple-dmabuf-feedback`
reports them correctly.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-03-11 13:55:19 +01:00
Marius Vlad c19cf3d684 libweston: Enable logging for libseat launcher
The built-in backend of libseat requires users to enable a logging
level in order for libseat to start writing out log messages.  For that
to happen we split out the info and error log level messages into the
compositor's log scope, while debug level messages go into a dedicated
scope.

With that, this patch brings in a new scope, called libseat-debug, which
users need to explicity create a subscription for it as to retrieve/have
access to debug message coming out of libseat. Note that by default we
have a subscription for the log-scope so any errors/info from libseat
would be displayed to the user.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-03-10 17:13:16 +02:00
Marius Vlad e9fe66a91c weston-log: Extract helper for generating a time stamp
As we might be needing it for other scopes extract the time stamp
genration into a helper.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-03-10 17:11:31 +02:00
Marius Vlad d40cedc8af desktop-shell: Remove wl_shell_surface::resize enum
And use the ones provided by libweston-desktop, as they are one
and the same.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-03-08 15:12:56 +02:00
Derek Foreman 7cae2a1fb0 backend-wayland: Stop supporting wl_shell
This has been deprecated for a long time, so let's stop supporting
it entirely.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-03-08 15:12:56 +02:00
Derek Foreman e6b8f5a5e4 remove wl_shell
This has been deprecated long enough, I think it's time to say goodbye.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-03-08 15:12:56 +02:00
Pekka Paalanen 5ba7ae2937 tests: preserve ivi runner section
Everywhere else where use this trick, we also have 'used' in the
attributes, except here. Make this consistent.

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

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-08 14:50:41 +02:00
Michael Olbrich 78c94d0719 libweston: explicitly cancel start_drag if no matching input device is found
Otherwise, the client will assume that dragging is in progress and remains in
that state forever.
This can happen when weston processes the mouse up event just before the
start_drag() arrives.

Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
2022-03-04 11:51:01 +00:00
Pekka Paalanen 4fb095eca1 doc: running on different seat with libseat
When using the libseat launcher, there is one more detail to take care:
stop libseat from managing the VT.

A normal user does not have permissions to manage a VT, so launching
would just fail. In this use case you also do not want to be managing
the VT, because your normal desktop is already owning the seat
associated with the VT.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-04 11:22:47 +00:00
Pekka Paalanen c26326bfb1 doc: expand on libseat via ssh
Give a little more details about how running Weston via ssh or serial
terminal is best done, now that launcher-direct and weston-launch are
gone.

Hopefully the removal of launcher-direct also makes less people run
Weston as root, when seatd is the privileged process. Running 'weston'
as root might still work through libseat's builtin backend without
seatd.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-04 11:41:42 +02:00
Pekka Paalanen 952a951662 build: enable libseat support by default
Now that launcher-direct and weston-launch are gone, libseat takes their
place.

Enable libseat support by default to give users a hint in case they miss
either of those.

People who used to get launcher-logind when libseat support was disabled
will now be using logind through libseat. This should not cause any
regressions, and if it does, we want to hear about them, because the
separate logind-launcher is also planned to be deprecated in the future.

Disabling logind-launcher by default is left for when it actually gets
deprecated.

In case someone does not have libseat available but do have logind
running, they can just disable libseat support.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-04 11:20:16 +02:00
Derek Foreman 2c91c70250 launchers: Remove --tty option
This doesn't work with any of the launchers we've kept. Remove the option
and all the bits that handle it.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-03-03 17:00:15 -06:00
Derek Foreman a96dfc7098 launchers: remove launchers
Moving forward we're going to be supporting libseat and logind as our
only launchers. We're doing this to reduce our maintenance burden,
and security impact.

Libseat supports all our existing use cases, and seatd can replace
weston-launch so we no longer have to carry a setuid-root program.

This patch removes weston-launch, and launcher-direct, leaving only
libseat and logind.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-03-03 16:54:14 -06:00
Vitaly Prosyak 87f2d09f18 color-lcms: Always use cmsContext for LCMS API which has THR suffix
Fix a typo. No CM functional change, just redirect LCMS error
into  created cmsContext which output into weston log.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-03-01 22:49:39 -05:00
Pekka Paalanen e2ee2b56f9 tests: make vertex-clip use WESTON_EXPORT_FOR_TESTS
This is probably the simplest case to demonstrate how to use
WESTON_EXPORT_FOR_TESTS.

Previously, vertex-clip test re-built vertex-clipping.c for itself. Now
it directly links in gl-renderer.so instead as that is where
vexter-clipping.c gets built into for actual use. This probably will not
work for any installed program, but luckily tests are never installed,
so Meson makes sure the DSO is found.

Unfortunately we cannot remove the definition of dep_vertex_clipping
yet, because clients/cliptest.c needs it.

This makes vertex-clip test depend on GL-renderer, but that is where the
code is really used.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-01 13:32:15 +00:00
Pekka Paalanen 32a790f774 shared: add WESTON_EXPORT_FOR_TESTS
This is a new function exporting macro that intends to make writing unit
tests in the Weston test suite easier.

A test needs to access a private function to be able to verify its
behavior. Previously we have used things like putting such functions in
a separate .c file and then building that file into the corresponding
test. That is a bit awkward and can lead to proliferation of arbitrary
.c files for no good reason. It may also require pre-processor magic,
and sometimes copying chunks of code causing a risk of deviating the
code being tested from the code actually used.

This patch proposes another approach: a private export from a DSO.
Except, private exports do not really exist, and this is just a normal
export with a specific C macro, and omitting the function from public
headers.

Once exported, a test program can link the DSO during build, be that a
shared library or even a plugin, use the private header declaring the
function, and simply call the function in the test.

The declaration of WESTON_EXPORT_FOR_TESTS is in shared/helpers.h so
that it is available to all components equally while still not being in
a public header. Other places that were considered:

- include/libweston/libweston.h is a public header, but external users
  should not know about the macro.

- libweston/libweston-private.h is too private and not available to all
  components, particularly color-lcms plugin.

- libweston/backend.h is not appropriate for color-lcms plugin either.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-03-01 13:32:15 +00:00
nerdopolis 8e2c67c317 clients/desktop-shell: Add a displayname= option for launchers
Signed-off-by: n3rdopolis <bluescreen_avenger@verizon.net>
2022-02-24 00:38:55 +02:00
James Le Cuirot 89587db3cb meson.build: Fix -Dbackend-default=auto following fbdev deprecation
Signed-off-by: James Le Cuirot <chewi@gentoo.org>
2022-02-23 15:57:57 +02:00
Takuro Ashie 351e6a4b21 Don't send compositor's global key bindings to the input method
Although weston_compositor_run_key_binding() is called when the current
keyboard grab is default_grab or input_method_grab, swallowing the key
event is processed only on default_grab. As a result key events that
should be swallowed are sent to the input method unexpectedly.

For example, when a user press `Super + s` on weston-editor to take a
screen shot, `s` will be unexpectedly entered to the text area.
I confirmed such behaviour with weston-simple-im and fcitx5-5.0.10.
It doesn't occur with weston-keyboard because it doesn't install
keyboard grab.

Signed-off-by: Takuro Ashie <ashie@clear-code.com>
2022-02-23 15:40:33 +02:00
Pekka Paalanen 29d4472e13 tests: use color_float rgb[] alias more
Iterate over rgb[] array instead of repeating the code for .r, .g and
.b.

Also in process_pipeline_comparison() f_max_err variable is dropped
since it was not used much.

This should make the code easier to read.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-02-18 15:22:44 +00:00
Pekka Paalanen 4012062228 tests: add rgb[] alias in color_float
Individual struct fields are inconvenient to index into, yet most
operations on a color just repeat the same for each of RGB channel.
Being able to index into RGB avoids repeating the same code for each
channel.

Alpha channel is left as separate, since it is almost never handled the
same as RGB.

The union keeps the old .r, .g and .b addressing working. The static
asserts ensure the aliasing is correct.

For demonstration, two simple functions in color_util.c are converted.

Unfortunately initializers need to be corrected everywhere. Field .a is
not explicitly initialized because it is unused in these cases.

This change should make code easier to read.

This change requires gnu99 or c11 standard. gnu99 is already the default
in top-level meson.build.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-02-18 15:22:44 +00:00
Daniel Stone 2ac6b6b084 tests: Add dependency on screenshooter client protocol
Given that the test-helper code relies on the screenshooter protocol,
make sure it's available for us to build, and the dependency ensures we
build in order.

Fixes: #588

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-18 12:24:01 +00:00
Robert Mader 3e6ef529f8 clients/simple-dmabuf-*: Increase buffer limit to four
In certain situations these clients crash a lot due to the low
buffer limit. Four buffers is also what EGL allows without blocking
and what is arguably the upper limit of what a compositor should
demand.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-02-17 12:26:41 +01:00
Vitaly Prosyak fe35ca2d68 tests: color shaper-matrix test
1. Use fixture_setup to set the generated by LCMS output profile based on
   given chromaticities and white points. The following  list of well known
   chromaticities:
    - sRGB
    - adobe RGB
    - bt2020
   and white point is D65. Use INTENT_ABSOLUTE_COLORIMETRIC to avoid BPC.
   Input profile is always sRGB and it is used internally by Weston as
   stock profile.

2. Use these hardcoded matrixes as part of pipeline 1DLUT->3x3->1DLUT.
   The diagnostic code to retrieve the transform matrix is availble into
   test in the comments. The conversion matrixes generated for the
   following cases:
    - sRGB to sRGB (unity)
    - sRGB to adobeRGB
    - sRGB to BT2020
3. Compare GPU shaders(gl texture3D) vs manual pipeline calculation
   Use different max tolerable error per transform.
   There are comments how number of points in 3DLUT is related to tolerance.
   Tolerance depends more on the 1D LUT used for the inv EOTF than
   the tested 3D LUT size: 9x9x9, 17x17x17, 33x33x33, 127x127x127.

4. Enable build matrix-shaper test if color-management-lcms is enabled.

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-12 23:19:02 -05:00
Vitaly Prosyak 264a18f01a tests: shared color processing functions
Added pixel pipeline processing as following:
tone curve(EOTF) + 3x3 matrix + tone curve(INV_EOTF)

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-12 23:19:02 -05:00
Vitaly Prosyak 6099c0e24b color-lcms: LCMS transform for color mapping
Use 3D LUT for color mapping.
For category CMLCMS_CATEGORY_INPUT_TO_BLEND use transform which has
3 profiles: input, output and light linearizing transfer function.
For category CMLCMS_CATEGORY_INPUT_TO_OUTPUT use input and output profiles +VCGT.
For category CMLCMS_CATEGORY_BLEND_TO_OUTPUT use output inverse EOTF + VCGT.

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-12 23:19:00 -05:00
Vitaly Prosyak c199aade3f color-lcms: linearization of an arbitrary color profile
Graeme sketched a linearization method there:
https://lists.freedesktop.org/archives/wayland-devel/2019-March/040171.html
Sebastian prototyped there:
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/14/commits

Thanks to Pekka for great simplifications in implementation, like the xyz_dot_prod()
Quote: "should help untangle lots of the multiplications and summations by saying
we are computing dot products, etc".

The approach was validated using matrix-shaper and cLUT type of profiles.
If profile is matrix-shaper type then an optimization is applied.
The extracted EOTF is inverted and concatenated with VCGT, if it is availible.
Introduce function cmlcms_reasonable_1D_points which would be shared between
linearization method and number of points in 1DLUT for the transform.
Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-11 13:06:11 -05:00
Vitaly Prosyak 37e0d54cc9 color-lcms: add matches parameters based on category
Use category, intent and output and input profiles
for comparison.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-11 12:58:02 -05:00
Vitaly Prosyak 19913366e8 color-lcms: add new fields for transform search parameter
Add to search parameter cmlcms_category, input and output profiles,
and render intent for output which would be used for both profiles.
Add common function setup_search_param for every category.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-11 12:58:00 -05:00
Vitaly Prosyak 19f318692e color-lcms: introduce sRGB stock profile
The stock profile would be used when client or output
do not provide any profile or unaware of color management.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-11 12:56:57 -05:00
Vitaly Prosyak a92fa34d1d color-lcms: add wrapper API for refcounting cmlcms_color_profile
It is used for convenience when profile is cached.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-09 20:42:50 -05:00
Vitaly Prosyak 494ff5b23b color-lcms: introduce cmlcms_category, EOTF and INV EOTF
1. The cmlcms_category is used to identify the purpose of transform:
   - CMLCMS_CATEGORY_INPUT_TO_BLEND
   - CMLCMS_CATEGORY_BLEND_TO_OUTPUT
   - CMLCMS_CATEGORY_INPUT_TO_OUTPUT

2. Added following fields to cmlcms_color_profile:

   - output_eotf - If the profile does support being an output profile and it
     is used as an output then this field represents a light linearizing
     transfer function and it can not be null. The field is null only if
     the profile is not  usable as an output profile. The field is set when
     cmlcms_color_profile  is created.

   - vcgt - VCGT tag cached from output profile, it could be null if not exist

   - output_inv_eotf_vcgt - if the profile does support being an output profile and it
     is used as an output then this field represents a concatenation of inverse
     EOTF + VCGT, if the tag exists and it can not be null.

3. Added field cmsHTRANSFORM to cmlcms_color_transform.
   It is used to store LCMS optimized pipeline.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-09 20:42:50 -05:00
Vitaly Prosyak 93c6180c71 gl-renderer: shaders implementation of color mapping function
The following GL extensions provide support for shaders CM:
 -GL_OES_texture_float_linear makes GL_RGB32F linear filterable.
 -GL ES 3.0 provides Texture3D support in GL API.
 -GL_OES_texture_3D provides sampler3D support in ESSL 1.00.

If abovesaid is supported then renderer sets flag WESTON_CAP_COLOR_OPS
which means that all fields in struct weston_color_transform are
supported, for example, 1DLUT and 3DLUT.

Use GL_OES_texture_3D to implement 3DLUT function which
uses trilinear interpolation for pixel processing or bypass as is.
Quote from https://nick-shaw.github.io/cinematiccolor/luts-and-transforms.html
"3D LUTs have long been embraced by color scientists and are one of
the tools commonly used for gamut mapping. In fact, 3D LUTs are used
within ICC profiles to model the complex device behaviors necessary
for accurate color image reproduction".
Quote from https://developer.nvidia.com/gpugems/gpugems2/part-iii-high-quality-rendering/
chapter-24-using-lookup-tables-accelerate-color
is about interpolation: "By generating intermediate results based
on a weighted average of the eight corners of the bounding cube,
this algorithm is typically sufficient for color processing,
and it is implemented in graphics hardware".

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-09 20:42:50 -05:00
Vitaly Prosyak cda130e4b0 gl-renderer: add declaration of color mapping function
Introduce shader color mapping identity and 3D LUT.
Shader requirements struct uses union for color mapping
to prepare the place for 3x3 matrix.

Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-09 20:42:50 -05:00
Vitaly Prosyak 2e2ad02d5c libweston: add definition of color mapping function
Introduce 3D LUT definition as part of Weston
color transform struct. A 3D LUT is a LUT containing
entries for each possible RGB triplets.
Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
2022-02-09 20:42:50 -05:00
Leandro Ribeiro 08dbd29e33 gitlab-ci: compile Linux image with support to VGEM
Add VGEM to the Linux image that runs in the CI. There are tests that we
plan to add in the future that need this.

This brings a complication, as we already have VKMS in the image. The
order in which DRM devices are loaded is not always the same, so the
node they receive is non-deterministic. Until now we were sure that VKMS
(the virtual device we use to run the DRM-backend tests in the CI) would
be in "/dev/dri/card0", but now we can't be sure. To deal with this
problem we find the node of each device using a one-liner shell script.

This commit also updates the documentation section that describes
specificities of DRM-backend tests in our test suite.

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
2022-02-09 08:13:50 +00:00
Daniel Stone ce8ead4bf7 debug: Show client PID in debug protocol stream
Make it slightly easier to disambiguate clients when we log the protocol
stream from the server side.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-08 09:48:48 +02:00
Marek Vasut b03195a8f7 screen-share: Name the seat "screen-share"
Name the seat created by the screen share plugin "screen-share" instead of
"default", to make it easier to recognize. No functional change intended.

Signed-off-by: Marek Vasut <marex@denx.de>
2022-02-08 09:41:24 +02:00
Marius Vlad 0b5c75f540 backend-drm/state-propose: Missing some newlines
It would look much better if the debug is printed separately.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-02-07 17:58:35 +02:00
Robert Mader c83f0a1539 tests: Add test for subsurfaces mapping hierachies
Test different scenarios where child subsurfaces of unmapped
subsurfaces would get mapped. This test will fail in various
ways without the commit
"libweston/compositor: Do not map subsurfaces without buffer"

Also try to test potential regressions of that patch.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-02-07 12:16:16 +00:00
Robert Mader 8b04534c76 libweston/compositor: Do not map subsurfaces without buffer
We can end in `subsurface_committed()` in different scenarios
without the surface having an attached buffer. While setting
the mapped state to `true` in that case doesn't matter for
that (sub)surface itself, it triggers its own child subsurfaces
to get mapped when they shouldn't.

Closes https://gitlab.freedesktop.org/wayland/weston/-/issues/426

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-02-07 12:16:16 +00:00
Marius Vlad 73b17da7d5 meson.build: Bump libweston major version
With commit 'compositor: Remove desktop zoom' weston_output_zoom was removed
from weston_output thus needing a libweston major bump.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Suggested-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2022-02-04 12:13:33 +02:00
Marius Vlad 2ab726b421 weston.ini.man: Clarify what startup-animation means
This isn't about opening new windows but the start-up animation
that desktop-shell does when it is being brought on/started.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-02-03 16:35:01 +00:00
Simon Ser 7e70f9016a clients: drop weston-info
Users should rely on wayland-info from wayland-utils [1] instead.
We've been printing a deprecation since 85382d394a ("clients:
deprecate weston-info"), so users should be aware already.

[1]: https://gitlab.freedesktop.org/wayland/wayland-utils/

Signed-off-by: Simon Ser <contact@emersion.fr>
2022-02-03 16:19:27 +00:00
Veeresh Kadasani 773bcf9097 man: Document available debug bindings.
Fixes: #398

Debug bindings were not documented in
weston-bindings so document them.

Signed-off-by: Veeresh Kadasani <veeresh.kadasani@huawei.com>
2022-02-03 16:11:59 +00:00
Derek Foreman 83927bb0e6 launcher-logind: Remove systemd-logind support
Many years ago (2014) systemd-logind was brought into libsystemd.
We've supported old versions of systemd-logind ever since.

Let's remove support for old versions of systemd-logind before the
merge for a tiny code simplification.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-02-03 16:00:26 +00:00
Derek Foreman 66374d48f1 compositor: Remove desktop zoom
Zoom is a neat trick, but in its current form it's very hard to test
and maintain.

It also causes output damage to scale outside of the output's boundaries,
which leads to an extra clipping step that's only necessary when zoom
is enabled.

Remove it to simplify desktop-shell and compositor.

Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
2022-02-03 15:51:20 +00:00
Robert Mader dc3b349325 tests: Add test for synced subsurfaces and buffer damage
Changing `wl_surface_damage()` to `wl_surface_damage_buffer()`
should not have an effect on the existing tests.
The new test will fail without the commit
"libweston/compositor: Cache buffer damage for synced subsurfaces"

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-02-03 15:44:47 +00:00
Robert Mader 933290e6ea libweston/compositor: Cache buffer damage for synced subsurfaces
The spec states:
> Because buffer transformation changes and damage requests may be
> interleaved in the protocol stream, it is impossible to determine
> the actual mapping between surface and buffer damage until
> wl_surface.commit time. Therefore, compositors wishing to take both
> kinds of damage into account will have to accumulate damage from the
> two requests separately and only transform from one to the other after
> receiving the wl_surface.commit.

For subsurfaces in sync mode, arguably the same is the case until the
cached state gets applied eventually. Thus, in order to keep complexity
to a sane level, just accumulate buffer damage and convert it only
when the cached state gets applied.

This mirrors how other compositors like Mutter implement cached damage
and what the spec arguably should demand.

Closes https://gitlab.freedesktop.org/wayland/weston/-/issues/446

Signed-off-by: Robert Mader <robert.mader@collabora.com>
2022-02-03 15:44:47 +00:00
Marius Vlad f3221832c5 kiosk-shell: Favor out views on same output
In multiple output cases, finding the succesor from the inactive layer
might result in picking the wrong view when there are multiple views
being stacked in the inactive layer. This adds two additional checks to
favor views on the same output as the one being destroyed/removed.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-02-03 15:37:03 +00:00
Marius Vlad f3ad593925 kiosk-shell: Don't occlude shsurf on other outputs
This adds an additional check to make sure the current focus surface
is on the same output as the surface that is going to be activated.

This is necessary in order to avoid placing the currently focused one in
the inactive layer, which shouldn't happen in situations where the new
surface is going to be placed on a different output than the currently
focused one.

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-02-03 15:37:03 +00:00
Marius Vlad 8a1849db8a kiosk-shell: Check if app_ids have been set after initial commit
Some applications would set-up the app_id after the initial commit
(without a buffer) which is too late to correctly assign the application
to the corresponding output set-up in the configuration file.

This patch fixes that by checking one more time, after a buffer has been
attached, if indeed there's an output with an app_id set.

Fixes: #469

Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
2022-02-03 15:37:03 +00:00
Manuel Stoeckl b0ed4a2e3b gl-renderer: add support for (a|x)bgr16161616 shm formats
These formats are useful because they are often easier to produce
on CPU than half-float formats, and abgr16161616 has both >= 10bpc
color channels and adequate alpha, unlike abgr2101010.

The 16-bpc textures created from buffers with these formats require
the GL_EXT_texture_norm16 extension.

As WL_SHM_FORMAT_ABGR16161616 was introduced in libwayland 1.20,
update Weston's build requirements and CI.

The formats also needed to be registered in the pixel format table,
and defined in a fallback path if recent libdrm is not available.

Signed-off-by: Manuel Stoeckl <code@mstoeckl.com>
2022-02-02 11:58:58 +00:00
Daniel Stone 30de938624 backend-drm: Add more view-to-plane failure states
Specifically log if there were no suitable planes for us to use, or if
we tried to place it on a plane but were told no by the kernel.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone a2c5709e71 backend-drm: Pass paint node through to plane_state find
This lets us clean up a bit of code.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 0ace8b66af backend-drm: Unify overlay/primary view->plane code
There's no real reason for these to be separate now that the eligibility
checks have been moved up so we don't call them unless it makes sense.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 81e74ff334 backend-drm: Don't take buffer-release reference for cursor views
We just copy the SHM buffer straight into a separately-allocated GBM BO,
so no need to take a reference on the buffer itself or keep it from
being released.

All drm_output_try_view_on_plane really does at this point is to call
the prepare_*_view function for the requisite plane type, and take a ref
on the weston_buffer from the client. Given that we don't need to keep
the client buffer alive, we can short-circuit
drm_output_try_view_on_plane, and instead just call
drm_output_prepare_cursor_view directly when we have a cursor plane.

This also makes it easier to just remove drm_output_try_view_on_plane in
following patches when we merge the overlay/scanout plane path into one.
Doing so gives us two clearly-separated paths: one for copying a SHM
client buffer into a cursor, and another for directly scanning out
client content.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 873e32137e backend-drm: Remove unnecessary check for fb
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone e1114228f5 backend-drm: Remove unused enum
At some point this got hobbled, such that NO_PLANES and
NO_PLANES_ACCEPTED became the same thing, so we can just check if the
returned plane_state is NULL or not.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 2dd3af3c22 backend-drm: Move IN_FENCE_FD check to common code
No need for this to be specialised within both overlay and scanout plane
paths.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 1b34c5cd80 backend-drm: Remove unnecessary check in prepare_scanout_view
We already guarantee this from the caller.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 6b828c7b57 backend-drm: Don't try non-fullscreen views on the primary plane
You'd think this would go without saying, but no, we just sort of buried
that.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone dc0de9ee2b backend-drm: Move overlay vs. primary plane check earlier
For views which cover the entire output, we always attempt to place them
on the primary plane, to avoid a situation where we place a fullscreen
view into an overlay plane and then have to disable the primary plane,
which doesn't always work.

Move this check earlier, so we don't consider overlay planes to be
candidates for fullscreen views. This check should be changed in future
to only filter for opaque views, but that's for another time.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 5e41b44b10 backend-drm: Change cursor checks to asserts
We shouldn't get down into trying to place a view on a cursor plane if
these checks are not met, so change them to asserts rather than early
returns.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone b3d7df5c3e backend-drm: Move plane-type-specific checks to switch statement
This makes it a bit more clear and easy to follow, rather than diving
through if nesting.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 0ecd6c3d33 backend-drm: Move renderer-only vs. scanout_plane test earlier
No point trying to put something on the scanout plane in mixed mode.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone ae60745b61 backend-drm: Move cursors_are_broken test earlier
No point trying to place a cursor buffer on a plane when we can't do
cursor planes.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone e5ad3c8865 backend-drm: Remove separate zpos_plane list
When we introduced support for variable zpos, we did so by filtering the
list of acceptable planes and then creating a separate zpos-ordered
list. Now that the planes are already zpos-sorted in the backend list,
and we have more early filtering, we can replace this with a single
plane-list walk.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 23257c073f backend-drm: Minor comment rewording
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 26c2f9a65f backend-drm: Don't try cursor buffers for client planes
For better or worse, cursor planes can only be used by uploaded SHM
buffers right now, so ignore them when we're calculating the acceptable
plane mask for client dmabufs.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 9c6a069435 backend-drm: Early-out for non-SHM buffers in renderer-only mode
If we're in renderer-only mode, we can only use the renderer and the
cursor plane. Don't even try to import client buffers as it makes no
sense.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 6aec64b2f7 backend-drm: Early-out for too-large SHM/cursor buffers
We know what our limit is for cursor planes, so don't try to assign a
view which is too large.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone ca4c2865e9 backend-drm: Early-out for cursor plane format testing
If we have a SHM buffer, it can only go into a cursor plane - and only
then if it's of the right format.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 66244856e2 backend-drm: Don't try to import SHM buffers as drm_fb
It won't work.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone d5ec9a1a1d backend-drm: Don't try to steal other-output special planes
Each output is hardcoded to the use of a single 'special' (primary or
cursor) plane; make sure we don't try to steal them from other outputs
which might not be happy to discover that we've taken it off them.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 075c4ac286 backend-drm: Don't try to use planes without GBM
GBM is how we import all our client content into DRM FBs, so don't try
anything other than renderer-only without it.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone af42fc1e33 backend-drm: Assign plane_idx by plane list order
Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 6609840479 backend-drm: Pre-sort plane list by zpos
Rather than constructing a zpos-sorted list every time, just have
plane_list be pre-sorted.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Daniel Stone 7ca7c14553 backend-drm: Rewrite zpos-sorting list insertion
It's possible to write this with a few less twisty special cases. Tested
manually with a randomly-distributed input tree as well as manually
trying to hit special cases around first/last entries.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2022-02-01 23:12:11 +00:00
Simon Ser 2833c28ff1 build: re-open main for regular development 2022-02-01 23:16:03 +01:00
217 changed files with 15670 additions and 15764 deletions
+4 -5
View File
@@ -43,7 +43,7 @@
variables: variables:
FDO_UPSTREAM_REPO: wayland/weston FDO_UPSTREAM_REPO: wayland/weston
FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH" FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH"
FDO_DISTRIBUTION_TAG: '2021-11-25.0-dmabuf-feedback' FDO_DISTRIBUTION_TAG: '2022-07-13.00-wayland-protocols-1.26'
include: include:
@@ -202,7 +202,7 @@ aarch64-debian-container_prep:
- $BUILDDIR/weston-virtme - $BUILDDIR/weston-virtme
- $PREFIX - $PREFIX
reports: reports:
junit: $BUILDDIR/meson-logs/testlog.junit.xml junit: $BUILDDIR/meson-logs/testlog-per-test-asan.sh.junit.xml
# Same as above, but without running any tests. # Same as above, but without running any tests.
.build-no-test: .build-no-test:
@@ -283,8 +283,8 @@ aarch64-debian-container_prep:
-Dwerror=true -Dwerror=true
-Dtest-skip-is-failure=true -Dtest-skip-is-failure=true
-Dlauncher-libseat=true -Dlauncher-libseat=true
-Ddeprecated-backend-fbdev=true -Ddeprecated-color-management-static=true
-Ddeprecated-weston-launch=true -Ddeprecated-color-management-colord=true
after_script: after_script:
- ninja -C "$BUILDDIR" coverage-html > "$BUILDDIR/meson-logs/ninja-coverage-html.txt" - ninja -C "$BUILDDIR" coverage-html > "$BUILDDIR/meson-logs/ninja-coverage-html.txt"
- ninja -C "$BUILDDIR" coverage-xml - ninja -C "$BUILDDIR" coverage-xml
@@ -340,7 +340,6 @@ docs-build:
-Dpipewire=false -Dpipewire=false
-Dwerror=true -Dwerror=true
-Dlauncher-libseat=true -Dlauncher-libseat=true
-Ddeprecated-weston-launch=true
x86_64-debian-no-gl-build: x86_64-debian-no-gl-build:
extends: extends:
+17 -6
View File
@@ -75,7 +75,8 @@ if [[ -n "$KERNEL_DEFCONFIG" ]]; then
--enable CONFIG_DRM \ --enable CONFIG_DRM \
--enable CONFIG_DRM_KMS_HELPER \ --enable CONFIG_DRM_KMS_HELPER \
--enable CONFIG_DRM_KMS_FB_HELPER \ --enable CONFIG_DRM_KMS_FB_HELPER \
--enable CONFIG_DRM_VKMS --enable CONFIG_DRM_VKMS \
--enable CONFIG_DRM_VGEM
make ARCH=${LINUX_ARCH} oldconfig make ARCH=${LINUX_ARCH} oldconfig
make ARCH=${LINUX_ARCH} make ARCH=${LINUX_ARCH}
@@ -94,7 +95,7 @@ fi
# Build and install Wayland; keep this version in sync with our dependency # Build and install Wayland; keep this version in sync with our dependency
# in meson.build. # in meson.build.
git clone --branch 1.18.0 --depth=1 https://gitlab.freedesktop.org/wayland/wayland git clone --branch 1.20.0 --depth=1 https://gitlab.freedesktop.org/wayland/wayland
cd wayland cd wayland
git show -s HEAD git show -s HEAD
mkdir build mkdir build
@@ -106,7 +107,7 @@ rm -rf wayland
# Keep this version in sync with our dependency in meson.build. If you wish to # 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 # raise a MR against custom protocol, please change this reference to clone
# your relevant tree, and make sure you bump $FDO_DISTRIBUTION_TAG. # your relevant tree, and make sure you bump $FDO_DISTRIBUTION_TAG.
git clone --branch 1.24 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols git clone --branch 1.26 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
cd wayland-protocols cd wayland-protocols
git show -s HEAD git show -s HEAD
meson build meson build
@@ -129,6 +130,17 @@ ninja ${NINJAFLAGS} -C build install
cd .. cd ..
rm -rf mesa rm -rf mesa
# 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. We can stop
# building and installing libdrm as soon as we move to Debian 12.
git clone --branch libdrm-2.4.108 --depth=1 https://gitlab.freedesktop.org/mesa/drm.git
cd drm
meson build -Dauto_features=disabled \
-Dvc4=false -Dfreedreno=false -Detnaviv=false
ninja ${NINJAFLAGS} -C build install
cd ..
rm -rf drm
# PipeWire is used for remoting support. Unlike our other dependencies its # 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 # 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. # stable, so again we lock it to a fixed version.
@@ -142,9 +154,8 @@ ninja ${NINJAFLAGS} -C build install
cd .. cd ..
rm -rf pipewire-src rm -rf pipewire-src
# seatd lets us avoid the pain of handling VTs manually through weston-launch # seatd lets us avoid the pain of open-coding TTY assignment within Weston.
# or open-coding TTY assignment within Weston. We use this for our tests using # We use this for our tests using the DRM backend.
# the DRM backend.
git clone --depth=1 --branch 0.6.1 https://git.sr.ht/~kennylevinsen/seatd git clone --depth=1 --branch 0.6.1 https://git.sr.ht/~kennylevinsen/seatd
cd seatd cd seatd
meson build -Dauto_features=disabled \ meson build -Dauto_features=disabled \
+2
View File
@@ -39,6 +39,7 @@ apt-get -y --no-install-recommends install \
clang-11 \ clang-11 \
curl \ curl \
doxygen \ doxygen \
graphviz \
freerdp2-dev \ freerdp2-dev \
gcovr \ gcovr \
git \ git \
@@ -68,6 +69,7 @@ apt-get -y --no-install-recommends install \
libmtdev-dev \ libmtdev-dev \
libpam0g-dev \ libpam0g-dev \
libpango1.0-dev \ libpango1.0-dev \
libpciaccess-dev \
libpixman-1-dev \ libpixman-1-dev \
libpng-dev \ libpng-dev \
libpulse-dev \ libpulse-dev \
+6
View File
@@ -3,3 +3,9 @@
# Cairo internal leaks from weston-keyboard # Cairo internal leaks from weston-keyboard
leak:cairo_select_font_face leak:cairo_select_font_face
leak:cairo_text_extents leak:cairo_text_extents
# Pango thread-global state (not destroyable?)
leak:pango_language_get_default
# This leaks in Debian's fontconfig/Xwayland setup?
leak:FcConfigSubstituteWithPat
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# When running Debian's Xwayland and fontconfig, we hit memory leaks which
# aren't visible on other setups. We do have suppressions for these tests, but
# regrettably ASan can't see through omitted frame pointers in Expat, so for
# Xwayland specifically, we disable fast-unwind.
#
# Doing it globally makes the other tests far, far, too slow to run.
case "$1" in
*xwayland*)
export ASAN_OPTIONS="detect_leaks=0,fast_unwind_on_malloc=0"
;;
*)
export ASAN_OPTIONS="detect_leaks=0"
;;
esac
export ASAN_OPTIONS
exec "$@"
+14 -3
View File
@@ -7,8 +7,15 @@ chmod -R 0700 /tmp
# set environment variables to run Weston tests # set environment variables to run Weston tests
export XDG_RUNTIME_DIR=/tmp/tests export XDG_RUNTIME_DIR=/tmp/tests
export WESTON_TEST_SUITE_DRM_DEVICE=card0
export LIBSEAT_BACKEND=seatd export LIBSEAT_BACKEND=seatd
# In our test suite, we use VKMS to run DRM-backend tests. The order in which
# 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/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 # 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). # $HOME/.local/lib/pythonX.Y/site-packages (the Python version may differ).
@@ -19,13 +26,17 @@ export HOME=/root
export PATH=$HOME/.local/bin:$PATH export PATH=$HOME/.local/bin:$PATH
export PATH=/usr/local/bin:$PATH export PATH=/usr/local/bin:$PATH
export ASAN_OPTIONS=detect_leaks=0,atexit=1
export SEATD_LOGLEVEL=debug export SEATD_LOGLEVEL=debug
# Terrible hack, per comment in weston-test-runner.c's main(): find Mesa's
# 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 # run the tests and save the exit status
# we give ourselves a very generous timeout multiplier due to ASan overhead # we give ourselves a very generous timeout multiplier due to ASan overhead
echo 0x1f > /sys/module/drm/parameters/debug echo 0x1f > /sys/module/drm/parameters/debug
seatd-launch -- meson test --no-rebuild --timeout-multiplier 4 seatd-launch -- meson test --no-rebuild --timeout-multiplier 4 \
--wrapper $(pwd)/../.gitlab-ci/virtme-scripts/per-test-asan.sh
# note that we need to store the return value from the tests in order to # note that we need to store the return value from the tests in order to
# determine if the test suite ran successfully or not. # determine if the test suite ran successfully or not.
TEST_RES=$? TEST_RES=$?
+4
View File
@@ -208,6 +208,10 @@ my_function(void)
parameter3, parameter4); parameter3, parameter4);
``` ```
- do not write fallback paths for failed simple memory allocations, use the
`x*alloc()` wrappers from `shared/xalloc.h` instead or use
`abort_oom_if_null()`
Conduct Conduct
======= =======
+8 -18
View File
@@ -18,6 +18,12 @@ bugs and shortcomings, we avoid unknown or variable behaviour as much as
possible, including variable performance such as occasional spikes in frame possible, including variable performance such as occasional spikes in frame
display time. display time.
Weston and libweston are not suitable for memory constrained environments
where the compositor is expected to continue running even in the face of
trivial memory allocations failing. If standard functions like `malloc()`
fail for small allocations,
[you can expect libweston to abort](https://gitlab.freedesktop.org/wayland/weston/-/issues/631).
A small suite of example or demo clients are also provided: though they can be A small suite of example or demo clients are also provided: though they can be
useful in themselves, their main purpose is to be an example or test case for useful in themselves, their main purpose is to be an example or test case for
others building compositors or clients. others building compositors or clients.
@@ -93,13 +99,6 @@ the available configuration options and display backends. It can also be
configured through a file on disk; more information on this can be found through configured through a file on disk; more information on this can be found through
`man weston.ini`. `man weston.ini`.
In some special cases, such as when running remotely or without logind's session
control, Weston may not be able to run directly from a text console. In these
situations, you can instead execute the `weston-launch` helper, which will gain
privileged access to input and output devices by running as root, then granting
access to the main Weston binary running as your user. Running Weston this way
is not recommended unless necessary.
Documentation Documentation
============= =============
@@ -294,7 +293,7 @@ Details:
- Child process execution and management will be outside of libweston. - Child process execution and management will be outside of libweston.
- The different backends (drm, fbdev, x11, etc) will be an internal - The different backends (drm, x11, etc) will be an internal
detail of libweston. Libweston will not support third party detail of libweston. Libweston will not support third party
backends. However, hosting programs need to handle backends. However, hosting programs need to handle
backend-specific configuration due to differences in behaviour and backend-specific configuration due to differences in behaviour and
@@ -308,19 +307,12 @@ Details:
- xwayland ??? - xwayland ???
- weston-launch is still with libweston even though it can only launch
Weston and nothing else. We would like to allow it to launch any compositor,
but since it gives by design root access to input devices and DRM, how can
we restrict it to intended programs?
There are still many more details to be decided. There are still many more details to be decided.
For packagers For packagers
------------- -------------
Always build Weston with --with-cairo=image.
The Weston project is (will be) intended to be split into several The Weston project is (will be) intended to be split into several
binary packages, each with its own dependencies. The maximal split binary packages, each with its own dependencies. The maximal split
would be roughly like this: would be roughly like this:
@@ -337,15 +329,13 @@ would be roughly like this:
- xwayland (depends on X11/xcb libs) - xwayland (depends on X11/xcb libs)
- fbdev-backend (depends on libudev...)
- rdp-backend (depends on freerdp) - rdp-backend (depends on freerdp)
- weston (the executable, not parallel-installable): - weston (the executable, not parallel-installable):
+ desktop shell + desktop shell
+ ivi-shell + ivi-shell
+ fullscreen shell + fullscreen shell
+ weston-info (deprecated), weston-terminal, etc. we install by default + weston-terminal, etc. we install by default
+ screen-share + screen-share
- weston demos (not parallel-installable) - weston demos (not parallel-installable)
+29 -63
View File
@@ -41,22 +41,23 @@
#include <assert.h> #include <assert.h>
#include <wayland-client.h> #include <wayland-client.h>
#include "window.h"
#include "shared/cairo-util.h"
#include <libweston/config-parser.h> #include <libweston/config-parser.h>
#include <libweston/zalloc.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/xalloc.h" #include "shared/xalloc.h"
#include <libweston/zalloc.h> #include "shared/cairo-util.h"
#include "shared/file-util.h" #include "shared/file-util.h"
#include "shared/process-util.h"
#include "shared/timespec-util.h" #include "shared/timespec-util.h"
#include "window.h"
#include "weston-desktop-shell-client-protocol.h" #include "weston-desktop-shell-client-protocol.h"
#define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES #define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES
#define DEFAULT_SPACING 10 #define DEFAULT_SPACING 10
extern char **environ; /* defined by libc */
enum clock_format { enum clock_format {
CLOCK_FORMAT_MINUTES, CLOCK_FORMAT_MINUTES,
CLOCK_FORMAT_SECONDS, CLOCK_FORMAT_SECONDS,
@@ -142,9 +143,11 @@ struct panel_launcher {
cairo_surface_t *icon; cairo_surface_t *icon;
int focused, pressed; int focused, pressed;
char *path; char *path;
char *displayname;
struct wl_list link; struct wl_list link;
struct wl_array envp; struct custom_env env;
struct wl_array argv; char * const *argp;
char * const *envp;
}; };
struct panel_clock { struct panel_clock {
@@ -211,7 +214,6 @@ check_desktop_ready(struct window *window)
static void static void
panel_launcher_activate(struct panel_launcher *widget) panel_launcher_activate(struct panel_launcher *widget)
{ {
char **argv;
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
@@ -223,13 +225,11 @@ panel_launcher_activate(struct panel_launcher *widget)
if (pid) if (pid)
return; return;
argv = widget->argv.data;
if (setsid() == -1) if (setsid() == -1)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (execve(argv[0], argv, widget->envp.data) < 0) { if (execve(widget->argp[0], widget->argp, widget->envp) < 0) {
fprintf(stderr, "execl '%s' failed: %s\n", argv[0], fprintf(stderr, "execl '%s' failed: %s\n", widget->argp[0],
strerror(errno)); strerror(errno));
exit(1); exit(1);
} }
@@ -277,7 +277,7 @@ panel_launcher_motion_handler(struct widget *widget, struct input *input,
{ {
struct panel_launcher *launcher = data; struct panel_launcher *launcher = data;
widget_set_tooltip(widget, basename((char *)launcher->path), x, y); widget_set_tooltip(widget, launcher->displayname, x, y);
return CURSOR_LEFT_PTR; return CURSOR_LEFT_PTR;
} }
@@ -575,10 +575,10 @@ panel_configure(void *data,
static void static void
panel_destroy_launcher(struct panel_launcher *launcher) panel_destroy_launcher(struct panel_launcher *launcher)
{ {
wl_array_release(&launcher->argv); custom_env_fini(&launcher->env);
wl_array_release(&launcher->envp);
free(launcher->path); free(launcher->path);
free(launcher->displayname);
cairo_surface_destroy(launcher->icon); cairo_surface_destroy(launcher->icon);
@@ -678,58 +678,19 @@ load_icon_or_fallback(const char *icon)
} }
static void static void
panel_add_launcher(struct panel *panel, const char *icon, const char *path) panel_add_launcher(struct panel *panel, const char *icon, const char *path, const char *displayname)
{ {
struct panel_launcher *launcher; struct panel_launcher *launcher;
char *start, *p, *eq, **ps;
int i, j, k;
launcher = xzalloc(sizeof *launcher); launcher = xzalloc(sizeof *launcher);
launcher->icon = load_icon_or_fallback(icon); launcher->icon = load_icon_or_fallback(icon);
launcher->path = xstrdup(path); launcher->path = xstrdup(path);
launcher->displayname = xstrdup(displayname);
wl_array_init(&launcher->envp); custom_env_init_from_environ(&launcher->env);
wl_array_init(&launcher->argv); custom_env_add_from_exec_string(&launcher->env, launcher->path);
for (i = 0; environ[i]; i++) { launcher->envp = custom_env_get_envp(&launcher->env);
ps = wl_array_add(&launcher->envp, sizeof *ps); launcher->argp = custom_env_get_argp(&launcher->env);
*ps = environ[i];
}
j = 0;
start = launcher->path;
while (*start) {
for (p = start, eq = NULL; *p && !isspace(*p); p++)
if (*p == '=')
eq = p;
if (eq && j == 0) {
ps = launcher->envp.data;
for (k = 0; k < i; k++)
if (strncmp(ps[k], start, eq - start) == 0) {
ps[k] = start;
break;
}
if (k == i) {
ps = wl_array_add(&launcher->envp, sizeof *ps);
*ps = start;
i++;
}
} else {
ps = wl_array_add(&launcher->argv, sizeof *ps);
*ps = start;
j++;
}
while (*p && isspace(*p))
*p++ = '\0';
start = p;
}
ps = wl_array_add(&launcher->envp, sizeof *ps);
*ps = NULL;
ps = wl_array_add(&launcher->argv, sizeof *ps);
*ps = NULL;
launcher->panel = panel; launcher->panel = panel;
wl_list_insert(panel->launcher_list.prev, &launcher->link); wl_list_insert(panel->launcher_list.prev, &launcher->link);
@@ -1447,7 +1408,7 @@ static void
panel_add_launchers(struct panel *panel, struct desktop *desktop) panel_add_launchers(struct panel *panel, struct desktop *desktop)
{ {
struct weston_config_section *s; struct weston_config_section *s;
char *icon, *path; char *icon, *path, *displayname;
const char *name; const char *name;
int count; int count;
@@ -1459,9 +1420,12 @@ panel_add_launchers(struct panel *panel, struct desktop *desktop)
weston_config_section_get_string(s, "icon", &icon, NULL); weston_config_section_get_string(s, "icon", &icon, NULL);
weston_config_section_get_string(s, "path", &path, NULL); weston_config_section_get_string(s, "path", &path, NULL);
weston_config_section_get_string(s, "displayname", &displayname, NULL);
if (displayname == NULL)
displayname = xstrdup(basename(path));
if (icon != NULL && path != NULL) { if (icon != NULL && path != NULL) {
panel_add_launcher(panel, icon, path); panel_add_launcher(panel, icon, path, displayname);
count++; count++;
} else { } else {
fprintf(stderr, "invalid launcher section\n"); fprintf(stderr, "invalid launcher section\n");
@@ -1469,6 +1433,7 @@ panel_add_launchers(struct panel *panel, struct desktop *desktop)
free(icon); free(icon);
free(path); free(path);
free(displayname);
} }
if (count == 0) { if (count == 0) {
@@ -1477,7 +1442,8 @@ panel_add_launchers(struct panel *panel, struct desktop *desktop)
/* add default launcher */ /* add default launcher */
panel_add_launcher(panel, panel_add_launcher(panel,
name, name,
BINDIR "/weston-terminal"); BINDIR "/weston-terminal",
"Terminal");
free(name); free(name);
} }
} }
-2
View File
@@ -351,8 +351,6 @@ axis_discrete_handler(struct widget *widget, struct input *input,
* \param widget widget * \param widget widget
* \param input input device that caused the motion event * \param input input device that caused the motion event
* \param time time the event happened * \param time time the event happened
* \param x absolute x position
* \param y absolute y position
* \param x x position relative to the window * \param x x position relative to the window
* \param y y position relative to the window * \param y y position relative to the window
* \param data user data associated to the window * \param data user data associated to the window
-504
View File
@@ -1,504 +0,0 @@
/*
* Copyright © 2008 Kristian Høgsberg
*
* 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 <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <errno.h>
#include <GL/gl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <linux/input.h>
#include <wayland-client.h>
#include "window.h"
struct gears {
struct window *window;
struct widget *widget;
struct display *d;
EGLDisplay display;
EGLDisplay config;
EGLContext context;
GLfloat angle;
struct {
GLfloat rotx;
GLfloat roty;
} view;
int button_down;
int last_x, last_y;
GLint gear_list[3];
int fullscreen;
int frames;
uint32_t last_fps;
};
struct gear_template {
GLfloat material[4];
GLfloat inner_radius;
GLfloat outer_radius;
GLfloat width;
GLint teeth;
GLfloat tooth_depth;
};
static const struct gear_template gear_templates[] = {
{ { 0.8, 0.1, 0.0, 1.0 }, 1.0, 4.0, 1.0, 20, 0.7 },
{ { 0.0, 0.8, 0.2, 1.0 }, 0.5, 2.0, 2.0, 10, 0.7 },
{ { 0.2, 0.2, 1.0, 1.0 }, 1.3, 2.0, 0.5, 10, 0.7 },
};
static GLfloat light_pos[4] = {5.0, 5.0, 10.0, 0.0};
static void die(const char *msg)
{
fprintf(stderr, "%s", msg);
exit(EXIT_FAILURE);
}
static void
make_gear(const struct gear_template *t)
{
GLint i;
GLfloat r0, r1, r2;
GLfloat angle, da;
GLfloat u, v, len;
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->material);
r0 = t->inner_radius;
r1 = t->outer_radius - t->tooth_depth / 2.0;
r2 = t->outer_radius + t->tooth_depth / 2.0;
da = 2.0 * M_PI / t->teeth / 4.0;
glShadeModel(GL_FLAT);
glNormal3f(0.0, 0.0, 1.0);
/* draw front face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
if (i < t->teeth) {
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
}
}
glEnd();
/* draw front sides of teeth */
glBegin(GL_QUADS);
da = 2.0 * M_PI / t->teeth / 4.0;
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
}
glEnd();
glNormal3f(0.0, 0.0, -1.0);
/* draw back face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
if (i < t->teeth) {
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
}
}
glEnd();
/* draw back sides of teeth */
glBegin(GL_QUADS);
da = 2.0 * M_PI / t->teeth / 4.0;
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
}
glEnd();
/* draw outward faces of teeth */
glBegin(GL_QUAD_STRIP);
for (i = 0; i < t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), t->width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), -t->width * 0.5);
u = r2 * cos(angle + da) - r1 * cos(angle);
v = r2 * sin(angle + da) - r1 * sin(angle);
len = sqrt(u * u + v * v);
u /= len;
v /= len;
glNormal3f(v, -u, 0.0);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), t->width * 0.5);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -t->width * 0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), t->width * 0.5);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -t->width * 0.5);
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
glNormal3f(v, -u, 0.0);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), t->width * 0.5);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -t->width * 0.5);
glNormal3f(cos(angle), sin(angle), 0.0);
}
glVertex3f(r1 * cos(0), r1 * sin(0), t->width * 0.5);
glVertex3f(r1 * cos(0), r1 * sin(0), -t->width * 0.5);
glEnd();
glShadeModel(GL_SMOOTH);
/* draw inside radius cylinder */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= t->teeth; i++) {
angle = i * 2.0 * M_PI / t->teeth;
glNormal3f(-cos(angle), -sin(angle), 0.0);
glVertex3f(r0 * cos(angle), r0 * sin(angle), -t->width * 0.5);
glVertex3f(r0 * cos(angle), r0 * sin(angle), t->width * 0.5);
}
glEnd();
}
static void
update_fps(struct gears *gears, uint32_t time)
{
long diff_ms;
static bool first_call = true;
if (first_call) {
gears->last_fps = time;
first_call = false;
} else
gears->frames++;
diff_ms = time - gears->last_fps;
if (diff_ms > 5000) {
float seconds = diff_ms / 1000.0;
float fps = gears->frames / seconds;
printf("%d frames in %6.3f seconds = %6.3f FPS\n", gears->frames, seconds, fps);
fflush(stdout);
gears->frames = 0;
gears->last_fps = time;
}
}
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct gears *gears = data;
update_fps(gears, time);
gears->angle = (GLfloat) (time % 8192) * 360 / 8192.0;
window_schedule_redraw(gears->window);
if (callback)
wl_callback_destroy(callback);
}
static const struct wl_callback_listener listener = {
frame_callback
};
static int
motion_handler(struct widget *widget, struct input *input,
uint32_t time, float x, float y, void *data)
{
struct gears *gears = data;
int offset_x, offset_y;
float step = 0.5;
if (gears->button_down) {
offset_x = x - gears->last_x;
offset_y = y - gears->last_y;
gears->last_x = x;
gears->last_y = y;
gears->view.roty += offset_x * step;
gears->view.rotx += offset_y * step;
if (gears->view.roty >= 360)
gears->view.roty = gears->view.roty - 360;
if (gears->view.roty <= 0)
gears->view.roty = gears->view.roty + 360;
if (gears->view.rotx >= 360)
gears->view.rotx = gears->view.rotx - 360;
if (gears->view.rotx <= 0)
gears->view.rotx = gears->view.rotx + 360;
}
return CURSOR_LEFT_PTR;
}
static void
button_handler(struct widget *widget, struct input *input,
uint32_t time, uint32_t button,
enum wl_pointer_button_state state, void *data)
{
struct gears *gears = data;
if (button == BTN_LEFT) {
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
gears->button_down = 1;
input_get_position(input,
&gears->last_x, &gears->last_y);
} else {
gears->button_down = 0;
}
}
}
static void
redraw_handler(struct widget *widget, void *data)
{
struct rectangle window_allocation;
struct rectangle allocation;
struct wl_callback *callback;
struct gears *gears = data;
widget_get_allocation(gears->widget, &allocation);
window_get_allocation(gears->window, &window_allocation);
if (display_acquire_window_surface(gears->d,
gears->window,
gears->context) < 0) {
die("Unable to acquire window surface, "
"compiled without cairo-egl?\n");
}
glViewport(allocation.x,
window_allocation.height - allocation.height - allocation.y,
allocation.width, allocation.height);
glScissor(allocation.x,
window_allocation.height - allocation.height - allocation.y,
allocation.width, allocation.height);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0, 0.0, -50);
glRotatef(gears->view.rotx, 1.0, 0.0, 0.0);
glRotatef(gears->view.roty, 0.0, 1.0, 0.0);
glPushMatrix();
glTranslatef(-3.0, -2.0, 0.0);
glRotatef(gears->angle, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[0]);
glPopMatrix();
glPushMatrix();
glTranslatef(3.1, -2.0, 0.0);
glRotatef(-2.0 * gears->angle - 9.0, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[1]);
glPopMatrix();
glPushMatrix();
glTranslatef(-3.1, 4.2, 0.0);
glRotatef(-2.0 * gears->angle - 25.0, 0.0, 0.0, 1.0);
glCallList(gears->gear_list[2]);
glPopMatrix();
glPopMatrix();
glFlush();
display_release_window_surface(gears->d, gears->window);
callback = wl_surface_frame(window_get_wl_surface(gears->window));
wl_callback_add_listener(callback, &listener, gears);
}
static void
resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
struct gears *gears = data;
int32_t size, big, small;
/* Constrain child size to be square and at least 300x300 */
if (width < height) {
small = width;
big = height;
} else {
small = height;
big = width;
}
if (gears->fullscreen)
size = small;
else
size = big;
widget_set_size(gears->widget, size, size);
}
static void
keyboard_focus_handler(struct window *window,
struct input *device, void *data)
{
window_schedule_redraw(window);
}
static void
fullscreen_handler(struct window *window, void *data)
{
struct gears *gears = data;
gears->fullscreen ^= 1;
window_set_fullscreen(window, gears->fullscreen);
}
static struct gears *
gears_create(struct display *display)
{
const int width = 450, height = 500;
struct gears *gears;
int i;
gears = zalloc(sizeof *gears);
gears->d = display;
gears->window = window_create(display);
gears->widget = window_frame_create(gears->window, gears);
window_set_title(gears->window, "Wayland Gears");
window_set_appid(gears->window, "org.freedesktop.weston.wayland-gears");
gears->display = display_get_egl_display(gears->d);
if (gears->display == NULL)
die("failed to create egl display\n");
eglBindAPI(EGL_OPENGL_API);
gears->config = display_get_argb_egl_config(gears->d);
gears->context = eglCreateContext(gears->display, gears->config,
EGL_NO_CONTEXT, NULL);
if (gears->context == NULL)
die("failed to create context\n");
if (!eglMakeCurrent(gears->display, NULL, NULL, gears->context))
die("failed to make context current\n");
for (i = 0; i < 3; i++) {
gears->gear_list[i] = glGenLists(1);
glNewList(gears->gear_list[i], GL_COMPILE);
make_gear(&gear_templates[i]);
glEndList();
}
gears->button_down = 0;
gears->last_x = 0;
gears->last_y = 0;
gears->view.rotx = 20.0;
gears->view.roty = 30.0;
printf("Warning: FPS count is limited by the wayland compositor or monitor refresh rate\n");
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 0.92);
window_set_user_data(gears->window, gears);
widget_set_resize_handler(gears->widget, resize_handler);
widget_set_redraw_handler(gears->widget, redraw_handler);
widget_set_button_handler(gears->widget, button_handler);
widget_set_motion_handler(gears->widget, motion_handler);
window_set_keyboard_focus_handler(gears->window,
keyboard_focus_handler);
window_set_fullscreen_handler(gears->window, fullscreen_handler);
window_schedule_resize(gears->window, width, height);
return gears;
}
static void
gears_destroy(struct gears *gears)
{
widget_destroy(gears->widget);
window_destroy(gears->window);
free(gears);
}
int main(int argc, char *argv[])
{
struct display *d;
struct gears *gears;
d = display_create(&argc, argv);
if (d == NULL) {
fprintf(stderr, "failed to create display: %s\n",
strerror(errno));
return -1;
}
gears = gears_create(d);
display_run(d);
gears_destroy(gears);
display_destroy(d);
return 0;
}
+12 -16
View File
@@ -35,6 +35,10 @@ dep_toytoolkit = declare_dependency(
link_with: lib_toytoolkit, link_with: lib_toytoolkit,
dependencies: deps_toytoolkit, dependencies: deps_toytoolkit,
) )
dep_gbm = dependency('gbm', required: false)
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_clients_enabled = get_option('simple-clients')
simple_build_all = simple_clients_enabled.contains('all') simple_build_all = simple_clients_enabled.contains('all')
@@ -60,6 +64,8 @@ simple_clients = [
'../libweston/pixel-formats.c', '../libweston/pixel-formats.c',
linux_dmabuf_unstable_v1_client_protocol_h, linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c, linux_dmabuf_unstable_v1_protocol_c,
presentation_time_client_protocol_h,
presentation_time_protocol_c,
xdg_shell_client_protocol_h, xdg_shell_client_protocol_h,
xdg_shell_protocol_c, xdg_shell_protocol_c,
], ],
@@ -125,7 +131,12 @@ simple_clients = [
ivi_application_client_protocol_h, ivi_application_client_protocol_h,
ivi_application_protocol_c, ivi_application_protocol_c,
], ],
'dep_objs': [ dep_wayland_client, dep_libshared, dep_libm ], 'dep_objs': [
dep_libm,
dep_libshared,
dep_matrix_c,
dep_wayland_client,
],
'deps': [ 'egl', 'wayland-egl', 'glesv2', 'wayland-cursor' ], 'deps': [ 'egl', 'wayland-egl', 'glesv2', 'wayland-cursor' ],
'options': [ 'renderer-gl' ] 'options': [ 'renderer-gl' ]
}, },
@@ -217,21 +228,6 @@ tools_list = [
], ],
'deps': [ dep_wayland_client ] 'deps': [ dep_wayland_client ]
}, },
{
'name': 'info',
'sources': [
'weston-info.c',
presentation_time_client_protocol_h,
presentation_time_protocol_c,
linux_dmabuf_unstable_v1_client_protocol_h,
linux_dmabuf_unstable_v1_protocol_c,
tablet_unstable_v2_client_protocol_h,
tablet_unstable_v2_protocol_c,
xdg_output_unstable_v1_client_protocol_h,
xdg_output_unstable_v1_protocol_c,
],
'deps': [ dep_wayland_client, dep_libshared ]
},
{ {
'name': 'terminal', 'name': 'terminal',
'sources': [ 'terminal.c' ], 'sources': [ 'terminal.c' ],
-374
View File
@@ -1,374 +0,0 @@
/*
* Copyright © 2013 Intel Corporation
*
* 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 <wayland-egl.h>
#include <wayland-cursor.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include "shared/platform.h"
struct window;
struct seat;
struct nested_client {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
EGLDisplay egl_display;
EGLContext egl_context;
EGLConfig egl_config;
EGLSurface egl_surface;
struct program *color_program;
GLuint vert, frag, program;
GLuint rotation;
GLuint pos;
GLuint col;
struct wl_surface *surface;
struct wl_egl_window *native;
int width, height;
};
#define POS 0
#define COL 1
static GLuint
create_shader(const char *source, GLenum shader_type)
{
GLuint shader;
GLint status;
shader = glCreateShader(shader_type);
if (shader == 0)
return 0;
glShaderSource(shader, 1, (const char **) &source, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status) {
char log[1000];
GLsizei len;
glGetShaderInfoLog(shader, 1000, &len, log);
fprintf(stderr, "Error: compiling %s: %.*s\n",
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
len, log);
return 0;
}
return shader;
}
static void
create_program(struct nested_client *client,
const char *vert, const char *frag)
{
GLint status;
client->vert = create_shader(vert, GL_VERTEX_SHADER);
client->frag = create_shader(frag, GL_FRAGMENT_SHADER);
client->program = glCreateProgram();
glAttachShader(client->program, client->frag);
glAttachShader(client->program, client->vert);
glBindAttribLocation(client->program, POS, "pos");
glBindAttribLocation(client->program, COL, "color");
glLinkProgram(client->program);
glGetProgramiv(client->program, GL_LINK_STATUS, &status);
if (!status) {
char log[1000];
GLsizei len;
glGetProgramInfoLog(client->program, 1000, &len, log);
fprintf(stderr, "Error: linking:\n%.*s\n", len, log);
exit(1);
}
client->rotation =
glGetUniformLocation(client->program, "rotation");
}
static const char vertex_shader_text[] =
"uniform mat4 rotation;\n"
"attribute vec4 pos;\n"
"attribute vec4 color;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" gl_Position = rotation * pos;\n"
" v_color = color;\n"
"}\n";
static const char color_fragment_shader_text[] =
"precision mediump float;\n"
"varying vec4 v_color;\n"
"void main() {\n"
" gl_FragColor = v_color;\n"
"}\n";
static void
render_triangle(struct nested_client *client, uint32_t time)
{
static const GLfloat verts[3][2] = {
{ -0.5, -0.5 },
{ 0.5, -0.5 },
{ 0, 0.5 }
};
static const GLfloat colors[3][3] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
GLfloat angle;
GLfloat rotation[4][4] = {
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 }
};
static const int32_t speed_div = 5;
static uint32_t start_time = 0;
if (client->program == 0)
create_program(client, vertex_shader_text,
color_fragment_shader_text);
if (start_time == 0)
start_time = time;
angle = ((time - start_time) / speed_div) % 360 * M_PI / 180.0;
rotation[0][0] = cos(angle);
rotation[0][2] = sin(angle);
rotation[2][0] = -sin(angle);
rotation[2][2] = cos(angle);
glClearColor(0.4, 0.4, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(client->program);
glViewport(0, 0, client->width, client->height);
glUniformMatrix4fv(client->rotation, 1, GL_FALSE,
(GLfloat *) rotation);
glVertexAttribPointer(POS, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(COL, 3, GL_FLOAT, GL_FALSE, 0, colors);
glEnableVertexAttribArray(POS);
glEnableVertexAttribArray(COL);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(POS);
glDisableVertexAttribArray(COL);
glFlush();
}
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time);
static const struct wl_callback_listener frame_listener = {
frame_callback
};
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
struct nested_client *client = data;
if (callback)
wl_callback_destroy(callback);
callback = wl_surface_frame(client->surface);
wl_callback_add_listener(callback, &frame_listener, client);
render_triangle(client, time);
eglSwapBuffers(client->egl_display, client->egl_surface);
}
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct nested_client *client = data;
if (strcmp(interface, "wl_compositor") == 0) {
client->compositor =
wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
}
}
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 nested_client *
nested_client_create(void)
{
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
static const EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLint major, minor, n;
EGLBoolean ret;
struct nested_client *client;
client = malloc(sizeof *client);
if (client == NULL)
return NULL;
client->width = 250;
client->height = 250;
client->display = wl_display_connect(NULL);
client->registry = wl_display_get_registry(client->display);
wl_registry_add_listener(client->registry,
&registry_listener, client);
/* get globals */
wl_display_roundtrip(client->display);
client->egl_display =
weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
client->display, NULL);
if (client->egl_display == NULL)
return NULL;
ret = eglInitialize(client->egl_display, &major, &minor);
if (!ret)
return NULL;
ret = eglBindAPI(EGL_OPENGL_ES_API);
if (!ret)
return NULL;
ret = eglChooseConfig(client->egl_display, config_attribs,
&client->egl_config, 1, &n);
if (!ret || n != 1)
return NULL;
client->egl_context = eglCreateContext(client->egl_display,
client->egl_config,
EGL_NO_CONTEXT,
context_attribs);
if (!client->egl_context)
return NULL;
client->surface = wl_compositor_create_surface(client->compositor);
client->native = wl_egl_window_create(client->surface,
client->width, client->height);
client->egl_surface = weston_platform_create_egl_surface(client->egl_display,
client->egl_config,
client->native, NULL);
eglMakeCurrent(client->egl_display, client->egl_surface,
client->egl_surface, client->egl_context);
wl_egl_window_resize(client->native,
client->width, client->height, 0, 0);
frame_callback(client, NULL, 0);
return client;
}
static void
nested_client_destroy(struct nested_client *client)
{
eglMakeCurrent(client->egl_display,
EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
weston_platform_destroy_egl_surface(client->egl_display,
client->egl_surface);
wl_egl_window_destroy(client->native);
wl_surface_destroy(client->surface);
if (client->compositor)
wl_compositor_destroy(client->compositor);
wl_registry_destroy(client->registry);
eglTerminate(client->egl_display);
eglReleaseThread();
wl_display_flush(client->display);
wl_display_disconnect(client->display);
}
int
main(int argc, char **argv)
{
struct nested_client *client;
int ret = 0;
if (getenv("WAYLAND_SOCKET") == NULL) {
fprintf(stderr,
"must be run by nested, don't run standalone\n");
return EXIT_FAILURE;
}
client = nested_client_create();
if (client == NULL)
return EXIT_FAILURE;
while (ret != -1)
ret = wl_display_dispatch(client->display);
nested_client_destroy(client);
return 0;
}
-1139
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -765,7 +765,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "xdg_wm_base") == 0) {
d->wm_base = d->wm_base =
wl_registry_bind(registry, name, wl_registry_bind(registry, name,
&xdg_wm_base_interface, version); &xdg_wm_base_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) { } else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, d->shm = wl_registry_bind(registry,
name, &wl_shm_interface, 1); name, &wl_shm_interface, 1);
+10
View File
@@ -343,12 +343,22 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
#ifdef HAVE_GBM_MODIFIERS #ifdef HAVE_GBM_MODIFIERS
if (display->modifiers_count > 0) { 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,
buffer->format,
display->modifiers,
display->modifiers_count,
GBM_BO_USE_RENDERING);
#else
buffer->bo = gbm_bo_create_with_modifiers(display->gbm.device, buffer->bo = gbm_bo_create_with_modifiers(display->gbm.device,
buffer->width, buffer->width,
buffer->height, buffer->height,
buffer->format, buffer->format,
display->modifiers, display->modifiers,
display->modifiers_count); display->modifiers_count);
#endif
if (buffer->bo) if (buffer->bo)
buffer->modifier = gbm_bo_get_modifier(buffer->bo); buffer->modifier = gbm_bo_get_modifier(buffer->bo);
} }
+98 -14
View File
@@ -41,6 +41,7 @@
#include <libweston/pixel-formats.h> #include <libweston/pixel-formats.h>
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include <xf86drm.h> #include <xf86drm.h>
#include <gbm.h> #include <gbm.h>
@@ -49,6 +50,11 @@
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#define L_LINE "│ "
#define L_VAL "├───"
#define L_LAST "└───"
#define L_GAP " "
#define NUM_BUFFERS 4 #define NUM_BUFFERS 4
/* We have to hack the DRM-backend to pretend that planes of the underlying /* We have to hack the DRM-backend to pretend that planes of the underlying
@@ -135,6 +141,7 @@ struct display {
struct output output; struct output output;
struct xdg_wm_base *wm_base; struct xdg_wm_base *wm_base;
struct zwp_linux_dmabuf_v1 *dmabuf; struct zwp_linux_dmabuf_v1 *dmabuf;
struct wp_presentation *presentation;
struct gbm_device *gbm_device; struct gbm_device *gbm_device;
struct egl egl; struct egl egl;
}; };
@@ -166,12 +173,14 @@ struct window {
struct xdg_surface *xdg_surface; struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
struct wl_callback *callback; struct wl_callback *callback;
struct wp_presentation_feedback *presentation_feedback;
bool wait_for_configure; bool wait_for_configure;
uint32_t n_redraws; bool presented_zero_copy;
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback_obj; struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback_obj;
struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback; struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback;
int card_fd; int card_fd;
struct drm_format format; struct drm_format format;
uint32_t bo_flags;
struct buffer buffers[NUM_BUFFERS]; struct buffer buffers[NUM_BUFFERS];
}; };
@@ -453,7 +462,7 @@ buffer_free(struct buffer *buf)
static void static void
create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width, create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
uint32_t height, uint32_t format, unsigned int count_modifiers, uint32_t height, uint32_t format, unsigned int count_modifiers,
uint64_t *modifiers); uint64_t *modifiers, uint32_t bo_flags);
static void static void
buffer_recreate(struct buffer *buf) buffer_recreate(struct buffer *buf)
@@ -466,7 +475,7 @@ buffer_recreate(struct buffer *buf)
create_dmabuf_buffer(window, buf, width, height, create_dmabuf_buffer(window, buf, width, height,
window->format.format, window->format.format,
window->format.modifiers.size / sizeof(uint64_t), window->format.modifiers.size / sizeof(uint64_t),
window->format.modifiers.data); window->format.modifiers.data, window->bo_flags);
buf->recreate = false; buf->recreate = false;
} }
@@ -516,7 +525,7 @@ static const struct zwp_linux_buffer_params_v1_listener params_listener = {
static void static void
create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width, create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
uint32_t height, uint32_t format, unsigned int count_modifiers, uint32_t height, uint32_t format, unsigned int count_modifiers,
uint64_t *modifiers) uint64_t *modifiers, uint32_t bo_flags)
{ {
struct display *display = window->display; struct display *display = window->display;
static uint32_t flags = 0; static uint32_t flags = 0;
@@ -531,10 +540,18 @@ create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
#ifdef HAVE_GBM_MODIFIERS #ifdef HAVE_GBM_MODIFIERS
if (count_modifiers > 0) { 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->bo = gbm_bo_create_with_modifiers(display->gbm_device,
buf->width, buf->height, buf->width, buf->height,
format, modifiers, format, modifiers,
count_modifiers); count_modifiers);
#endif
if (buf->bo) if (buf->bo)
buf->modifier = gbm_bo_get_modifier(buf->bo); buf->modifier = gbm_bo_get_modifier(buf->bo);
} }
@@ -543,7 +560,7 @@ create_dmabuf_buffer(struct window *window, struct buffer *buf, uint32_t width,
if (!buf->bo) { if (!buf->bo) {
buf->bo = gbm_bo_create(display->gbm_device, buf->width, buf->bo = gbm_bo_create(display->gbm_device, buf->width,
buf->height, buf->format, buf->height, buf->format,
GBM_BO_USE_RENDERING); bo_flags);
buf->modifier = DRM_FORMAT_MOD_INVALID; buf->modifier = DRM_FORMAT_MOD_INVALID;
} }
@@ -639,6 +656,7 @@ render(struct buffer *buffer)
} }
static const struct wl_callback_listener frame_listener; static const struct wl_callback_listener frame_listener;
static const struct wp_presentation_feedback_listener presentation_feedback_listener;
static void static void
redraw(void *data, struct wl_callback *callback, uint32_t time) redraw(void *data, struct wl_callback *callback, uint32_t time)
@@ -660,6 +678,18 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->callback = wl_surface_frame(window->surface); window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &frame_listener, window); wl_callback_add_listener(window->callback, &frame_listener, window);
if (window->presentation_feedback)
wp_presentation_feedback_destroy(window->presentation_feedback);
if (window->display->presentation) {
window->presentation_feedback =
wp_presentation_feedback(window->display->presentation,
window->surface);
wp_presentation_feedback_add_listener(window->presentation_feedback,
&presentation_feedback_listener,
window);
}
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
buf->status = IN_USE; buf->status = IN_USE;
@@ -674,6 +704,48 @@ static const struct wl_callback_listener frame_listener = {
redraw redraw
}; };
static void presentation_feedback_handle_sync_output(void *data,
struct wp_presentation_feedback *feedback,
struct wl_output *output)
{
}
static void presentation_feedback_handle_presented(void *data,
struct wp_presentation_feedback *feedback,
uint32_t tv_sec_hi,
uint32_t tv_sec_lo,
uint32_t tv_nsec,
uint32_t refresh,
uint32_t seq_hi,
uint32_t seq_lo,
uint32_t flags)
{
struct window *window = data;
bool zero_copy = flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
if (zero_copy && !window->presented_zero_copy) {
fprintf(stderr, "Presenting in zero-copy mode\n");
}
if (!zero_copy && window->presented_zero_copy) {
fprintf(stderr, "Stopped presenting in zero-copy mode\n");
}
window->presented_zero_copy = zero_copy;
wp_presentation_feedback_destroy(feedback);
}
static void presentation_feedback_handle_discarded(void *data,
struct wp_presentation_feedback *feedback)
{
wp_presentation_feedback_destroy(feedback);
}
static const struct wp_presentation_feedback_listener presentation_feedback_listener = {
.sync_output = presentation_feedback_handle_sync_output,
.presented = presentation_feedback_handle_presented,
.discarded = presentation_feedback_handle_discarded,
};
static void static void
xdg_surface_handle_configure(void *data, struct xdg_surface *surface, xdg_surface_handle_configure(void *data, struct xdg_surface *surface,
uint32_t serial) uint32_t serial)
@@ -810,6 +882,8 @@ destroy_window(struct window *window)
if (window->callback) if (window->callback)
wl_callback_destroy(window->callback); wl_callback_destroy(window->callback);
if (window->presentation_feedback)
wp_presentation_feedback_destroy(window->presentation_feedback);
for (i = 0; i < NUM_BUFFERS; i++) for (i = 0; i < NUM_BUFFERS; i++)
if (window->buffers[i].buffer) if (window->buffers[i].buffer)
@@ -873,7 +947,7 @@ create_window(struct display *display)
create_dmabuf_buffer(window, &window->buffers[i], width, height, create_dmabuf_buffer(window, &window->buffers[i], width, height,
window->format.format, window->format.format,
window->format.modifiers.size / sizeof(uint64_t), window->format.modifiers.size / sizeof(uint64_t),
window->format.modifiers.data); window->format.modifiers.data, window->bo_flags);
window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base, window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base,
@@ -1000,8 +1074,7 @@ dmabuf_feedback_main_device(void *data,
drm_node = get_drm_node(feedback->main_device, false); drm_node = get_drm_node(feedback->main_device, false);
assert(drm_node && "error: failed to retrieve drm node"); assert(drm_node && "error: failed to retrieve drm node");
fprintf(stderr, "compositor sent main_device event for dma-buf feedback - %s\n", fprintf(stderr, "feedback: main device %s\n", drm_node);
drm_node);
if (!window->card_fd) { if (!window->card_fd) {
window->card_fd = open(drm_node, O_RDWR | O_CLOEXEC); window->card_fd = open(drm_node, O_RDWR | O_CLOEXEC);
@@ -1110,11 +1183,11 @@ print_tranche_format_modifier(uint32_t format, uint64_t modifier)
char fourcc_str[5]; char fourcc_str[5];
fourcc2str(format, fourcc_str, sizeof(fourcc_str)); fourcc2str(format, fourcc_str, sizeof(fourcc_str));
len = asprintf(&format_str, "0x%08x (%s)", format, fourcc_str); len = asprintf(&format_str, "%s (0x%08x)", fourcc_str, format);
} }
assert(len > 0); assert(len > 0);
fprintf(stderr, "│ ├────────tranche format/modifier pair - format %s, modifier %s\n", fprintf(stderr, L_LINE L_VAL " format %s, modifier %s\n",
format_str, mod_name); format_str, mod_name);
free(format_str); free(format_str);
@@ -1131,14 +1204,14 @@ print_dmabuf_feedback_tranche(struct dmabuf_feedback_tranche *tranche)
drm_node = get_drm_node(tranche->target_device, tranche->is_scanout_tranche); drm_node = get_drm_node(tranche->target_device, tranche->is_scanout_tranche);
assert(drm_node && "error: could not retrieve drm node"); assert(drm_node && "error: could not retrieve drm node");
fprintf(stderr, "├──────target_device for tranche - %s\n", drm_node); fprintf(stderr, L_VAL " tranche: target device %s, %s\n",
fprintf(stderr, "│ └scanout tranche? %s\n", tranche->is_scanout_tranche ? "yes" : "no"); drm_node, tranche->is_scanout_tranche ? "scanout" : "no flags");
wl_array_for_each(fmt, &tranche->formats.arr) wl_array_for_each(fmt, &tranche->formats.arr)
wl_array_for_each(mod, &fmt->modifiers) wl_array_for_each(mod, &fmt->modifiers)
print_tranche_format_modifier(fmt->format, *mod); print_tranche_format_modifier(fmt->format, *mod);
fprintf(stderr, "│ └end of tranche\n"); fprintf(stderr, L_LINE L_LAST " end of tranche\n");
} }
static void static void
@@ -1173,6 +1246,8 @@ pick_initial_format_from_renderer_tranche(struct window *window,
window->format.format = fmt->format; window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers); wl_array_copy(&window->format.modifiers, &fmt->modifiers);
window->bo_flags = GBM_BO_USE_RENDERING;
return true; return true;
} }
return false; return false;
@@ -1203,6 +1278,8 @@ pick_format_from_scanout_tranche(struct window *window,
window->format.format = fmt->format; window->format.format = fmt->format;
wl_array_copy(&window->format.modifiers, &fmt->modifiers); wl_array_copy(&window->format.modifiers, &fmt->modifiers);
window->bo_flags = GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT;
return true; return true;
} }
return false; return false;
@@ -1216,7 +1293,7 @@ dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_fee
bool got_scanout_tranche = false; bool got_scanout_tranche = false;
unsigned int i; unsigned int i;
fprintf(stderr, "end of dma-buf feedback\n\n"); fprintf(stderr, L_LAST " end of dma-buf feedback\n\n");
/* The first time that we receive dma-buf feedback for a surface it /* The first time that we receive dma-buf feedback for a surface it
* contains only the renderer tranches. We pick the INITIAL_BUFFER_FORMAT * contains only the renderer tranches. We pick the INITIAL_BUFFER_FORMAT
@@ -1344,6 +1421,10 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->dmabuf = wl_registry_bind(registry, id, d->dmabuf = wl_registry_bind(registry, id,
&zwp_linux_dmabuf_v1_interface, &zwp_linux_dmabuf_v1_interface,
MIN(version, 4)); MIN(version, 4));
} else if (strcmp(interface, "wp_presentation") == 0) {
d->presentation = wl_registry_bind(registry, id,
&wp_presentation_interface,
1);
} }
} }
@@ -1368,6 +1449,9 @@ destroy_display(struct display *display)
if (display->egl.display != EGL_NO_DISPLAY) if (display->egl.display != EGL_NO_DISPLAY)
eglTerminate(display->egl.display); eglTerminate(display->egl.display);
if (display->presentation)
wp_presentation_destroy(display->presentation);
zwp_linux_dmabuf_v1_destroy(display->dmabuf); zwp_linux_dmabuf_v1_destroy(display->dmabuf);
xdg_wm_base_destroy(display->wm_base); xdg_wm_base_destroy(display->wm_base);
+366 -60
View File
@@ -46,9 +46,11 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <libweston/matrix.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/platform.h" #include "shared/platform.h"
#include "shared/weston-egl-ext.h" #include "shared/weston-egl-ext.h"
#include "shared/xalloc.h"
struct window; struct window;
struct seat; struct seat;
@@ -73,6 +75,8 @@ struct display {
} egl; } egl;
struct window *window; struct window *window;
struct wl_list output_list; /* struct output::link */
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage; PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
}; };
@@ -82,22 +86,45 @@ struct geometry {
struct window { struct window {
struct display *display; struct display *display;
struct geometry geometry, window_size; struct geometry window_size;
struct geometry logical_size;
struct geometry buffer_size;
int32_t buffer_scale;
enum wl_output_transform buffer_transform;
bool needs_buffer_geometry_update;
struct { struct {
GLuint rotation_uniform; GLuint rotation_uniform;
GLuint pos; GLuint pos;
GLuint col; GLuint col;
} gl; } gl;
uint32_t benchmark_time, frames; uint32_t frames;
uint32_t initial_frame_time;
uint32_t benchmark_time;
struct wl_egl_window *native; struct wl_egl_window *native;
struct wl_surface *surface; struct wl_surface *surface;
struct xdg_surface *xdg_surface; struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
EGLSurface egl_surface; EGLSurface egl_surface;
struct wl_callback *callback; int fullscreen, maximized, opaque, buffer_bpp, frame_sync, delay;
int fullscreen, maximized, opaque, buffer_size, frame_sync, delay;
bool wait_for_configure; bool wait_for_configure;
struct wl_list window_output_list; /* struct window_output::link */
};
struct output {
struct display *display;
struct wl_output *wl_output;
uint32_t name;
struct wl_list link; /* struct display::output_list */
enum wl_output_transform transform;
int32_t scale;
};
struct window_output {
struct output *output;
struct wl_list link; /* struct window::window_output_list */
}; };
static const char *vert_shader_text = static const char *vert_shader_text =
@@ -155,7 +182,7 @@ init_egl(struct display *display, struct window *window)
EGLConfig *configs; EGLConfig *configs;
EGLBoolean ret; EGLBoolean ret;
if (window->opaque || window->buffer_size == 16) if (window->opaque || window->buffer_bpp == 16)
config_attribs[9] = 0; config_attribs[9] = 0;
display->egl.dpy = display->egl.dpy =
@@ -179,13 +206,13 @@ init_egl(struct display *display, struct window *window)
assert(ret && n >= 1); assert(ret && n >= 1);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
EGLint buffer_size, red_size; EGLint buffer_bpp, red_size;
eglGetConfigAttrib(display->egl.dpy, eglGetConfigAttrib(display->egl.dpy,
configs[i], EGL_BUFFER_SIZE, &buffer_size); configs[i], EGL_BUFFER_SIZE, &buffer_bpp);
eglGetConfigAttrib(display->egl.dpy, eglGetConfigAttrib(display->egl.dpy,
configs[i], EGL_RED_SIZE, &red_size); configs[i], EGL_RED_SIZE, &red_size);
if ((window->buffer_size == 0 || if ((window->buffer_bpp == 0 ||
window->buffer_size == buffer_size) && red_size < 10) { window->buffer_bpp == buffer_bpp) && red_size < 10) {
display->egl.conf = configs[i]; display->egl.conf = configs[i];
break; break;
} }
@@ -193,7 +220,7 @@ init_egl(struct display *display, struct window *window)
free(configs); free(configs);
if (display->egl.conf == NULL) { if (display->egl.conf == NULL) {
fprintf(stderr, "did not find config with buffer size %d\n", fprintf(stderr, "did not find config with buffer size %d\n",
window->buffer_size); window->buffer_bpp);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -256,6 +283,92 @@ create_shader(struct window *window, const char *source, GLenum shader_type)
return shader; return shader;
} }
static int32_t
compute_buffer_scale(struct window *window)
{
struct window_output *window_output;
int32_t scale = 1;
wl_list_for_each(window_output, &window->window_output_list, link) {
if (window_output->output->scale > scale)
scale = window_output->output->scale;
}
return scale;
}
static enum wl_output_transform
compute_buffer_transform(struct window *window)
{
struct window_output *window_output;
enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
wl_list_for_each(window_output, &window->window_output_list, link) {
/* If the surface spans over multiple outputs the optimal
* transform value can be ambiguous. Thus just return the value
* from the oldest entered output.
*/
transform = window_output->output->transform;
break;
}
return transform;
}
static void
update_buffer_geometry(struct window *window)
{
enum wl_output_transform new_buffer_transform;
int32_t new_buffer_scale;
struct geometry new_buffer_size;
new_buffer_transform = compute_buffer_transform(window);
if (window->buffer_transform != new_buffer_transform) {
window->buffer_transform = new_buffer_transform;
wl_surface_set_buffer_transform(window->surface,
window->buffer_transform);
}
new_buffer_scale = compute_buffer_scale(window);
if (window->buffer_scale != new_buffer_scale) {
window->buffer_scale = new_buffer_scale;
wl_surface_set_buffer_scale(window->surface,
window->buffer_scale);
}
switch (window->buffer_transform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_180:
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
new_buffer_size.width = window->logical_size.width;
new_buffer_size.height = window->logical_size.height;
break;
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
new_buffer_size.width = window->logical_size.height;
new_buffer_size.height = window->logical_size.width;
break;
}
new_buffer_size.width *= window->buffer_scale;
new_buffer_size.height *= window->buffer_scale;
if (window->buffer_size.width != new_buffer_size.width ||
window->buffer_size.height != new_buffer_size.height) {
window->buffer_size = new_buffer_size;
if (window->native)
wl_egl_window_resize(window->native,
window->buffer_size.width,
window->buffer_size.height, 0, 0);
}
window->needs_buffer_geometry_update = false;
}
static void static void
init_gl(struct window *window) init_gl(struct window *window)
{ {
@@ -264,9 +377,12 @@ init_gl(struct window *window)
GLint status; GLint status;
EGLBoolean ret; EGLBoolean ret;
if (window->needs_buffer_geometry_update)
update_buffer_geometry(window);
window->native = wl_egl_window_create(window->surface, window->native = wl_egl_window_create(window->surface,
window->geometry.width, window->buffer_size.width,
window->geometry.height); window->buffer_size.height);
window->egl_surface = window->egl_surface =
weston_platform_create_egl_surface(window->display->egl.dpy, weston_platform_create_egl_surface(window->display->egl.dpy,
window->display->egl.conf, window->display->egl.conf,
@@ -276,6 +392,9 @@ init_gl(struct window *window)
window->egl_surface, window->display->egl.ctx); window->egl_surface, window->display->egl.ctx);
assert(ret == EGL_TRUE); assert(ret == EGL_TRUE);
if (!window->frame_sync)
eglSwapInterval(window->display->egl.dpy, 0);
frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER); frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER); vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
@@ -348,16 +467,13 @@ handle_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
window->window_size.width = width; window->window_size.width = width;
window->window_size.height = height; window->window_size.height = height;
} }
window->geometry.width = width; window->logical_size.width = width;
window->geometry.height = height; window->logical_size.height = height;
} else if (!window->fullscreen && !window->maximized) { } else if (!window->fullscreen && !window->maximized) {
window->geometry = window->window_size; window->logical_size = window->window_size;
} }
if (window->native) window->needs_buffer_geometry_update = true;
wl_egl_window_resize(window->native,
window->geometry.width,
window->geometry.height, 0, 0);
} }
static void static void
@@ -371,12 +487,80 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_toplevel_close, handle_toplevel_close,
}; };
static void
add_window_output(struct window *window, struct wl_output *wl_output)
{
struct output *output;
struct output *output_found = NULL;
struct window_output *window_output;
wl_list_for_each(output, &window->display->output_list, link) {
if (output->wl_output == wl_output) {
output_found = output;
break;
}
}
if (!output_found)
return;
window_output = xmalloc(sizeof *window_output);
window_output->output = output_found;
wl_list_insert(window->window_output_list.prev, &window_output->link);
window->needs_buffer_geometry_update = true;
}
static void
destroy_window_output(struct window *window, struct wl_output *wl_output)
{
struct window_output *window_output;
struct window_output *window_output_found = NULL;
wl_list_for_each(window_output, &window->window_output_list, link) {
if (window_output->output->wl_output == wl_output) {
window_output_found = window_output;
break;
}
}
if (window_output_found) {
wl_list_remove(&window_output_found->link);
free(window_output_found);
window->needs_buffer_geometry_update = true;
}
}
static void
surface_enter(void *data,
struct wl_surface *wl_surface, struct wl_output *wl_output)
{
struct window *window = data;
add_window_output(window, wl_output);
}
static void
surface_leave(void *data,
struct wl_surface *wl_surface, struct wl_output *wl_output)
{
struct window *window = data;
destroy_window_output(window, wl_output);
}
static const struct wl_surface_listener surface_listener = {
surface_enter,
surface_leave
};
static void static void
create_surface(struct window *window) create_surface(struct window *window)
{ {
struct display *display = window->display; struct display *display = window->display;
window->surface = wl_compositor_create_surface(display->compositor); window->surface = wl_compositor_create_surface(display->compositor);
wl_surface_add_listener(window->surface, &surface_listener, window);
window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base, window->xdg_surface = xdg_wm_base_get_xdg_surface(display->wm_base,
window->surface); window->surface);
@@ -399,9 +583,6 @@ create_surface(struct window *window)
window->wait_for_configure = true; window->wait_for_configure = true;
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);
} }
static void static void
@@ -421,15 +602,12 @@ destroy_surface(struct window *window)
if (window->xdg_surface) if (window->xdg_surface)
xdg_surface_destroy(window->xdg_surface); xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
if (window->callback)
wl_callback_destroy(window->callback);
} }
static void static void
redraw(void *data, struct wl_callback *callback, uint32_t time) redraw(struct window *window)
{ {
struct window *window = data;
struct display *display = window->display; struct display *display = window->display;
static const GLfloat verts[3][2] = { static const GLfloat verts[3][2] = {
{ -0.5, -0.5 }, { -0.5, -0.5 },
@@ -442,28 +620,22 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
{ 0, 0, 1 } { 0, 0, 1 }
}; };
GLfloat angle; GLfloat angle;
GLfloat rotation[4][4] = { struct weston_matrix rotation;
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 }
};
static const uint32_t speed_div = 5, benchmark_interval = 5; static const uint32_t speed_div = 5, benchmark_interval = 5;
struct wl_region *region; struct wl_region *region;
EGLint rect[4]; EGLint rect[4];
EGLint buffer_age = 0; EGLint buffer_age = 0;
struct timeval tv; struct timeval tv;
assert(window->callback == callback); if (window->needs_buffer_geometry_update)
window->callback = NULL; update_buffer_geometry(window);
if (callback)
wl_callback_destroy(callback);
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
time = tv.tv_sec * 1000 + tv.tv_usec / 1000; uint32_t time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (window->frames == 0) if (window->frames == 0) {
window->initial_frame_time = time;
window->benchmark_time = time; window->benchmark_time = time;
}
if (time - window->benchmark_time > (benchmark_interval * 1000)) { if (time - window->benchmark_time > (benchmark_interval * 1000)) {
printf("%d frames in %d seconds: %f fps\n", printf("%d frames in %d seconds: %f fps\n",
window->frames, window->frames,
@@ -473,20 +645,51 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->frames = 0; window->frames = 0;
} }
angle = (time / speed_div) % 360 * M_PI / 180.0; weston_matrix_init(&rotation);
rotation[0][0] = cos(angle); angle = ((time - window->initial_frame_time) / speed_div) % 360 * M_PI / 180.0;
rotation[0][2] = sin(angle); rotation.d[0] = cos(angle);
rotation[2][0] = -sin(angle); rotation.d[2] = sin(angle);
rotation[2][2] = cos(angle); rotation.d[8] = -sin(angle);
rotation.d[10] = cos(angle);
switch (window->buffer_transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
weston_matrix_scale(&rotation, -1, 1, 1);
break;
default:
break;
}
switch (window->buffer_transform) {
default:
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
break;
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
weston_matrix_rotate_xy(&rotation, 0, 1);
break;
case WL_OUTPUT_TRANSFORM_180:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
weston_matrix_rotate_xy(&rotation, -1, 0);
break;
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
weston_matrix_rotate_xy(&rotation, 0, -1);
break;
}
if (display->swap_buffers_with_damage) if (display->swap_buffers_with_damage)
eglQuerySurface(display->egl.dpy, window->egl_surface, eglQuerySurface(display->egl.dpy, window->egl_surface,
EGL_BUFFER_AGE_EXT, &buffer_age); EGL_BUFFER_AGE_EXT, &buffer_age);
glViewport(0, 0, window->geometry.width, window->geometry.height); glViewport(0, 0, window->buffer_size.width, window->buffer_size.height);
glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE, glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
(GLfloat *) rotation); (GLfloat *) rotation.d);
if (window->opaque || window->fullscreen) if (window->opaque || window->fullscreen)
glClearColor(0.0, 0.0, 0.0, 1); glClearColor(0.0, 0.0, 0.0, 1);
@@ -508,9 +711,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
if (window->opaque || window->fullscreen) { if (window->opaque || window->fullscreen) {
region = wl_compositor_create_region(window->display->compositor); region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0, wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
window->geometry.width,
window->geometry.height);
wl_surface_set_opaque_region(window->surface, region); wl_surface_set_opaque_region(window->surface, region);
wl_region_destroy(region); wl_region_destroy(region);
} else { } else {
@@ -518,10 +719,10 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
} }
if (display->swap_buffers_with_damage && buffer_age > 0) { if (display->swap_buffers_with_damage && buffer_age > 0) {
rect[0] = window->geometry.width / 4 - 1; rect[0] = window->buffer_size.width / 4 - 1;
rect[1] = window->geometry.height / 4 - 1; rect[1] = window->buffer_size.height / 4 - 1;
rect[2] = window->geometry.width / 2 + 2; rect[2] = window->buffer_size.width / 2 + 2;
rect[3] = window->geometry.height / 2 + 2; rect[3] = window->buffer_size.height / 2 + 2;
display->swap_buffers_with_damage(display->egl.dpy, display->swap_buffers_with_damage(display->egl.dpy,
window->egl_surface, window->egl_surface,
rect, 1); rect, 1);
@@ -745,6 +946,92 @@ static const struct xdg_wm_base_listener wm_base_listener = {
xdg_wm_base_ping, xdg_wm_base_ping,
}; };
static void
display_handle_geometry(void *data,
struct wl_output *wl_output,
int32_t x, int32_t y,
int32_t physical_width,
int32_t physical_height,
int32_t subpixel,
const char *make,
const char *model,
int32_t transform)
{
struct output *output = data;
output->transform = transform;
output->display->window->needs_buffer_geometry_update = true;
}
static void
display_handle_mode(void *data,
struct wl_output *wl_output,
uint32_t flags,
int32_t width,
int32_t height,
int32_t refresh)
{
}
static void
display_handle_done(void *data,
struct wl_output *wl_output)
{
}
static void
display_handle_scale(void *data,
struct wl_output *wl_output,
int32_t scale)
{
struct output *output = data;
output->scale = scale;
output->display->window->needs_buffer_geometry_update = true;
}
static const struct wl_output_listener output_listener = {
display_handle_geometry,
display_handle_mode,
display_handle_done,
display_handle_scale
};
static void
display_add_output(struct display *d, uint32_t name)
{
struct output *output;
output = xzalloc(sizeof *output);
output->display = d;
output->scale = 1;
output->wl_output =
wl_registry_bind(d->registry, name, &wl_output_interface, 2);
output->name = name;
wl_list_insert(d->output_list.prev, &output->link);
wl_output_add_listener(output->wl_output, &output_listener, output);
}
static void
display_destroy_output(struct display *d, struct output *output)
{
destroy_window_output(d->window, output->wl_output);
wl_output_destroy(output->wl_output);
wl_list_remove(&output->link);
free(output);
}
static void
display_destroy_outputs(struct display *d)
{
struct output *tmp;
struct output *output;
wl_list_for_each_safe(output, tmp, &d->output_list, link)
display_destroy_output(d, output);
}
static void static void
registry_handle_global(void *data, struct wl_registry *registry, registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) uint32_t name, const char *interface, uint32_t version)
@@ -778,6 +1065,8 @@ registry_handle_global(void *data, struct wl_registry *registry,
fprintf(stderr, "unable to load default left pointer\n"); fprintf(stderr, "unable to load default left pointer\n");
// TODO: abort ? // TODO: abort ?
} }
} else if (strcmp(interface, "wl_output") == 0 && version >= 2) {
display_add_output(d, name);
} }
} }
@@ -785,6 +1074,15 @@ static void
registry_handle_global_remove(void *data, struct wl_registry *registry, registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) uint32_t name)
{ {
struct display *d = data;
struct output *output;
wl_list_for_each(output, &d->output_list, link) {
if (output->name == name) {
display_destroy_output(d, output);
break;
}
}
} }
static const struct wl_registry_listener registry_listener = { static const struct wl_registry_listener registry_listener = {
@@ -823,13 +1121,19 @@ main(int argc, char **argv)
window.display = &display; window.display = &display;
display.window = &window; display.window = &window;
window.geometry.width = 250; window.buffer_size.width = 250;
window.geometry.height = 250; window.buffer_size.height = 250;
window.window_size = window.geometry; window.window_size = window.buffer_size;
window.buffer_size = 0; window.buffer_scale = 1;
window.buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
window.needs_buffer_geometry_update = false;
window.buffer_bpp = 0;
window.frame_sync = 1; window.frame_sync = 1;
window.delay = 0; window.delay = 0;
wl_list_init(&display.output_list);
wl_list_init(&window.window_output_list);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strcmp("-d", argv[i]) == 0 && i+1 < argc) if (strcmp("-d", argv[i]) == 0 && i+1 < argc)
window.delay = atoi(argv[++i]); window.delay = atoi(argv[++i]);
@@ -840,7 +1144,7 @@ main(int argc, char **argv)
else if (strcmp("-o", argv[i]) == 0) else if (strcmp("-o", argv[i]) == 0)
window.opaque = 1; window.opaque = 1;
else if (strcmp("-s", argv[i]) == 0) else if (strcmp("-s", argv[i]) == 0)
window.buffer_size = 16; window.buffer_bpp = 16;
else if (strcmp("-b", argv[i]) == 0) else if (strcmp("-b", argv[i]) == 0)
window.frame_sync = 0; window.frame_sync = 0;
else if (strcmp("-h", argv[i]) == 0) else if (strcmp("-h", argv[i]) == 0)
@@ -887,7 +1191,7 @@ main(int argc, char **argv)
while (running && ret != -1) { while (running && ret != -1) {
ret = wl_display_dispatch_pending(display.display); ret = wl_display_dispatch_pending(display.display);
redraw(&window, NULL, 0); redraw(&window);
} }
fprintf(stderr, "simple-egl exiting\n"); fprintf(stderr, "simple-egl exiting\n");
@@ -897,6 +1201,8 @@ main(int argc, char **argv)
wl_surface_destroy(display.cursor_surface); wl_surface_destroy(display.cursor_surface);
out_no_xdg_shell: out_no_xdg_shell:
display_destroy_outputs(&display);
if (display.cursor_theme) if (display.cursor_theme)
wl_cursor_theme_destroy(display.cursor_theme); wl_cursor_theme_destroy(display.cursor_theme);
+2 -4
View File
@@ -75,11 +75,9 @@ create_shm_buffer(struct touch *touch)
struct wl_shm_pool *pool; struct wl_shm_pool *pool;
int fd, size, stride; int fd, size, stride;
void *data; void *data;
struct buffer *buffer = NULL; struct buffer *buffer;
buffer = zalloc(sizeof(*buffer)); buffer = xzalloc(sizeof(*buffer));
if (!buffer)
return NULL;
stride = touch->width * 4; stride = touch->width * 4;
size = stride * touch->height; size = stride * touch->height;
+19 -4
View File
@@ -3023,13 +3023,22 @@ static void
terminal_destroy(struct terminal *terminal) terminal_destroy(struct terminal *terminal)
{ {
display_unwatch_fd(terminal->display, terminal->master); display_unwatch_fd(terminal->display, terminal->master);
window_destroy(terminal->window);
close(terminal->master); close(terminal->master);
cairo_scaled_font_destroy(terminal->font_bold);
cairo_scaled_font_destroy(terminal->font_normal);
widget_destroy(terminal->widget);
window_destroy(terminal->window);
wl_list_remove(&terminal->link); wl_list_remove(&terminal->link);
if (wl_list_empty(&terminal_list)) if (wl_list_empty(&terminal_list))
display_exit(terminal->display); display_exit(terminal->display);
free(terminal->data);
free(terminal->data_attr);
free(terminal->tab_ruler);
free(terminal->title); free(terminal->title);
free(terminal); free(terminal);
} }
@@ -3048,9 +3057,11 @@ io_handler(struct task *task, uint32_t events)
} }
len = read(terminal->master, buffer, sizeof buffer); len = read(terminal->master, buffer, sizeof buffer);
if (len < 0) if (len < 0) {
terminal_destroy(terminal); terminal_destroy(terminal);
else return;
}
terminal_data(terminal, buffer, len); terminal_data(terminal, buffer, len);
} }
@@ -3128,7 +3139,7 @@ static const struct weston_option terminal_options[] = {
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct display *d; struct display *d;
struct terminal *terminal; struct terminal *terminal, *tmp;
const char *config_file; const char *config_file;
struct sigaction sigpipe; struct sigaction sigpipe;
struct weston_config *config; struct weston_config *config;
@@ -3183,5 +3194,9 @@ int main(int argc, char *argv[])
display_run(d); display_run(d);
wl_list_for_each_safe(terminal, tmp, &terminal_list, link)
terminal_destroy(terminal);
display_destroy(d);
return 0; return 0;
} }
File diff suppressed because it is too large Load Diff
+38 -371
View File
@@ -42,25 +42,6 @@
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <stdbool.h> #include <stdbool.h>
#ifdef HAVE_CAIRO_EGL
#include <wayland-egl.h>
#ifdef USE_CAIRO_GLESV2
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#else
#include <GL/gl.h>
#endif
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <cairo-gl.h>
#elif !defined(ENABLE_EGL) /* platform.h defines these if EGL is enabled */
typedef void *EGLDisplay;
typedef void *EGLConfig;
typedef void *EGLContext;
#define EGL_NO_DISPLAY ((EGLDisplay)0)
#endif /* no HAVE_CAIRO_EGL */
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#ifdef HAVE_XKBCOMMON_COMPOSE #ifdef HAVE_XKBCOMMON_COMPOSE
@@ -109,10 +90,6 @@ struct display {
struct xdg_wm_base *xdg_shell; struct xdg_wm_base *xdg_shell;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints; struct zwp_pointer_constraints_v1 *pointer_constraints;
EGLDisplay dpy;
EGLConfig argb_config;
EGLContext argb_ctx;
cairo_device_t *argb_device;
uint32_t serial; uint32_t serial;
int display_fd; int display_fd;
@@ -178,18 +155,6 @@ struct toysurface {
enum wl_output_transform buffer_transform, int32_t buffer_scale, enum wl_output_transform buffer_transform, int32_t buffer_scale,
struct rectangle *server_allocation); struct rectangle *server_allocation);
/*
* Make the toysurface current with the given EGL context.
* Returns 0 on success, and negative on failure.
*/
int (*acquire)(struct toysurface *base, EGLContext ctx);
/*
* Release the toysurface from the EGL context, returning control
* to Cairo.
*/
void (*release)(struct toysurface *base);
/* /*
* Destroy the toysurface, including the Cairo surface, any * Destroy the toysurface, including the Cairo surface, any
* backing storage, and the Wayland protocol objects. * backing storage, and the Wayland protocol objects.
@@ -240,6 +205,7 @@ struct window {
int redraw_needed; int redraw_needed;
int redraw_task_scheduled; int redraw_task_scheduled;
struct task redraw_task; struct task redraw_task;
struct task close_task;
int resize_needed; int resize_needed;
int custom; int custom;
int focused; int focused;
@@ -545,167 +511,6 @@ buffer_to_surface_size (enum wl_output_transform buffer_transform, int32_t buffe
*height /= buffer_scale; *height /= buffer_scale;
} }
#ifdef HAVE_CAIRO_EGL
struct egl_window_surface {
struct toysurface base;
cairo_surface_t *cairo_surface;
struct display *display;
struct wl_surface *surface;
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
};
static struct egl_window_surface *
to_egl_window_surface(struct toysurface *base)
{
return container_of(base, struct egl_window_surface, base);
}
static cairo_surface_t *
egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
int32_t width, int32_t height, uint32_t flags,
enum wl_output_transform buffer_transform, int32_t buffer_scale)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
surface_to_buffer_size (buffer_transform, buffer_scale, &width, &height);
wl_egl_window_resize(surface->egl_window, width, height, dx, dy);
cairo_gl_surface_set_size(surface->cairo_surface, width, height);
return cairo_surface_reference(surface->cairo_surface);
}
static void
egl_window_surface_swap(struct toysurface *base,
enum wl_output_transform buffer_transform, int32_t buffer_scale,
struct rectangle *server_allocation)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
cairo_gl_surface_swapbuffers(surface->cairo_surface);
wl_egl_window_get_attached_size(surface->egl_window,
&server_allocation->width,
&server_allocation->height);
buffer_to_surface_size (buffer_transform, buffer_scale,
&server_allocation->width,
&server_allocation->height);
}
static int
egl_window_surface_acquire(struct toysurface *base, EGLContext ctx)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
cairo_device_t *device;
device = cairo_surface_get_device(surface->cairo_surface);
if (!device)
return -1;
if (!ctx) {
if (device == surface->display->argb_device)
ctx = surface->display->argb_ctx;
else
assert(0);
}
cairo_device_flush(device);
cairo_device_acquire(device);
if (!eglMakeCurrent(surface->display->dpy, surface->egl_surface,
surface->egl_surface, ctx))
fprintf(stderr, "failed to make surface current\n");
return 0;
}
static void
egl_window_surface_release(struct toysurface *base)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
cairo_device_t *device;
device = cairo_surface_get_device(surface->cairo_surface);
if (!device)
return;
if (!eglMakeCurrent(surface->display->dpy,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
fprintf(stderr, "failed to make context current\n");
cairo_device_release(device);
}
static void
egl_window_surface_destroy(struct toysurface *base)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
struct display *d = surface->display;
cairo_surface_destroy(surface->cairo_surface);
weston_platform_destroy_egl_surface(d->dpy, surface->egl_surface);
wl_egl_window_destroy(surface->egl_window);
surface->surface = NULL;
free(surface);
}
static struct toysurface *
egl_window_surface_create(struct display *display,
struct wl_surface *wl_surface,
uint32_t flags,
struct rectangle *rectangle)
{
struct egl_window_surface *surface;
if (display->dpy == EGL_NO_DISPLAY)
return NULL;
surface = zalloc(sizeof *surface);
if (!surface)
return NULL;
surface->base.prepare = egl_window_surface_prepare;
surface->base.swap = egl_window_surface_swap;
surface->base.acquire = egl_window_surface_acquire;
surface->base.release = egl_window_surface_release;
surface->base.destroy = egl_window_surface_destroy;
surface->display = display;
surface->surface = wl_surface;
surface->egl_window = wl_egl_window_create(surface->surface,
rectangle->width,
rectangle->height);
surface->egl_surface =
weston_platform_create_egl_surface(display->dpy,
display->argb_config,
surface->egl_window, NULL);
surface->cairo_surface =
cairo_gl_surface_create_for_egl(display->argb_device,
surface->egl_surface,
rectangle->width,
rectangle->height);
return &surface->base;
}
#else
static struct toysurface *
egl_window_surface_create(struct display *display,
struct wl_surface *wl_surface,
uint32_t flags,
struct rectangle *rectangle)
{
return NULL;
}
#endif
struct shm_surface_data { struct shm_surface_data {
struct wl_buffer *buffer; struct wl_buffer *buffer;
struct shm_pool *pool; struct shm_pool *pool;
@@ -1159,17 +964,6 @@ shm_surface_swap(struct toysurface *base,
surface->current = NULL; surface->current = NULL;
} }
static int
shm_surface_acquire(struct toysurface *base, EGLContext ctx)
{
return -1;
}
static void
shm_surface_release(struct toysurface *base)
{
}
static void static void
shm_surface_destroy(struct toysurface *base) shm_surface_destroy(struct toysurface *base)
{ {
@@ -1192,8 +986,6 @@ shm_surface_create(struct display *display, struct wl_surface *wl_surface,
surface = xzalloc(sizeof *surface); surface = xzalloc(sizeof *surface);
surface->base.prepare = shm_surface_prepare; surface->base.prepare = shm_surface_prepare;
surface->base.swap = shm_surface_swap; surface->base.swap = shm_surface_swap;
surface->base.acquire = shm_surface_acquire;
surface->base.release = shm_surface_release;
surface->base.destroy = shm_surface_destroy; surface->base.destroy = shm_surface_destroy;
surface->display = display; surface->display = display;
@@ -1432,13 +1224,23 @@ window_has_focus(struct window *window)
return window->focused; return window->focused;
} }
static void
close_task_run(struct task *task, uint32_t events)
{
struct window *window = container_of(task, struct window, close_task);
window->close_handler(window->user_data);
}
static void static void
window_close(struct window *window) window_close(struct window *window)
{ {
if (window->close_handler) if (window->close_handler && !window->close_task.run) {
window->close_handler(window->user_data); window->close_task.run = close_task_run;
else display_defer(window->display, &window->close_task);
} else {
display_exit(window->display); display_exit(window->display);
}
} }
struct display * struct display *
@@ -1453,15 +1255,6 @@ surface_create_surface(struct surface *surface, uint32_t flags)
struct display *display = surface->window->display; struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation; struct rectangle allocation = surface->allocation;
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
egl_window_surface_create(display,
surface->surface,
flags,
&allocation);
}
if (!surface->toysurface) if (!surface->toysurface)
surface->toysurface = shm_surface_create(display, surface->toysurface = shm_surface_create(display,
surface->surface, surface->surface,
@@ -4439,9 +4232,24 @@ xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_surface)
window_close(window); window_close(window);
} }
static void
xdg_toplevel_handle_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height)
{
}
static void
xdg_toplevel_handle_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel,
struct wl_array *caps)
{
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = { static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_handle_configure, xdg_toplevel_handle_configure,
xdg_toplevel_handle_close, xdg_toplevel_handle_close,
xdg_toplevel_handle_configure_bounds,
xdg_toplevel_handle_wm_capabilities,
}; };
static void static void
@@ -5272,11 +5080,6 @@ surface_create(struct window *window)
static enum window_buffer_type static enum window_buffer_type
get_preferred_buffer_type(struct display *display) get_preferred_buffer_type(struct display *display)
{ {
#ifdef HAVE_CAIRO_EGL
if (display->argb_device && !getenv("TOYTOOLKIT_NO_EGL"))
return WINDOW_BUFFER_TYPE_EGL_WINDOW;
#endif
return WINDOW_BUFFER_TYPE_SHM; return WINDOW_BUFFER_TYPE_SHM;
} }
@@ -5319,14 +5122,14 @@ window_create(struct display *display)
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(window->display->xdg_shell, xdg_wm_base_get_xdg_surface(window->display->xdg_shell,
window->main_surface->surface); window->main_surface->surface);
fail_on_null(window->xdg_surface, 0, __FILE__, __LINE__); abort_oom_if_null(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface, xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window); &xdg_surface_listener, window);
window->xdg_toplevel = window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface); xdg_surface_get_toplevel(window->xdg_surface);
fail_on_null(window->xdg_toplevel, 0, __FILE__, __LINE__); abort_oom_if_null(window->xdg_toplevel);
xdg_toplevel_add_listener(window->xdg_toplevel, xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window); &xdg_toplevel_listener, window);
@@ -5531,7 +5334,7 @@ create_menu(struct display *display,
menu->widget = window_add_widget(menu->window, menu); menu->widget = window_add_widget(menu->window, menu);
menu->frame = frame_create(window->display->theme, 0, 0, menu->frame = frame_create(window->display->theme, 0, 0,
FRAME_BUTTON_NONE, NULL, NULL); FRAME_BUTTON_NONE, NULL, NULL);
fail_on_null(menu->frame, 0, __FILE__, __LINE__); abort_oom_if_null(menu->frame);
menu->entries = entries; menu->entries = entries;
menu->count = count; menu->count = count;
menu->release_count = 0; menu->release_count = 0;
@@ -5565,7 +5368,7 @@ create_simple_positioner(struct display *display,
struct xdg_positioner *positioner; struct xdg_positioner *positioner;
positioner = xdg_wm_base_create_positioner(display->xdg_shell); positioner = xdg_wm_base_create_positioner(display->xdg_shell);
fail_on_null(positioner, 0, __FILE__, __LINE__); abort_oom_if_null(positioner);
xdg_positioner_set_anchor_rect(positioner, x, y, 1, 1); xdg_positioner_set_anchor_rect(positioner, x, y, 1, 1);
xdg_positioner_set_size(positioner, w, h); xdg_positioner_set_size(positioner, w, h);
xdg_positioner_set_anchor(positioner, xdg_positioner_set_anchor(positioner,
@@ -5610,7 +5413,7 @@ window_show_menu(struct display *display,
window->xdg_surface = window->xdg_surface =
xdg_wm_base_get_xdg_surface(display->xdg_shell, xdg_wm_base_get_xdg_surface(display->xdg_shell,
window->main_surface->surface); window->main_surface->surface);
fail_on_null(window->xdg_surface, 0, __FILE__, __LINE__); abort_oom_if_null(window->xdg_surface);
xdg_surface_add_listener(window->xdg_surface, xdg_surface_add_listener(window->xdg_surface,
&xdg_surface_listener, window); &xdg_surface_listener, window);
@@ -5623,7 +5426,7 @@ window_show_menu(struct display *display,
window->xdg_popup = xdg_surface_get_popup(window->xdg_surface, window->xdg_popup = xdg_surface_get_popup(window->xdg_surface,
parent->xdg_surface, parent->xdg_surface,
positioner); positioner);
fail_on_null(window->xdg_popup, 0, __FILE__, __LINE__); abort_oom_if_null(window->xdg_popup);
xdg_positioner_destroy(positioner); xdg_positioner_destroy(positioner);
xdg_popup_grab(window->xdg_popup, input->seat, xdg_popup_grab(window->xdg_popup, input->seat,
display_get_serial(window->display)); display_get_serial(window->display));
@@ -6089,7 +5892,8 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
display_add_data_device(d, id, version); display_add_data_device(d, id, version);
} else if (strcmp(interface, "xdg_wm_base") == 0) { } else if (strcmp(interface, "xdg_wm_base") == 0) {
d->xdg_shell = wl_registry_bind(registry, id, d->xdg_shell = wl_registry_bind(registry, id,
&xdg_wm_base_interface, 1); &xdg_wm_base_interface,
MIN(version, 5));
xdg_wm_base_add_listener(d->xdg_shell, &wm_base_listener, d); xdg_wm_base_add_listener(d->xdg_shell, &wm_base_listener, d);
} else if (strcmp(interface, "text_cursor_position") == 0) { } else if (strcmp(interface, "text_cursor_position") == 0) {
d->text_cursor_position = d->text_cursor_position =
@@ -6140,90 +5944,6 @@ static const struct wl_registry_listener registry_listener = {
registry_handle_global_remove registry_handle_global_remove
}; };
#ifdef HAVE_CAIRO_EGL
static int
init_egl(struct display *d)
{
EGLint major, minor;
EGLint n;
#ifdef USE_CAIRO_GLESV2
# define GL_BIT EGL_OPENGL_ES2_BIT
#else
# define GL_BIT EGL_OPENGL_BIT
#endif
static const EGLint argb_cfg_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_DEPTH_SIZE, 1,
EGL_RENDERABLE_TYPE, GL_BIT,
EGL_NONE
};
#ifdef USE_CAIRO_GLESV2
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLint api = EGL_OPENGL_ES_API;
#else
EGLint *context_attribs = NULL;
EGLint api = EGL_OPENGL_API;
#endif
d->dpy =
weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
d->display, NULL);
if (!eglInitialize(d->dpy, &major, &minor)) {
fprintf(stderr, "failed to initialize EGL\n");
return -1;
}
if (!eglBindAPI(api)) {
fprintf(stderr, "failed to bind EGL client API\n");
return -1;
}
if (!eglChooseConfig(d->dpy, argb_cfg_attribs,
&d->argb_config, 1, &n) || n != 1) {
fprintf(stderr, "failed to choose argb EGL config\n");
return -1;
}
d->argb_ctx = eglCreateContext(d->dpy, d->argb_config,
EGL_NO_CONTEXT, context_attribs);
if (d->argb_ctx == NULL) {
fprintf(stderr, "failed to create EGL context\n");
return -1;
}
d->argb_device = cairo_egl_device_create(d->dpy, d->argb_ctx);
if (cairo_device_status(d->argb_device) != CAIRO_STATUS_SUCCESS) {
fprintf(stderr, "failed to get cairo EGL argb device\n");
return -1;
}
return 0;
}
static void
fini_egl(struct display *display)
{
cairo_device_destroy(display->argb_device);
eglMakeCurrent(display->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglTerminate(display->dpy);
eglReleaseThread();
}
#endif
static void static void
init_dummy_surface(struct display *display) init_dummy_surface(struct display *display)
{ {
@@ -6329,12 +6049,6 @@ display_create(int *argc, char *argv[])
return NULL; return NULL;
} }
#ifdef HAVE_CAIRO_EGL
if (init_egl(d) < 0)
fprintf(stderr, "EGL does not seem to work, "
"falling back to software rendering and wl_shm.\n");
#endif
create_cursors(d); create_cursors(d);
d->theme = theme_create(); d->theme = theme_create();
@@ -6393,10 +6107,7 @@ display_destroy(struct display *display)
theme_destroy(display->theme); theme_destroy(display->theme);
destroy_cursors(display); destroy_cursors(display);
#ifdef HAVE_CAIRO_EGL cleanup_after_cairo();
if (display->argb_device)
fini_egl(display);
#endif
if (display->relative_pointer_manager) if (display->relative_pointer_manager)
zwp_relative_pointer_manager_v1_destroy(display->relative_pointer_manager); zwp_relative_pointer_manager_v1_destroy(display->relative_pointer_manager);
@@ -6462,12 +6173,6 @@ display_has_subcompositor(struct display *display)
return display->subcompositor != NULL; return display->subcompositor != NULL;
} }
cairo_device_t *
display_get_cairo_device(struct display *display)
{
return display->argb_device;
}
struct output * struct output *
display_get_output(struct display *display) display_get_output(struct display *display)
{ {
@@ -6489,12 +6194,6 @@ display_get_serial(struct display *display)
return display->serial; return display->serial;
} }
EGLDisplay
display_get_egl_display(struct display *d)
{
return d->dpy;
}
struct wl_data_source * struct wl_data_source *
display_create_data_source(struct display *display) display_create_data_source(struct display *display)
{ {
@@ -6504,38 +6203,6 @@ display_create_data_source(struct display *display)
return NULL; return NULL;
} }
EGLConfig
display_get_argb_egl_config(struct display *d)
{
return d->argb_config;
}
int
display_acquire_window_surface(struct display *display,
struct window *window,
EGLContext ctx)
{
struct surface *surface = window->main_surface;
if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
return -1;
widget_get_cairo_surface(window->main_surface->widget);
return surface->toysurface->acquire(surface->toysurface, ctx);
}
void
display_release_window_surface(struct display *display,
struct window *window)
{
struct surface *surface = window->main_surface;
if (surface->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
return;
surface->toysurface->release(surface->toysurface);
}
void void
display_defer(struct display *display, struct task *task) display_defer(struct display *display, struct task *task)
{ {
-20
View File
@@ -71,9 +71,6 @@ display_get_display(struct display *display);
int int
display_has_subcompositor(struct display *display); display_has_subcompositor(struct display *display);
cairo_device_t *
display_get_cairo_device(struct display *display);
struct wl_compositor * struct wl_compositor *
display_get_compositor(struct display *display); display_get_compositor(struct display *display);
@@ -114,22 +111,6 @@ display_set_output_configure_handler(struct display *display,
struct wl_data_source * struct wl_data_source *
display_create_data_source(struct display *display); display_create_data_source(struct display *display);
#ifdef EGL_NO_DISPLAY
EGLDisplay
display_get_egl_display(struct display *d);
EGLConfig
display_get_argb_egl_config(struct display *d);
int
display_acquire_window_surface(struct display *display,
struct window *window,
EGLContext ctx);
void
display_release_window_surface(struct display *display,
struct window *window);
#endif
#define SURFACE_OPAQUE 0x01 #define SURFACE_OPAQUE 0x01
#define SURFACE_SHM 0x02 #define SURFACE_SHM 0x02
@@ -416,7 +397,6 @@ struct wl_subsurface *
widget_get_wl_subsurface(struct widget *widget); widget_get_wl_subsurface(struct widget *widget);
enum window_buffer_type { enum window_buffer_type {
WINDOW_BUFFER_TYPE_EGL_WINDOW,
WINDOW_BUFFER_TYPE_SHM, WINDOW_BUFFER_TYPE_SHM,
}; };
+447 -183
View File
@@ -1,7 +1,7 @@
/* /*
* Copyright © 2010-2011 Intel Corporation * Copyright © 2010-2011 Intel Corporation
* Copyright © 2008-2011 Kristian Høgsberg * Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2012-2018 Collabora, Ltd. * Copyright © 2012-2018,2022 Collabora, Ltd.
* Copyright © 2010-2011 Benjamin Franzke * Copyright © 2010-2011 Benjamin Franzke
* Copyright © 2013 Jason Ekstrand * Copyright © 2013 Jason Ekstrand
* Copyright © 2017, 2018 General Electric Company * Copyright © 2017, 2018 General Electric Company
@@ -36,6 +36,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -50,15 +51,16 @@
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/process-util.h"
#include "shared/string-helpers.h" #include "shared/string-helpers.h"
#include "git-version.h" #include "git-version.h"
#include <libweston/version.h> #include <libweston/version.h>
#include "weston.h" #include "weston.h"
#include "weston-private.h"
#include <libweston/backend-drm.h> #include <libweston/backend-drm.h>
#include <libweston/backend-headless.h> #include <libweston/backend-headless.h>
#include <libweston/backend-rdp.h> #include <libweston/backend-rdp.h>
#include <libweston/backend-fbdev.h>
#include <libweston/backend-x11.h> #include <libweston/backend-x11.h>
#include <libweston/backend-wayland.h> #include <libweston/backend-wayland.h>
#include <libweston/windowed-output-api.h> #include <libweston/windowed-output-api.h>
@@ -134,37 +136,6 @@ static struct weston_log_scope *log_scope;
static struct weston_log_scope *protocol_scope; static struct weston_log_scope *protocol_scope;
static int cached_tm_mday = -1; static int cached_tm_mday = -1;
static char *
weston_log_timestamp(char *buf, size_t len)
{
struct timeval tv;
struct tm *brokendown_time;
char datestr[128];
char timestr[128];
gettimeofday(&tv, NULL);
brokendown_time = localtime(&tv.tv_sec);
if (brokendown_time == NULL) {
snprintf(buf, len, "%s", "[(NULL)localtime] ");
return buf;
}
memset(datestr, 0, sizeof(datestr));
if (brokendown_time->tm_mday != cached_tm_mday) {
strftime(datestr, sizeof(datestr), "Date: %Y-%m-%d %Z\n",
brokendown_time);
cached_tm_mday = brokendown_time->tm_mday;
}
strftime(timestr, sizeof(timestr), "%H:%M:%S", brokendown_time);
/* if datestr is empty it prints only timestr*/
snprintf(buf, len, "%s[%s.%03li]", datestr,
timestr, (tv.tv_usec / 1000));
return buf;
}
static void static void
custom_handler(const char *fmt, va_list arg) custom_handler(const char *fmt, va_list arg)
{ {
@@ -172,7 +143,7 @@ custom_handler(const char *fmt, va_list arg)
weston_log_scope_printf(log_scope, "%s libwayland: ", weston_log_scope_printf(log_scope, "%s libwayland: ",
weston_log_timestamp(timestr, weston_log_timestamp(timestr,
sizeof(timestr))); sizeof(timestr), &cached_tm_mday));
weston_log_scope_vprintf(log_scope, fmt, arg); weston_log_scope_vprintf(log_scope, fmt, arg);
} }
@@ -218,7 +189,8 @@ vlog(const char *fmt, va_list ap)
if (weston_log_scope_is_enabled(log_scope)) { if (weston_log_scope_is_enabled(log_scope)) {
int len_va; int len_va;
char *log_timestamp = weston_log_timestamp(timestr, char *log_timestamp = weston_log_timestamp(timestr,
sizeof(timestr)); sizeof(timestr),
&cached_tm_mday);
len_va = vasprintf(&str, fmt, ap); len_va = vasprintf(&str, fmt, ap);
if (len_va >= 0) { if (len_va >= 0) {
len = weston_log_scope_printf(log_scope, "%s %s", len = weston_log_scope_printf(log_scope, "%s %s",
@@ -270,6 +242,8 @@ protocol_log_fn(void *user_data,
size_t logsize; size_t logsize;
char timestr[128]; char timestr[128];
struct wl_resource *res = message->resource; struct wl_resource *res = message->resource;
struct wl_client *client = wl_resource_get_client(res);
pid_t pid = 0;
const char *signature = message->message->signature; const char *signature = message->message->signature;
int i; int i;
char type; char type;
@@ -281,10 +255,12 @@ protocol_log_fn(void *user_data,
if (!fp) if (!fp)
return; return;
wl_client_get_credentials(client, &pid, NULL, NULL);
weston_log_scope_timestamp(protocol_scope, weston_log_scope_timestamp(protocol_scope,
timestr, sizeof timestr); timestr, sizeof timestr);
fprintf(fp, "%s ", timestr); fprintf(fp, "%s ", timestr);
fprintf(fp, "client %p %s ", wl_resource_get_client(res), fprintf(fp, "client %p (PID %d) %s ", client, pid,
direction == WL_PROTOCOL_LOGGER_REQUEST ? "rq" : "ev"); direction == WL_PROTOCOL_LOGGER_REQUEST ? "rq" : "ev");
fprintf(fp, "%s@%u.%s(", fprintf(fp, "%s@%u.%s(",
wl_resource_get_class(res), wl_resource_get_class(res),
@@ -382,6 +358,7 @@ sigchld_handler(int signal_number, void *data)
} }
wl_list_remove(&p->link); wl_list_remove(&p->link);
wl_list_init(&p->link);
p->cleanup(p, status); p->cleanup(p, status);
} }
@@ -391,12 +368,56 @@ sigchld_handler(int signal_number, void *data)
return 1; return 1;
} }
static void WL_EXPORT struct wl_client *
child_client_exec(int sockfd, const char *path) weston_client_launch(struct weston_compositor *compositor,
struct weston_process *proc,
const char *path,
weston_process_cleanup_func_t cleanup)
{ {
int clientfd; struct wl_client *client = NULL;
char s[32]; struct custom_env child_env;
struct fdstr wayland_socket;
const char *fail_cloexec = "Couldn't unset CLOEXEC on client socket";
const char *fail_seteuid = "Couldn't call seteuid";
char *fail_exec;
char * const *argp;
char * const *envp;
sigset_t allsigs; sigset_t allsigs;
pid_t pid;
bool ret;
size_t written __attribute__((unused));
weston_log("launching '%s'\n", path);
str_printf(&fail_exec, "Error: Couldn't launch client '%s'\n", path);
custom_env_init_from_environ(&child_env);
custom_env_add_arg(&child_env, path);
if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0,
wayland_socket.fds) < 0) {
weston_log("weston_client_launch: "
"socketpair failed while launching '%s': %s\n",
path, strerror(errno));
custom_env_fini(&child_env);
return NULL;
}
fdstr_update_str1(&wayland_socket);
custom_env_set_env_var(&child_env, "WAYLAND_SOCKET",
wayland_socket.str1);
argp = custom_env_get_argp(&child_env);
envp = custom_env_get_envp(&child_env);
pid = fork();
switch (pid) {
case 0:
/* Put the client in a new session so it won't catch signals
* intended for the parent. Sharing a session can be
* confusing when launching weston under gdb, as the ctrl-c
* intended for gdb will pass to the child, and weston
* will cleanly shut down when the child exits.
*/
setsid();
/* do not give our signal mask to the new process */ /* do not give our signal mask to the new process */
sigfillset(&allsigs); sigfillset(&allsigs);
@@ -404,65 +425,33 @@ child_client_exec(int sockfd, const char *path)
/* Launch clients as the user. Do not launch clients with wrong euid. */ /* Launch clients as the user. Do not launch clients with wrong euid. */
if (seteuid(getuid()) == -1) { if (seteuid(getuid()) == -1) {
weston_log("compositor: failed seteuid\n"); written = write(STDERR_FILENO, fail_seteuid,
return; strlen(fail_seteuid));
_exit(EXIT_FAILURE);
} }
/* SOCK_CLOEXEC closes both ends, so we dup the fd to get a ret = fdstr_clear_cloexec_fd1(&wayland_socket);
* non-CLOEXEC fd to pass through exec. */ if (!ret) {
clientfd = dup(sockfd); written = write(STDERR_FILENO, fail_cloexec,
if (clientfd == -1) { strlen(fail_cloexec));
weston_log("compositor: dup failed: %s\n", strerror(errno)); _exit(EXIT_FAILURE);
return;
} }
snprintf(s, sizeof s, "%d", clientfd); execve(argp[0], argp, envp);
setenv("WAYLAND_SOCKET", s, 1);
if (execl(path, path, NULL) < 0) if (fail_exec)
weston_log("compositor: executing '%s' failed: %s\n", written = write(STDERR_FILENO, fail_exec,
path, strerror(errno)); strlen(fail_exec));
} _exit(EXIT_FAILURE);
WL_EXPORT struct wl_client * default:
weston_client_launch(struct weston_compositor *compositor, close(wayland_socket.fds[1]);
struct weston_process *proc, client = wl_client_create(compositor->wl_display,
const char *path, wayland_socket.fds[0]);
weston_process_cleanup_func_t cleanup)
{
int sv[2];
pid_t pid;
struct wl_client *client;
weston_log("launching '%s'\n", path);
if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
weston_log("weston_client_launch: "
"socketpair failed while launching '%s': %s\n",
path, strerror(errno));
return NULL;
}
pid = fork();
if (pid == -1) {
close(sv[0]);
close(sv[1]);
weston_log("weston_client_launch: "
"fork failed while launching '%s': %s\n", path,
strerror(errno));
return NULL;
}
if (pid == 0) {
child_client_exec(sv[1], path);
_exit(-1);
}
close(sv[1]);
client = wl_client_create(compositor->wl_display, sv[0]);
if (!client) { if (!client) {
close(sv[0]); custom_env_fini(&child_env);
close(wayland_socket.fds[0]);
free(fail_exec);
weston_log("weston_client_launch: " weston_log("weston_client_launch: "
"wl_client_create failed while launching '%s'.\n", "wl_client_create failed while launching '%s'.\n",
path); path);
@@ -472,6 +461,18 @@ weston_client_launch(struct weston_compositor *compositor,
proc->pid = pid; proc->pid = pid;
proc->cleanup = cleanup; proc->cleanup = cleanup;
wet_watch_process(compositor, proc); wet_watch_process(compositor, proc);
break;
case -1:
fdstr_close_all(&wayland_socket);
weston_log("weston_client_launch: "
"fork failed while launching '%s': %s\n", path,
strerror(errno));
break;
}
custom_env_fini(&child_env);
free(fail_exec);
return client; return client;
} }
@@ -646,9 +647,6 @@ usage(int error_code)
#if defined(BUILD_DRM_COMPOSITOR) #if defined(BUILD_DRM_COMPOSITOR)
"\t\t\t\tdrm-backend.so\n" "\t\t\t\tdrm-backend.so\n"
#endif #endif
#if defined(BUILD_FBDEV_COMPOSITOR)
"\t\t\t\tfbdev-backend.so\n"
#endif
#if defined(BUILD_HEADLESS_COMPOSITOR) #if defined(BUILD_HEADLESS_COMPOSITOR)
"\t\t\t\theadless-backend.so\n" "\t\t\t\theadless-backend.so\n"
#endif #endif
@@ -685,22 +683,12 @@ usage(int error_code)
fprintf(out, fprintf(out,
"Options for drm-backend.so:\n\n" "Options for drm-backend.so:\n\n"
" --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n" " --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n"
" --tty=TTY\t\tThe tty to use\n"
" --drm-device=CARD\tThe DRM device to use, e.g. \"card0\".\n" " --drm-device=CARD\tThe DRM device to use, e.g. \"card0\".\n"
" --use-pixman\t\tUse the pixman (CPU) renderer\n" " --use-pixman\t\tUse the pixman (CPU) renderer\n"
" --current-mode\tPrefer current KMS mode over EDID preferred mode\n" " --current-mode\tPrefer current KMS mode over EDID preferred mode\n"
" --continue-without-input\tAllow the compositor to start without input devices\n\n"); " --continue-without-input\tAllow the compositor to start without input devices\n\n");
#endif #endif
#if defined(BUILD_FBDEV_COMPOSITOR)
fprintf(out,
"Options for fbdev-backend.so:\n\n"
" --tty=TTY\t\tThe tty to use\n"
" --device=DEVICE\tThe framebuffer device to use\n"
" --seat=SEAT\t\tThe seat that weston should run on, instead of the seat defined in XDG_SEAT\n"
"\n");
#endif
#if defined(BUILD_HEADLESS_COMPOSITOR) #if defined(BUILD_HEADLESS_COMPOSITOR)
fprintf(out, fprintf(out,
"Options for headless-backend.so:\n\n" "Options for headless-backend.so:\n\n"
@@ -721,6 +709,7 @@ usage(int error_code)
" --width=WIDTH\t\tWidth of desktop\n" " --width=WIDTH\t\tWidth of desktop\n"
" --height=HEIGHT\tHeight of desktop\n" " --height=HEIGHT\tHeight of desktop\n"
" --env-socket\t\tUse socket defined in RDP_FD env variable as peer connection\n" " --env-socket\t\tUse socket defined in RDP_FD env variable as peer connection\n"
" --external-listener-fd=FD\tUse socket as listener connection\n"
" --address=ADDR\tThe address to bind\n" " --address=ADDR\tThe address to bind\n"
" --port=PORT\t\tThe port to listen on\n" " --port=PORT\t\tThe port to listen on\n"
" --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n" " --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n"
@@ -869,7 +858,7 @@ handle_primary_client_destroyed(struct wl_listener *listener, void *data)
static int static int
weston_create_listening_socket(struct wl_display *display, const char *socket_name) weston_create_listening_socket(struct wl_display *display, const char *socket_name)
{ {
char name_candidate[16]; char name_candidate[32];
if (socket_name) { if (socket_name) {
if (wl_display_add_socket(display, socket_name)) { if (wl_display_add_socket(display, socket_name)) {
@@ -1002,7 +991,7 @@ wet_get_bindir_path(const char *name)
static int static int
load_modules(struct weston_compositor *ec, const char *modules, load_modules(struct weston_compositor *ec, const char *modules,
int *argc, char *argv[], bool *xwayland) int *argc, char *argv[])
{ {
const char *p, *end; const char *p, *end;
char buffer[256]; char buffer[256];
@@ -1016,11 +1005,11 @@ load_modules(struct weston_compositor *ec, const char *modules,
snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p); snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
if (strstr(buffer, "xwayland.so")) { if (strstr(buffer, "xwayland.so")) {
weston_log("Old Xwayland module loading detected: " weston_log("fatal: Old Xwayland module loading detected: "
"Please use --xwayland command line option " "Please use --xwayland command line option "
"or set xwayland=true in the [core] section " "or set xwayland=true in the [core] section "
"in weston.ini\n"); "in weston.ini\n");
*xwayland = true; return -1;
} else { } else {
if (wet_load_module(ec, buffer, argc, argv) < 0) if (wet_load_module(ec, buffer, argc, argv) < 0)
return -1; return -1;
@@ -1348,6 +1337,223 @@ wet_output_set_color_profile(struct weston_output *output,
return ok ? 0 : -1; return ok ? 0 : -1;
} }
static int
wet_output_set_eotf_mode(struct weston_output *output,
struct weston_config_section *section)
{
static const struct {
const char *name;
enum weston_eotf_mode eotf_mode;
} modes[] = {
{ "sdr", WESTON_EOTF_MODE_SDR },
{ "hdr-gamma", WESTON_EOTF_MODE_TRADITIONAL_HDR },
{ "st2084", WESTON_EOTF_MODE_ST2084 },
{ "hlg", WESTON_EOTF_MODE_HLG },
};
struct wet_compositor *compositor;
enum weston_eotf_mode eotf_mode = WESTON_EOTF_MODE_SDR;
char *str = NULL;
unsigned i;
compositor = to_wet_compositor(output->compositor);
if (section) {
weston_config_section_get_string(section, "eotf-mode",
&str, NULL);
}
if (!str) {
/* The default SDR mode is always supported. */
assert(weston_output_get_supported_eotf_modes(output) & eotf_mode);
weston_output_set_eotf_mode(output, eotf_mode);
return 0;
}
for (i = 0; i < ARRAY_LENGTH(modes); i++)
if (strcmp(str, modes[i].name) == 0)
break;
if (i == ARRAY_LENGTH(modes)) {
weston_log("Error in config for output '%s': '%s' is not a valid EOTF mode. Try one of:",
output->name, str);
for (i = 0; i < ARRAY_LENGTH(modes); i++)
weston_log_continue(" %s", modes[i].name);
weston_log_continue("\n");
return -1;
}
eotf_mode = modes[i].eotf_mode;
if ((weston_output_get_supported_eotf_modes(output) & eotf_mode) == 0) {
weston_log("Error: output '%s' does not support EOTF mode %s.\n",
output->name, str);
free(str);
return -1;
}
if (eotf_mode != WESTON_EOTF_MODE_SDR &&
!compositor->use_color_manager) {
weston_log("Error: EOTF mode %s on output '%s' requires color-management=true in weston.ini\n",
str, output->name);
free(str);
return -1;
}
weston_output_set_eotf_mode(output, eotf_mode);
free(str);
return 0;
}
struct wet_color_characteristics_keys {
const char *name;
enum weston_color_characteristics_groups group;
float minval;
float maxval;
};
#define COLOR_CHARAC_NAME "color_characteristics"
static int
parse_color_characteristics(struct weston_color_characteristics *cc_out,
struct weston_config_section *section)
{
static const struct wet_color_characteristics_keys keys[] = {
{ "red_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "red_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "green_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "green_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "blue_x", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "blue_y", WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES, 0.0f, 1.0f },
{ "white_x", WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE, 0.0f, 1.0f },
{ "white_y", WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE, 0.0f, 1.0f },
{ "max_L", WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL, 0.0f, 1e5f },
{ "min_L", WESTON_COLOR_CHARACTERISTICS_GROUP_MINL, 0.0f, 1e5f },
{ "maxFALL", WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL, 0.0f, 1e5f },
};
static const char *msgpfx = "Config error in weston.ini [" COLOR_CHARAC_NAME "]";
struct weston_color_characteristics cc = {};
float *const keyvalp[ARRAY_LENGTH(keys)] = {
/* These must be in the same order as keys[]. */
&cc.primary[0].x, &cc.primary[0].y,
&cc.primary[1].x, &cc.primary[1].y,
&cc.primary[2].x, &cc.primary[2].y,
&cc.white.x, &cc.white.y,
&cc.max_luminance,
&cc.min_luminance,
&cc.maxFALL,
};
bool found[ARRAY_LENGTH(keys)] = {};
uint32_t missing_group_mask = 0;
unsigned i;
char *section_name;
int ret = 0;
weston_config_section_get_string(section, "name",
&section_name, "<unnamed>");
if (strchr(section_name, ':') != NULL) {
ret = -1;
weston_log("%s name=%s: reserved name. Do not use ':' character in the name.\n",
msgpfx, section_name);
}
/* Parse keys if they exist */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
double value;
if (weston_config_section_get_double(section, keys[i].name,
&value, NAN) == 0) {
float f = value;
found[i] = true;
/* Range check, NaN shall not pass. */
if (f >= keys[i].minval && f <= keys[i].maxval) {
/* Key found, parsed, and good value. */
*keyvalp[i] = f;
continue;
}
ret = -1;
weston_log("%s name=%s: %s value %f is outside of the range %f - %f.\n",
msgpfx, section_name, keys[i].name, value,
keys[i].minval, keys[i].maxval);
continue;
}
if (errno == EINVAL) {
found[i] = true;
ret = -1;
weston_log("%s name=%s: failed to parse the value of key %s.\n",
msgpfx, section_name, keys[i].name);
}
}
/* Collect set and unset groups */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
uint32_t group = keys[i].group;
if (found[i])
cc.group_mask |= group;
else
missing_group_mask |= group;
}
/* Ensure groups are given fully or not at all. */
for (i = 0; i < ARRAY_LENGTH(keys); i++) {
uint32_t group = keys[i].group;
if ((cc.group_mask & group) && (missing_group_mask & group)) {
ret = -1;
weston_log("%s name=%s: group %d key %s is %s. "
"You must set either none or all keys of a group.\n",
msgpfx, section_name, ffs(group), keys[i].name,
found[i] ? "set" : "missing");
}
}
free(section_name);
if (ret == 0)
*cc_out = cc;
return ret;
}
WESTON_EXPORT_FOR_TESTS int
wet_output_set_color_characteristics(struct weston_output *output,
struct weston_config *wc,
struct weston_config_section *section)
{
char *cc_name = NULL;
struct weston_config_section *cc_section;
struct weston_color_characteristics cc;
weston_config_section_get_string(section, COLOR_CHARAC_NAME,
&cc_name, NULL);
if (!cc_name)
return 0;
cc_section = weston_config_get_section(wc, COLOR_CHARAC_NAME,
"name", cc_name);
if (!cc_section) {
weston_log("Config error in weston.ini, output %s: "
"no [" COLOR_CHARAC_NAME "] section with 'name=%s' found.\n",
output->name, cc_name);
goto out_error;
}
if (parse_color_characteristics(&cc, cc_section) < 0)
goto out_error;
weston_output_set_color_characteristics(output, &cc);
free(cc_name);
return 0;
out_error:
free(cc_name);
return -1;
}
static void static void
allow_content_protection(struct weston_output *output, allow_content_protection(struct weston_output *output,
struct weston_config_section *section) struct weston_config_section *section)
@@ -1503,14 +1709,46 @@ wet_head_tracker_create(struct wet_compositor *compositor,
weston_head_add_destroy_listener(head, &track->head_destroy_listener); weston_head_add_destroy_listener(head, &track->head_destroy_listener);
} }
/* Place output exactly to the right of the most recently enabled output.
*
* Historically, we haven't given much thought to output placement,
* simply adding outputs in a horizontal line as they're enabled. This
* function simply sets an output's x coordinate to the right of the
* most recently enabled output, and its y to zero.
*
* If you're adding new calls to this function, you're also not giving
* much thought to output placement, so please consider carefully if
* it's really doing what you want.
*
* You especially don't want to use this for any code that won't
* immediately enable the passed output.
*/
static void
weston_output_lazy_align(struct weston_output *output)
{
struct weston_compositor *c;
struct weston_output *peer;
int next_x = 0;
/* Put this output to the right of the most recently enabled output */
c = output->compositor;
if (!wl_list_empty(&c->output_list)) {
peer = container_of(c->output_list.prev,
struct weston_output, link);
next_x = peer->x + peer->width;
}
output->x = next_x;
output->y = 0;
}
static void static void
simple_head_enable(struct wet_compositor *wet, struct weston_head *head) simple_head_enable(struct wet_compositor *wet, struct weston_head *head)
{ {
struct weston_output *output; struct weston_output *output;
int ret = 0; int ret = 0;
output = weston_compositor_create_output_with_head(wet->compositor, output = weston_compositor_create_output(wet->compositor, head,
head); head->name);
if (!output) { if (!output) {
weston_log("Could not create an output for head \"%s\".\n", weston_log("Could not create an output for head \"%s\".\n",
weston_head_get_name(head)); weston_head_get_name(head));
@@ -1519,6 +1757,8 @@ simple_head_enable(struct wet_compositor *wet, struct weston_head *head)
return; return;
} }
weston_output_lazy_align(output);
if (wet->simple_output_configure) if (wet->simple_output_configure)
ret = wet->simple_output_configure(output); ret = wet->simple_output_configure(output);
if (ret < 0) { if (ret < 0) {
@@ -1813,6 +2053,8 @@ drm_backend_output_configure(struct weston_output *output,
enum weston_drm_backend_output_mode mode = enum weston_drm_backend_output_mode mode =
WESTON_DRM_BACKEND_OUTPUT_PREFERRED; WESTON_DRM_BACKEND_OUTPUT_PREFERRED;
uint32_t transform = WL_OUTPUT_TRANSFORM_NORMAL; uint32_t transform = WL_OUTPUT_TRANSFORM_NORMAL;
uint32_t max_bpc = 0;
bool max_bpc_specified = false;
char *s; char *s;
char *modeline = NULL; char *modeline = NULL;
char *gbm_format = NULL; char *gbm_format = NULL;
@@ -1825,12 +2067,18 @@ drm_backend_output_configure(struct weston_output *output,
} }
weston_config_section_get_string(section, "mode", &s, "preferred"); weston_config_section_get_string(section, "mode", &s, "preferred");
if (weston_config_section_get_uint(section, "max-bpc", &max_bpc, 16) == 0)
max_bpc_specified = true;
if (strcmp(s, "off") == 0) { if (strcmp(s, "off") == 0) {
assert(0 && "off was supposed to be pruned"); assert(0 && "off was supposed to be pruned");
return -1; return -1;
} else if (wet->drm_use_current_mode || strcmp(s, "current") == 0) { } else if (wet->drm_use_current_mode || strcmp(s, "current") == 0) {
mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT; mode = WESTON_DRM_BACKEND_OUTPUT_CURRENT;
/* If mode=current and no max-bpc was specfied on the .ini file,
use current max_bpc so full modeset is not done. */
if (!max_bpc_specified)
max_bpc = 0;
} else if (strcmp(s, "preferred") != 0) { } else if (strcmp(s, "preferred") != 0) {
modeline = s; modeline = s;
s = NULL; s = NULL;
@@ -1844,6 +2092,8 @@ drm_backend_output_configure(struct weston_output *output,
} }
free(modeline); free(modeline);
api->set_max_bpc(output, max_bpc);
if (count_remaining_heads(output, NULL) == 1) { if (count_remaining_heads(output, NULL) == 1) {
struct weston_head *head = weston_output_get_first_head(output); struct weston_head *head = weston_output_get_first_head(output);
transform = weston_head_get_transform(head); transform = weston_head_get_transform(head);
@@ -1871,6 +2121,13 @@ drm_backend_output_configure(struct weston_output *output,
allow_content_protection(output, section); allow_content_protection(output, section);
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
if (wet_output_set_color_characteristics(output,
wet->config, section) < 0)
return -1;
return 0; return 0;
} }
@@ -1958,7 +2215,9 @@ wet_output_handle_destroy(struct wl_listener *listener, void *data)
} }
static struct wet_output * static struct wet_output *
wet_layoutput_create_output(struct wet_layoutput *lo, const char *name) wet_layoutput_create_output_with_head(struct wet_layoutput *lo,
const char *name,
struct weston_head *head)
{ {
struct wet_output *output; struct wet_output *output;
@@ -1968,7 +2227,7 @@ wet_layoutput_create_output(struct wet_layoutput *lo, const char *name)
output->output = output->output =
weston_compositor_create_output(lo->compositor->compositor, weston_compositor_create_output(lo->compositor->compositor,
name); head, name);
if (!output->output) { if (!output->output) {
free(output); free(output);
return NULL; return NULL;
@@ -2121,8 +2380,8 @@ drm_try_attach(struct weston_output *output,
{ {
unsigned i; unsigned i;
/* try to attach all heads, this probably succeeds */ /* try to attach remaining heads, this probably succeeds */
for (i = 0; i < add->n; i++) { for (i = 1; i < add->n; i++) {
if (!add->heads[i]) if (!add->heads[i])
continue; continue;
@@ -2142,6 +2401,8 @@ drm_try_enable(struct weston_output *output,
{ {
/* Try to enable, and detach heads one by one until it succeeds. */ /* Try to enable, and detach heads one by one until it succeeds. */
while (!output->enabled) { while (!output->enabled) {
weston_output_lazy_align(output);
if (weston_output_enable(output) == 0) if (weston_output_enable(output) == 0)
return 0; return 0;
@@ -2238,7 +2499,8 @@ drm_process_layoutput(struct wet_compositor *wet, struct wet_layoutput *lo)
if (ret < 0) if (ret < 0)
return -1; return -1;
} }
output = wet_layoutput_create_output(lo, name); output = wet_layoutput_create_output_with_head(lo, name,
lo->add.heads[0]);
free(name); free(name);
name = NULL; name = NULL;
@@ -2625,17 +2887,26 @@ load_drm_backend(struct weston_compositor *c,
struct weston_config_section *section; struct weston_config_section *section;
struct wet_compositor *wet = to_wet_compositor(c); struct wet_compositor *wet = to_wet_compositor(c);
bool without_input = false; bool without_input = false;
bool use_pixman_default;
int ret = 0; int ret = 0;
wet->drm_use_current_mode = false; wet->drm_use_current_mode = false;
section = weston_config_get_section(wc, "core", NULL, NULL); section = weston_config_get_section(wc, "core", NULL, NULL);
/* Use the pixman renderer by default when GBM/EGL support is
* not enabled */
#if defined(BUILD_DRM_GBM)
use_pixman_default = false;
#else
use_pixman_default = true;
#endif
weston_config_section_get_bool(section, "use-pixman", &config.use_pixman, weston_config_section_get_bool(section, "use-pixman", &config.use_pixman,
false); use_pixman_default);
const struct weston_option options[] = { const struct weston_option options[] = {
{ WESTON_OPTION_STRING, "seat", 0, &config.seat_id }, { WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
{ WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
{ WESTON_OPTION_STRING, "drm-device", 0, &config.specific_device }, { WESTON_OPTION_STRING, "drm-device", 0, &config.specific_device },
{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode }, { WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman }, { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
@@ -2688,6 +2959,15 @@ headless_backend_output_configure(struct weston_output *output)
.scale = 1, .scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL .transform = WL_OUTPUT_TRANSFORM_NORMAL
}; };
struct weston_config *wc = wet_get_config(output->compositor);
struct weston_config_section *section;
section = weston_config_get_section(wc, "output", "name", output->name);
if (wet_output_set_eotf_mode(output, section) < 0)
return -1;
if (wet_output_set_color_characteristics(output, wc, section) < 0)
return -1;
return wet_configure_windowed_output_from_config(output, &defaults); return wet_configure_windowed_output_from_config(output, &defaults);
} }
@@ -2806,8 +3086,11 @@ weston_rdp_backend_config_init(struct weston_rdp_backend_config *config)
config->server_cert = NULL; config->server_cert = NULL;
config->server_key = NULL; config->server_key = NULL;
config->env_socket = 0; config->env_socket = 0;
config->external_listener_fd = -1;
config->no_clients_resize = 0; config->no_clients_resize = 0;
config->force_no_compression = 0; config->force_no_compression = 0;
config->remotefx_codec = true;
config->refresh_rate = RDP_DEFAULT_FREQ;
} }
static int static int
@@ -2815,7 +3098,9 @@ load_rdp_backend(struct weston_compositor *c,
int *argc, char *argv[], struct weston_config *wc) int *argc, char *argv[], struct weston_config *wc)
{ {
struct weston_rdp_backend_config config = {{ 0, }}; struct weston_rdp_backend_config config = {{ 0, }};
struct weston_config_section *section;
int ret = 0; int ret = 0;
bool no_remotefx_codec = false;
struct wet_output_config *parsed_options = wet_init_parsed_options(c); struct wet_output_config *parsed_options = wet_init_parsed_options(c);
if (!parsed_options) if (!parsed_options)
@@ -2825,6 +3110,7 @@ load_rdp_backend(struct weston_compositor *c,
const struct weston_option rdp_options[] = { const struct weston_option rdp_options[] = {
{ WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket }, { WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
{ WESTON_OPTION_INTEGER, "external-listener-fd", 0, &config.external_listener_fd },
{ WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width }, { WESTON_OPTION_INTEGER, "width", 0, &parsed_options->width },
{ WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height }, { WESTON_OPTION_INTEGER, "height", 0, &parsed_options->height },
{ WESTON_OPTION_STRING, "address", 0, &config.bind_address }, { WESTON_OPTION_STRING, "address", 0, &config.bind_address },
@@ -2834,11 +3120,17 @@ load_rdp_backend(struct weston_compositor *c,
{ WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert }, { WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert },
{ WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }, { WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key },
{ WESTON_OPTION_BOOLEAN, "force-no-compression", 0, &config.force_no_compression }, { WESTON_OPTION_BOOLEAN, "force-no-compression", 0, &config.force_no_compression },
{ WESTON_OPTION_BOOLEAN, "no-remotefx-codec", 0, &no_remotefx_codec },
}; };
parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv); parse_options(rdp_options, ARRAY_LENGTH(rdp_options), argc, argv);
config.remotefx_codec = !no_remotefx_codec;
wet_set_simple_head_configurator(c, rdp_backend_output_configure); wet_set_simple_head_configurator(c, rdp_backend_output_configure);
section = weston_config_get_section(wc, "rdp", NULL, NULL);
weston_config_section_get_int(section, "refresh-rate",
&config.refresh_rate,
RDP_DEFAULT_FREQ);
ret = weston_compositor_load_backend(c, WESTON_BACKEND_RDP, ret = weston_compositor_load_backend(c, WESTON_BACKEND_RDP,
&config.base); &config.base);
@@ -2851,54 +3143,6 @@ load_rdp_backend(struct weston_compositor *c,
return ret; return ret;
} }
static int
fbdev_backend_output_configure(struct weston_output *output)
{
struct weston_config *wc = wet_get_config(output->compositor);
struct weston_config_section *section;
section = weston_config_get_section(wc, "output", "name", "fbdev");
if (wet_output_set_transform(output, section,
WL_OUTPUT_TRANSFORM_NORMAL,
UINT32_MAX) < 0) {
return -1;
}
weston_output_set_scale(output, 1);
return 0;
}
static int
load_fbdev_backend(struct weston_compositor *c,
int *argc, char **argv, struct weston_config *wc)
{
struct weston_fbdev_backend_config config = {{ 0, }};
int ret = 0;
const struct weston_option fbdev_options[] = {
{ WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
{ WESTON_OPTION_STRING, "device", 0, &config.device },
{ WESTON_OPTION_STRING, "seat", 0, &config.seat_id },
};
parse_options(fbdev_options, ARRAY_LENGTH(fbdev_options), argc, argv);
config.base.struct_version = WESTON_FBDEV_BACKEND_CONFIG_VERSION;
config.base.struct_size = sizeof(struct weston_fbdev_backend_config);
config.configure_device = configure_input_device;
wet_set_simple_head_configurator(c, fbdev_backend_output_configure);
/* load the actual wayland backend and configure it */
ret = weston_compositor_load_backend(c, WESTON_BACKEND_FBDEV,
&config.base);
free(config.device);
return ret;
}
static int static int
x11_backend_output_configure(struct weston_output *output) x11_backend_output_configure(struct weston_output *output)
{ {
@@ -3144,8 +3388,6 @@ load_backend(struct weston_compositor *compositor, const char *backend,
return load_headless_backend(compositor, argc, argv, config); return load_headless_backend(compositor, argc, argv, config);
else if (strstr(backend, "rdp-backend.so")) else if (strstr(backend, "rdp-backend.so"))
return load_rdp_backend(compositor, argc, argv, config); return load_rdp_backend(compositor, argc, argv, config);
else if (strstr(backend, "fbdev-backend.so"))
return load_fbdev_backend(compositor, argc, argv, config);
else if (strstr(backend, "drm-backend.so")) else if (strstr(backend, "drm-backend.so"))
return load_drm_backend(compositor, argc, argv, config); return load_drm_backend(compositor, argc, argv, config);
else if (strstr(backend, "x11-backend.so")) else if (strstr(backend, "x11-backend.so"))
@@ -3266,13 +3508,19 @@ weston_log_subscribe_to_scopes(struct weston_log_context *log_ctx,
weston_log_setup_scopes(log_ctx, flight_rec, flight_rec_scopes); weston_log_setup_scopes(log_ctx, flight_rec, flight_rec_scopes);
} }
static void
sigint_helper(int sig)
{
raise(SIGUSR2);
}
WL_EXPORT int WL_EXPORT int
wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data) wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
{ {
int ret = EXIT_FAILURE; int ret = EXIT_FAILURE;
char *cmdline; char *cmdline;
struct wl_display *display; struct wl_display *display;
struct wl_event_source *signals[4]; struct wl_event_source *signals[3];
struct wl_event_loop *loop; struct wl_event_loop *loop;
int i, fd; int i, fd;
char *backend = NULL; char *backend = NULL;
@@ -3302,6 +3550,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
struct weston_log_subscriber *logger = NULL; struct weston_log_subscriber *logger = NULL;
struct weston_log_subscriber *flight_rec = NULL; struct weston_log_subscriber *flight_rec = NULL;
sigset_t mask; sigset_t mask;
struct sigaction action;
bool wait_for_debugger = false; bool wait_for_debugger = false;
struct wl_protocol_logger *protologger = NULL; struct wl_protocol_logger *protologger = NULL;
@@ -3392,16 +3641,28 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
loop = wl_display_get_event_loop(display); loop = wl_display_get_event_loop(display);
signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal,
display); display);
signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal, signals[1] = wl_event_loop_add_signal(loop, SIGUSR2, on_term_signal,
display);
signals[2] = wl_event_loop_add_signal(loop, SIGQUIT, on_term_signal,
display); display);
wl_list_init(&wet.child_process_list); wl_list_init(&wet.child_process_list);
signals[3] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler, signals[2] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler,
&wet); &wet);
if (!signals[0] || !signals[1] || !signals[2] || !signals[3]) /* When debugging weston, if use wl_event_loop_add_signal() to catch
* SIGINT, the debugger can't catch it, and attempting to stop
* weston from within the debugger results in weston exiting
* cleanly.
*
* Instead, use the sigaction() function, which sets up the signal
* in a way that gdb can successfully catch, but have the handler
* for SIGINT send SIGUSR2 (xwayland uses SIGUSR1), which we catch
* via wl_event_loop_add_signal().
*/
action.sa_handler = sigint_helper;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGINT, &action, NULL);
if (!signals[0] || !signals[1] || !signals[2])
goto out_signals; goto out_signals;
/* Xwayland uses SIGUSR1 for communicating with weston. Since some /* Xwayland uses SIGUSR1 for communicating with weston. Since some
@@ -3522,13 +3783,10 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
if (wet_load_shell(wet.compositor, shell, &argc, argv) < 0) if (wet_load_shell(wet.compositor, shell, &argc, argv) < 0)
goto out; goto out;
weston_config_section_get_string(section, "modules", &modules, ""); /* Load xwayland before other modules - this way if we're using
if (load_modules(wet.compositor, modules, &argc, argv, &xwayland) < 0) * the systemd-notify module it will notify after we're ready
goto out; * to receive xwayland connections.
*/
if (load_modules(wet.compositor, option_modules, &argc, argv, &xwayland) < 0)
goto out;
if (!xwayland) { if (!xwayland) {
weston_config_section_get_bool(section, "xwayland", &xwayland, weston_config_section_get_bool(section, "xwayland", &xwayland,
false); false);
@@ -3538,6 +3796,13 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
goto out; goto out;
} }
weston_config_section_get_string(section, "modules", &modules, "");
if (load_modules(wet.compositor, modules, &argc, argv) < 0)
goto out;
if (load_modules(wet.compositor, option_modules, &argc, argv) < 0)
goto out;
section = weston_config_get_section(config, "keyboard", NULL, NULL); section = weston_config_get_section(config, "keyboard", NULL, NULL);
weston_config_section_get_bool(section, "numlock-on", &numlock_on, false); weston_config_section_get_bool(section, "numlock-on", &numlock_on, false);
if (numlock_on) { if (numlock_on) {
@@ -3573,8 +3838,6 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
ret = wet.compositor->exit_code; ret = wet.compositor->exit_code;
out: out:
wet_compositor_destroy_layout(&wet);
/* free(NULL) is valid, and it won't be NULL if it's used */ /* free(NULL) is valid, and it won't be NULL if it's used */
free(wet.parsed_options); free(wet.parsed_options);
@@ -3582,6 +3845,7 @@ out:
wl_protocol_logger_destroy(protologger); wl_protocol_logger_destroy(protologger);
weston_compositor_destroy(wet.compositor); weston_compositor_destroy(wet.compositor);
wet_compositor_destroy_layout(&wet);
weston_log_scope_destroy(protocol_scope); weston_log_scope_destroy(protocol_scope);
protocol_scope = NULL; protocol_scope = NULL;
+14 -10
View File
@@ -78,6 +78,7 @@ if get_option('screenshare')
deps_screenshare = [ deps_screenshare = [
dep_libexec_weston, dep_libexec_weston,
dep_libshared, dep_libshared,
dep_shell_utils,
dep_libweston_public, dep_libweston_public,
dep_libweston_private_h, # XXX: https://gitlab.freedesktop.org/wayland/weston/issues/292 dep_libweston_private_h, # XXX: https://gitlab.freedesktop.org/wayland/weston/issues/292
dep_wayland_client, dep_wayland_client,
@@ -95,19 +96,18 @@ if get_option('screenshare')
env_modmap += 'screen-share.so=@0@;'.format(plugin_screenshare.full_path()) env_modmap += 'screen-share.so=@0@;'.format(plugin_screenshare.full_path())
endif endif
if get_option('color-management-lcms') if get_option('deprecated-color-management-static')
config_h.set('HAVE_LCMS', '1')
srcs_lcms = [ srcs_lcms = [
'cms-static.c', 'cms-static.c',
'cms-helper.c', 'cms-helper.c',
] ]
dep_lcms2 = dependency('lcms2', required: false)
if not dep_lcms2.found() if not dep_lcms2.found()
error('cms-static requires lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.') error('cms-static requires lcms2 which was not found. Or, you can use \'-Ddeprecated-color-management-static=false\'.')
endif endif
config_h.set('HAVE_LCMS', '1')
plugin_lcms = shared_library( plugin_lcms = shared_library(
'cms-static', 'cms-static',
srcs_lcms, srcs_lcms,
@@ -119,11 +119,13 @@ if get_option('color-management-lcms')
install_rpath: '$ORIGIN' install_rpath: '$ORIGIN'
) )
env_modmap += 'cms-static.so=@0@;'.format(plugin_lcms.full_path()) env_modmap += 'cms-static.so=@0@;'.format(plugin_lcms.full_path())
warning('deprecated-color-management-static is enabled. This will go away, see https://gitlab.freedesktop.org/wayland/weston/-/issues/634')
endif endif
if get_option('color-management-colord') if get_option('deprecated-color-management-colord')
if not get_option('color-management-lcms') if not get_option('deprecated-color-management-static')
error('LCMS must be enabled to support colord. Or, you can use \'-Dcolor-management-colord=false\'.') error('deprecated-color-management-static must be enabled to support colord. Or, you can use \'-Ddeprecated-color-management-colord=false\'.')
endif endif
srcs_colord = [ srcs_colord = [
@@ -133,7 +135,7 @@ if get_option('color-management-colord')
dep_colord = dependency('colord', version: '>= 0.1.27', required: false) dep_colord = dependency('colord', version: '>= 0.1.27', required: false)
if not dep_colord.found() if not dep_colord.found()
error('cms-colord requires colord >= 0.1.27 which was not found. Or, you can use \'-Dcolor-management-colord=false\'.') error('cms-colord requires colord >= 0.1.27 which was not found. Or, you can use \'-Ddeprecated-color-management-colord=false\'.')
endif endif
plugin_colord_deps = [ dep_libweston_public, dep_colord, dep_lcms2 ] plugin_colord_deps = [ dep_libweston_public, dep_colord, dep_lcms2 ]
@@ -141,7 +143,7 @@ if get_option('color-management-colord')
foreach depname : [ 'glib-2.0', 'gobject-2.0' ] foreach depname : [ 'glib-2.0', 'gobject-2.0' ]
dep = dependency(depname, required: false) dep = dependency(depname, required: false)
if not dep.found() if not dep.found()
error('cms-colord requires \'@0@\' which was not found. If you rather not build this, set \'-Dcolor-management-colord=false\'.'.format(depname)) error('cms-colord requires \'@0@\' which was not found. If you rather not build this, set \'-Ddeprecated-color-management-colord=false\'.'.format(depname))
endif endif
plugin_colord_deps += dep plugin_colord_deps += dep
endforeach endforeach
@@ -156,6 +158,8 @@ if get_option('color-management-colord')
install_dir: dir_module_weston install_dir: dir_module_weston
) )
env_modmap += 'cms-colord.so=@0@;'.format(plugin_colord.full_path()) env_modmap += 'cms-colord.so=@0@;'.format(plugin_colord.full_path())
warning('deprecated-color-management-colord is enabled. This will go away, see https://gitlab.freedesktop.org/wayland/weston/-/issues/634')
endif endif
if get_option('systemd') if get_option('systemd')
+42 -18
View File
@@ -43,10 +43,12 @@
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include "backend.h" #include "backend.h"
#include "libweston-internal.h" #include "libweston-internal.h"
#include "pixel-formats.h"
#include "weston.h" #include "weston.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/os-compatibility.h" #include "shared/os-compatibility.h"
#include "shared/timespec-util.h" #include "shared/timespec-util.h"
#include "shell-utils/shell-utils.h"
#include "fullscreen-shell-unstable-v1-client-protocol.h" #include "fullscreen-shell-unstable-v1-client-protocol.h"
struct shared_output { struct shared_output {
@@ -59,7 +61,7 @@ struct shared_output {
struct wl_registry *registry; struct wl_registry *registry;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_shm *shm; struct wl_shm *shm;
uint32_t shm_formats; bool shm_formats_has_xrgb;
struct zwp_fullscreen_shell_v1 *fshell; struct zwp_fullscreen_shell_v1 *fshell;
struct wl_output *output; struct wl_output *output;
struct wl_surface *surface; struct wl_surface *surface;
@@ -114,9 +116,7 @@ struct ss_shm_buffer {
struct screen_share { struct screen_share {
struct weston_compositor *compositor; struct weston_compositor *compositor;
/* XXX: missing compositor destroy listener struct wl_listener compositor_destroy_listener;
* https://gitlab.freedesktop.org/wayland/weston/issues/298
*/
char *command; char *command;
}; };
@@ -368,7 +368,7 @@ ss_seat_create(struct shared_output *so, uint32_t id)
if (seat == NULL) if (seat == NULL)
return NULL; return NULL;
weston_seat_init(&seat->base, so->output->compositor, "default"); weston_seat_init(&seat->base, so->output->compositor, "screen-share");
seat->output = so; seat->output = so;
seat->id = id; seat->id = id;
seat->parent.seat = wl_registry_bind(so->parent.registry, id, seat->parent.seat = wl_registry_bind(so->parent.registry, id,
@@ -702,7 +702,8 @@ shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
{ {
struct shared_output *so = data; struct shared_output *so = data;
so->parent.shm_formats |= (1 << format); if (format == WL_SHM_FORMAT_XRGB8888)
so->parent.shm_formats_has_xrgb = true;
} }
struct wl_shm_listener shm_listener = { struct wl_shm_listener shm_listener = {
@@ -828,6 +829,9 @@ shared_output_repainted(struct wl_listener *listener, void *data)
pixman_box32_t *r; pixman_box32_t *r;
pixman_image_t *damaged_image; pixman_image_t *damaged_image;
pixman_transform_t transform; pixman_transform_t transform;
const struct pixel_format_info *read_format =
so->output->compositor->read_format;
const pixman_format_code_t pixman_format = read_format->pixman_format;
width = so->output->current_mode->width; width = so->output->current_mode->width;
height = so->output->current_mode->height; height = so->output->current_mode->height;
@@ -882,13 +886,13 @@ shared_output_repainted(struct wl_listener *listener, void *data)
y_orig = y; y_orig = y;
so->output->compositor->renderer->read_pixels( so->output->compositor->renderer->read_pixels(
so->output, PIXMAN_a8r8g8b8, so->tmp_data, so->output, read_format,
x, y_orig, width, height); so->tmp_data, x, y_orig, width, height);
damaged_image = pixman_image_create_bits(PIXMAN_a8r8g8b8, damaged_image = pixman_image_create_bits(pixman_format,
width, height, width, height,
so->tmp_data, so->tmp_data,
(PIXMAN_FORMAT_BPP(PIXMAN_a8r8g8b8) / 8) * width); (PIXMAN_FORMAT_BPP(pixman_format) / 8) * width);
if (!damaged_image) if (!damaged_image)
goto err_pixman_init; goto err_pixman_init;
@@ -968,7 +972,7 @@ shared_output_create(struct weston_output *output, int parent_fd)
/* Get SHM formats */ /* Get SHM formats */
wl_display_roundtrip(so->parent.display); wl_display_roundtrip(so->parent.display);
if (!(so->parent.shm_formats & (1 << WL_SHM_FORMAT_XRGB8888))) { if (!so->parent.shm_formats_has_xrgb) {
weston_log("Screen share failed: " weston_log("Screen share failed: "
"WL_SHM_FORMAT_XRGB8888 not available\n"); "WL_SHM_FORMAT_XRGB8888 not available\n");
goto err_display; goto err_display;
@@ -1144,22 +1148,37 @@ share_output_binding(struct weston_keyboard *keyboard,
struct screen_share *ss = data; struct screen_share *ss = data;
pointer = weston_seat_get_pointer(keyboard->seat); pointer = weston_seat_get_pointer(keyboard->seat);
if (!pointer) { if (pointer) {
weston_log("Cannot pick output: Seat does not have pointer\n");
return;
}
output = weston_output_find(pointer->seat->compositor, output = weston_output_find(pointer->seat->compositor,
wl_fixed_to_int(pointer->x), wl_fixed_to_int(pointer->x),
wl_fixed_to_int(pointer->y)); wl_fixed_to_int(pointer->y));
} else {
output = get_focused_output(keyboard->seat->compositor);
if (!output)
output = get_default_output(keyboard->seat->compositor);
}
if (!output) { if (!output) {
weston_log("Cannot pick output: Pointer not on any output\n"); weston_log("Cannot pick output: Pointer not on any output, "
"or no focused/default output found\n");
return; return;
} }
weston_output_share(output, ss->command); weston_output_share(output, ss->command);
} }
static void
compositor_destroy_listener(struct wl_listener *listener, void *data)
{
struct screen_share *ss =
wl_container_of(listener, ss, compositor_destroy_listener);
wl_list_remove(&ss->compositor_destroy_listener.link);
free(ss->command);
free(ss);
}
WL_EXPORT int WL_EXPORT int
wet_module_init(struct weston_compositor *compositor, wet_module_init(struct weston_compositor *compositor,
int *argc, char *argv[]) int *argc, char *argv[])
@@ -1175,11 +1194,16 @@ wet_module_init(struct weston_compositor *compositor,
return -1; return -1;
ss->compositor = compositor; ss->compositor = compositor;
wl_list_init(&ss->compositor_destroy_listener.link);
ss->compositor_destroy_listener.notify = compositor_destroy_listener;
wl_signal_add(&compositor->destroy_signal, &ss->compositor_destroy_listener);
config = wet_get_config(compositor); config = wet_get_config(compositor);
section = weston_config_get_section(config, "screen-share", NULL, NULL); section = weston_config_get_section(config, "screen-share", NULL, NULL);
weston_config_section_get_string(section, "command", &ss->command, ""); weston_config_section_get_string(section, "command", &ss->command, NULL);
weston_compositor_add_key_binding(compositor, KEY_S, weston_compositor_add_key_binding(compositor, KEY_S,
MODIFIER_CTRL | MODIFIER_ALT, MODIFIER_CTRL | MODIFIER_ALT,
+15 -3
View File
@@ -141,6 +141,12 @@ deactivate_input_method(struct input_method *input_method)
input_method->input = NULL; input_method->input = NULL;
input_method->context = NULL; input_method->context = NULL;
/* text_input_manager::destroy_listener by compositor shutdown */
if (!text_input->manager) {
zwp_text_input_v1_send_leave(text_input->resource);
return;
}
if (wl_list_empty(&text_input->input_methods) && if (wl_list_empty(&text_input->input_methods) &&
text_input->input_panel_visible && text_input->input_panel_visible &&
text_input->manager->current_text_input == text_input) { text_input->manager->current_text_input == text_input) {
@@ -456,6 +462,8 @@ text_input_manager_notifier_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&text_input_manager->destroy_listener.link); wl_list_remove(&text_input_manager->destroy_listener.link);
wl_global_destroy(text_input_manager->text_input_manager_global); wl_global_destroy(text_input_manager->text_input_manager_global);
if (text_input_manager->current_text_input)
text_input_manager->current_text_input->manager = NULL;
free(text_input_manager); free(text_input_manager);
} }
@@ -949,7 +957,7 @@ input_method_init_seat(struct weston_seat *seat)
seat->input_method->focus_listener_initialized = true; seat->input_method->focus_listener_initialized = true;
} }
static void launch_input_method(struct text_backend *text_backend); static void launch_input_method(void *data);
static void static void
respawn_input_method_process(struct text_backend *text_backend) respawn_input_method_process(struct text_backend *text_backend)
@@ -989,8 +997,10 @@ input_method_client_notifier(struct wl_listener *listener, void *data)
} }
static void static void
launch_input_method(struct text_backend *text_backend) launch_input_method(void *data)
{ {
struct text_backend *text_backend = data;
if (!text_backend->input_method.path) if (!text_backend->input_method.path)
return; return;
@@ -1093,6 +1103,7 @@ text_backend_init(struct weston_compositor *ec)
{ {
struct text_backend *text_backend; struct text_backend *text_backend;
struct weston_seat *seat; struct weston_seat *seat;
struct wl_event_loop *loop;
text_backend = zalloc(sizeof(*text_backend)); text_backend = zalloc(sizeof(*text_backend));
if (text_backend == NULL) if (text_backend == NULL)
@@ -1110,7 +1121,8 @@ text_backend_init(struct weston_compositor *ec)
text_input_manager_create(ec); text_input_manager_create(ec);
launch_input_method(text_backend); loop = wl_display_get_event_loop(ec->wl_display);
wl_event_loop_add_idle(loop, launch_input_method, text_backend);
return text_backend; return text_backend;
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2008 Kristian Høgsberg * Copyright 2022 Collabora, Ltd.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@@ -23,28 +23,12 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "config.h" #pragma once
#include <errno.h> #include <libweston/libweston.h>
#include <stdint.h> #include <libweston/config-parser.h>
#include <stdio.h>
#include <stdlib.h>
#include "xalloc.h" int
wet_output_set_color_characteristics(struct weston_output *output,
void * struct weston_config *wc,
fail_on_null(void *p, size_t size, char *file, int32_t line) struct weston_config_section *section);
{
if (p == NULL) {
fprintf(stderr, "[%s] ", program_invocation_short_name);
if (file)
fprintf(stderr, "%s:%d: ", file, line);
fprintf(stderr, "out of memory");
if (size)
fprintf(stderr, " (%zd)", size);
fprintf(stderr, "\n");
exit(EXIT_FAILURE);
}
return p;
}
+2 -1
View File
@@ -68,8 +68,9 @@ screenshooter_take_shot(struct wl_client *client,
{ {
struct weston_output *output = struct weston_output *output =
weston_head_from_resource(output_resource)->output; weston_head_from_resource(output_resource)->output;
struct weston_compositor *ec = output->compositor;
struct weston_buffer *buffer = struct weston_buffer *buffer =
weston_buffer_from_resource(buffer_resource); weston_buffer_from_resource(ec, buffer_resource);
if (buffer == NULL) { if (buffer == NULL) {
wl_resource_post_no_memory(resource); wl_resource_post_no_memory(resource);
+144 -78
View File
@@ -30,34 +30,65 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <fcntl.h>
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include "compositor/weston.h" #include "compositor/weston.h"
#include <libweston/xwayland-api.h> #include <libweston/xwayland-api.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/os-compatibility.h"
#include "shared/process-util.h"
#include "shared/string-helpers.h"
#ifdef HAVE_XWAYLAND_LISTENFD
# define LISTEN_STR "-listenfd"
#else
# define LISTEN_STR "-listen"
#endif
struct wet_xwayland { struct wet_xwayland {
struct weston_compositor *compositor; struct weston_compositor *compositor;
struct wl_listener compositor_destroy_listener;
const struct weston_xwayland_api *api; const struct weston_xwayland_api *api;
struct weston_xwayland *xwayland; struct weston_xwayland *xwayland;
struct wl_event_source *sigusr1_source; struct wl_event_source *display_fd_source;
struct wl_client *client; struct wl_client *client;
int wm_fd; int wm_fd;
struct weston_process process; struct weston_process process;
}; };
static int static int
handle_sigusr1(int signal_number, void *data) handle_display_fd(int fd, uint32_t mask, void *data)
{ {
struct wet_xwayland *wxw = data; struct wet_xwayland *wxw = data;
char buf[64];
ssize_t n;
/* We'd be safer if we actually had the struct /* xwayland exited before being ready, don't finish initialization,
* signalfd_siginfo from the signalfd data and could verify * the process watcher will cleanup */
* this came from Xwayland.*/ if (!(mask & WL_EVENT_READABLE))
wxw->api->xserver_loaded(wxw->xwayland, wxw->client, wxw->wm_fd); goto out;
wl_event_source_remove(wxw->sigusr1_source);
/* Xwayland writes to the pipe twice, so if we close it too early
* it's possible the second write will fail and Xwayland shuts down.
* Make sure we read until end of line marker to avoid this. */
n = read(fd, buf, sizeof buf);
if (n < 0 && errno != EAGAIN) {
weston_log("read from Xwayland display_fd failed: %s\n",
strerror(errno));
goto out;
}
/* Returning 1 here means recheck and call us again if required. */
if (n <= 0 || (n > 0 && buf[n - 1] != '\n'))
return 1; return 1;
wxw->api->xserver_loaded(wxw->xwayland, wxw->client, wxw->wm_fd);
out:
wl_event_source_remove(wxw->display_fd_source);
close(fd);
return 0;
} }
static pid_t static pid_t
@@ -65,93 +96,109 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd
{ {
struct wet_xwayland *wxw = user_data; struct wet_xwayland *wxw = user_data;
pid_t pid; pid_t pid;
char s[12], abstract_fd_str[12], unix_fd_str[12], wm_fd_str[12]; struct fdstr wayland_socket;
int sv[2], wm[2], fd; struct fdstr x11_abstract_socket;
struct fdstr x11_unix_socket;
struct fdstr x11_wm_socket;
struct fdstr display_pipe;
char *xserver = NULL; char *xserver = NULL;
struct weston_config *config = wet_get_config(wxw->compositor); struct weston_config *config = wet_get_config(wxw->compositor);
struct weston_config_section *section; struct weston_config_section *section;
struct wl_event_loop *loop;
char *exec_failure_msg;
struct custom_env child_env;
char *const *envp;
char *const *argp;
bool ret;
size_t written __attribute__ ((unused));
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, wayland_socket.fds) < 0) {
weston_log("wl connection socketpair failed\n"); weston_log("wl connection socketpair failed\n");
return 1; return 1;
} }
fdstr_update_str1(&wayland_socket);
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) { if (os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, x11_wm_socket.fds) < 0) {
weston_log("X wm connection socketpair failed\n"); weston_log("X wm connection socketpair failed\n");
return 1; return 1;
} }
fdstr_update_str1(&x11_wm_socket);
if (pipe2(display_pipe.fds, O_CLOEXEC) < 0) {
weston_log("pipe creation for displayfd failed\n");
return 1;
}
fdstr_update_str1(&display_pipe);
fdstr_set_fd1(&x11_abstract_socket, abstract_fd);
fdstr_set_fd1(&x11_unix_socket, unix_fd);
section = weston_config_get_section(config, "xwayland", NULL, NULL);
weston_config_section_get_string(section, "path",
&xserver, XSERVER_PATH);
str_printf(&exec_failure_msg,
"Error: executing Xwayland as '%s' failed.\n", xserver);
custom_env_init_from_environ(&child_env);
custom_env_set_env_var(&child_env, "WAYLAND_SOCKET", wayland_socket.str1);
custom_env_add_arg(&child_env, xserver);
custom_env_add_arg(&child_env, display);
custom_env_add_arg(&child_env, "-rootless");
custom_env_add_arg(&child_env, LISTEN_STR);
custom_env_add_arg(&child_env, x11_abstract_socket.str1);
custom_env_add_arg(&child_env, LISTEN_STR);
custom_env_add_arg(&child_env, x11_unix_socket.str1);
custom_env_add_arg(&child_env, "-displayfd");
custom_env_add_arg(&child_env, display_pipe.str1);
custom_env_add_arg(&child_env, "-wm");
custom_env_add_arg(&child_env, x11_wm_socket.str1);
custom_env_add_arg(&child_env, "-terminate");
envp = custom_env_get_envp(&child_env);
argp = custom_env_get_argp(&child_env);
pid = fork(); pid = fork();
switch (pid) { switch (pid) {
case 0: case 0:
setsid();
/* SOCK_CLOEXEC closes both ends, so we need to unset /* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */ * the flag on the client fd. */
fd = dup(sv[1]); ret = fdstr_clear_cloexec_fd1(&wayland_socket);
if (fd < 0) ret &= fdstr_clear_cloexec_fd1(&x11_abstract_socket);
goto fail; ret &= fdstr_clear_cloexec_fd1(&x11_unix_socket);
snprintf(s, sizeof s, "%d", fd); ret &= fdstr_clear_cloexec_fd1(&x11_wm_socket);
setenv("WAYLAND_SOCKET", s, 1); ret &= fdstr_clear_cloexec_fd1(&display_pipe);
if (!ret)
_exit(EXIT_FAILURE);
fd = dup(abstract_fd); execve(xserver, argp, envp);
if (fd < 0) /* execve does not return on success, so it failed */
goto fail;
snprintf(abstract_fd_str, sizeof abstract_fd_str, "%d", fd);
fd = dup(unix_fd);
if (fd < 0)
goto fail;
snprintf(unix_fd_str, sizeof unix_fd_str, "%d", fd);
fd = dup(wm[1]);
if (fd < 0)
goto fail;
snprintf(wm_fd_str, sizeof wm_fd_str, "%d", fd);
section = weston_config_get_section(config, if (exec_failure_msg) {
"xwayland", NULL, NULL); written = write(STDERR_FILENO, exec_failure_msg,
weston_config_section_get_string(section, "path", strlen(exec_failure_msg));
&xserver, XSERVER_PATH); }
/* Ignore SIGUSR1 in the child, which will make the X
* server send SIGUSR1 to the parent (weston) when
* it's done with initialization. During
* initialization the X server will round trip and
* block on the wayland compositor, so avoid making
* blocking requests (like xcb_connect_to_fd) until
* it's done with that. */
signal(SIGUSR1, SIG_IGN);
if (execl(xserver,
xserver,
display,
"-rootless",
#ifdef HAVE_XWAYLAND_LISTENFD
"-listenfd", abstract_fd_str,
"-listenfd", unix_fd_str,
#else
"-listen", abstract_fd_str,
"-listen", unix_fd_str,
#endif
"-wm", wm_fd_str,
"-terminate",
NULL) < 0)
weston_log("exec of '%s %s -rootless "
#ifdef HAVE_XWAYLAND_LISTENFD
"-listenfd %s -listenfd %s "
#else
"-listen %s -listen %s "
#endif
"-wm %s -terminate' failed: %s\n",
xserver, display,
abstract_fd_str, unix_fd_str, wm_fd_str,
strerror(errno));
fail:
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
default: default:
close(sv[1]); close(wayland_socket.fds[1]);
wxw->client = wl_client_create(wxw->compositor->wl_display, sv[0]); wxw->client = wl_client_create(wxw->compositor->wl_display,
wayland_socket.fds[0]);
close(wm[1]); close(x11_wm_socket.fds[1]);
wxw->wm_fd = wm[0]; wxw->wm_fd = x11_wm_socket.fds[0];
/* During initialization the X server will round trip
* and block on the wayland compositor, so avoid making
* blocking requests (like xcb_connect_to_fd) until
* it's done with that. */
close(display_pipe.fds[1]);
loop = wl_display_get_event_loop(wxw->compositor->wl_display);
wxw->display_fd_source =
wl_event_loop_add_fd(loop, display_pipe.fds[0],
WL_EVENT_READABLE,
handle_display_fd, wxw);
wxw->process.pid = pid; wxw->process.pid = pid;
wet_watch_process(wxw->compositor, &wxw->process); wet_watch_process(wxw->compositor, &wxw->process);
@@ -159,9 +206,16 @@ spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd
case -1: case -1:
weston_log("Failed to fork to spawn xserver process\n"); weston_log("Failed to fork to spawn xserver process\n");
fdstr_close_all(&wayland_socket);
fdstr_close_all(&x11_wm_socket);
fdstr_close_all(&display_pipe);
break; break;
} }
custom_env_fini(&child_env);
free(exec_failure_msg);
free(xserver);
return pid; return pid;
} }
@@ -170,22 +224,34 @@ xserver_cleanup(struct weston_process *process, int status)
{ {
struct wet_xwayland *wxw = struct wet_xwayland *wxw =
container_of(process, struct wet_xwayland, process); container_of(process, struct wet_xwayland, process);
struct wl_event_loop *loop =
wl_display_get_event_loop(wxw->compositor->wl_display);
wxw->api->xserver_exited(wxw->xwayland, status); wxw->api->xserver_exited(wxw->xwayland, status);
wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
handle_sigusr1, wxw);
wxw->client = NULL; wxw->client = NULL;
} }
static void
wxw_compositor_destroy(struct wl_listener *listener, void *data)
{
struct wet_xwayland *wxw =
wl_container_of(listener, wxw, compositor_destroy_listener);
wl_list_remove(&wxw->compositor_destroy_listener.link);
/* Don't call xserver_exited because Xwayland's own destroy handler
* already does this for us ... */
if (wxw->client)
kill(wxw->process.pid, SIGTERM);
wl_list_remove(&wxw->process.link);
free(wxw);
}
int int
wet_load_xwayland(struct weston_compositor *comp) wet_load_xwayland(struct weston_compositor *comp)
{ {
const struct weston_xwayland_api *api; const struct weston_xwayland_api *api;
struct weston_xwayland *xwayland; struct weston_xwayland *xwayland;
struct wet_xwayland *wxw; struct wet_xwayland *wxw;
struct wl_event_loop *loop;
if (weston_compositor_load_xwayland(comp) < 0) if (weston_compositor_load_xwayland(comp) < 0)
return -1; return -1;
@@ -209,13 +275,13 @@ wet_load_xwayland(struct weston_compositor *comp)
wxw->compositor = comp; wxw->compositor = comp;
wxw->api = api; wxw->api = api;
wxw->xwayland = xwayland; wxw->xwayland = xwayland;
wl_list_init(&wxw->process.link);
wxw->process.cleanup = xserver_cleanup; wxw->process.cleanup = xserver_cleanup;
wxw->compositor_destroy_listener.notify = wxw_compositor_destroy;
if (api->listen(xwayland, wxw, spawn_xserver) < 0) if (api->listen(xwayland, wxw, spawn_xserver) < 0)
return -1; return -1;
loop = wl_display_get_event_loop(comp->wl_display); wl_signal_add(&comp->destroy_signal, &wxw->compositor_destroy_listener);
wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
handle_sigusr1, wxw);
return 0; return 0;
} }
-737
View File
@@ -1,737 +0,0 @@
/*
* Copyright © 2010-2012 Intel Corporation
* Copyright © 2011-2012 Collabora, Ltd.
* Copyright © 2013 Raspberry Pi Foundation
*
* 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 <linux/input.h>
#include "shell.h"
#include "shared/helpers.h"
struct exposay_surface {
struct desktop_shell *shell;
struct exposay_output *eoutput;
struct weston_surface *surface;
struct weston_view *view;
struct wl_listener view_destroy_listener;
struct wl_list link;
int x;
int y;
int width;
int height;
double scale;
int row;
int column;
/* The animations only apply a transformation for their own lifetime,
* and don't have an option to indefinitely maintain the
* transformation in a steady state - so, we apply our own once the
* animation has finished. */
struct weston_transform transform;
};
static void exposay_set_state(struct desktop_shell *shell,
enum exposay_target_state state,
struct weston_seat *seat);
static void exposay_check_state(struct desktop_shell *shell);
static void
exposay_surface_destroy(struct exposay_surface *esurface)
{
wl_list_remove(&esurface->link);
wl_list_remove(&esurface->view_destroy_listener.link);
if (esurface->shell->exposay.focus_current == esurface->view)
esurface->shell->exposay.focus_current = NULL;
if (esurface->shell->exposay.focus_prev == esurface->view)
esurface->shell->exposay.focus_prev = NULL;
free(esurface);
}
static void
exposay_in_flight_inc(struct desktop_shell *shell)
{
shell->exposay.in_flight++;
}
static void
exposay_in_flight_dec(struct desktop_shell *shell)
{
if (--shell->exposay.in_flight > 0)
return;
exposay_check_state(shell);
}
static void
exposay_animate_in_done(struct weston_view_animation *animation, void *data)
{
struct exposay_surface *esurface = data;
wl_list_insert(&esurface->view->geometry.transformation_list,
&esurface->transform.link);
weston_matrix_init(&esurface->transform.matrix);
weston_matrix_scale(&esurface->transform.matrix,
esurface->scale, esurface->scale, 1.0f);
weston_matrix_translate(&esurface->transform.matrix,
esurface->x - esurface->view->geometry.x,
esurface->y - esurface->view->geometry.y,
0);
weston_view_geometry_dirty(esurface->view);
weston_compositor_schedule_repaint(esurface->view->surface->compositor);
exposay_in_flight_dec(esurface->shell);
}
static void
exposay_animate_in(struct exposay_surface *esurface)
{
exposay_in_flight_inc(esurface->shell);
weston_move_scale_run(esurface->view,
esurface->x - esurface->view->geometry.x,
esurface->y - esurface->view->geometry.y,
1.0, esurface->scale, 0,
exposay_animate_in_done, esurface);
}
static void
exposay_animate_out_done(struct weston_view_animation *animation, void *data)
{
struct exposay_surface *esurface = data;
struct desktop_shell *shell = esurface->shell;
exposay_surface_destroy(esurface);
exposay_in_flight_dec(shell);
}
static void
exposay_animate_out(struct exposay_surface *esurface)
{
exposay_in_flight_inc(esurface->shell);
/* Remove the static transformation set up by
* exposay_transform_in_done(). */
wl_list_remove(&esurface->transform.link);
weston_view_geometry_dirty(esurface->view);
weston_move_scale_run(esurface->view,
esurface->x - esurface->view->geometry.x,
esurface->y - esurface->view->geometry.y,
1.0, esurface->scale, 1,
exposay_animate_out_done, esurface);
}
static void
exposay_highlight_surface(struct desktop_shell *shell,
struct exposay_surface *esurface)
{
struct weston_view *view = esurface->view;
if (shell->exposay.focus_current == view)
return;
shell->exposay.row_current = esurface->row;
shell->exposay.column_current = esurface->column;
shell->exposay.cur_output = esurface->eoutput;
activate(shell, view, shell->exposay.seat,
WESTON_ACTIVATE_FLAG_NONE);
shell->exposay.focus_current = view;
}
static int
exposay_is_animating(struct desktop_shell *shell)
{
if (shell->exposay.state_cur == EXPOSAY_LAYOUT_INACTIVE ||
shell->exposay.state_cur == EXPOSAY_LAYOUT_OVERVIEW)
return 0;
return (shell->exposay.in_flight > 0);
}
static void
exposay_pick(struct desktop_shell *shell, int x, int y)
{
struct exposay_surface *esurface;
if (exposay_is_animating(shell))
return;
wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
if (x < esurface->x || x > esurface->x + esurface->width)
continue;
if (y < esurface->y || y > esurface->y + esurface->height)
continue;
exposay_highlight_surface(shell, esurface);
return;
}
}
static void
handle_view_destroy(struct wl_listener *listener, void *data)
{
struct exposay_surface *esurface = container_of(listener,
struct exposay_surface,
view_destroy_listener);
exposay_surface_destroy(esurface);
}
/* Compute each surface size and then inner pad (10% of surface size).
* After that, it's necessary to recompute surface size (90% of its
* original size). Also, each surface can't be bigger than half the
* exposay area width and height.
*/
static void
exposay_surface_and_inner_pad_size(pixman_rectangle32_t exposay_area, struct exposay_output *eoutput)
{
if (exposay_area.height < exposay_area.width)
eoutput->surface_size = exposay_area.height / eoutput->grid_size;
else
eoutput->surface_size = exposay_area.width / eoutput->grid_size;
eoutput->padding_inner = eoutput->surface_size / 10;
eoutput->surface_size -= eoutput->padding_inner;
if ((uint32_t)eoutput->surface_size > (exposay_area.width / 2))
eoutput->surface_size = exposay_area.width / 2;
if ((uint32_t)eoutput->surface_size > (exposay_area.height / 2))
eoutput->surface_size = exposay_area.height / 2;
}
/* Compute the exposay top/left margin in order to centralize it */
static void
exposay_margin_size(struct desktop_shell *shell, pixman_rectangle32_t exposay_area,
int row_size, int column_size, int *left_margin, int *top_margin)
{
(*left_margin) = exposay_area.x + (exposay_area.width - row_size) / 2;
(*top_margin) = exposay_area.y + (exposay_area.height - column_size) / 2;
}
/* Pretty lame layout for now; just tries to make a square. Should take
* aspect ratio into account really. Also needs to be notified of surface
* addition and removal and adjust layout/animate accordingly.
*
* Lay the grid out as square as possible, losing surfaces from the
* bottom row if required. Start with fixed padding of a 10% margin
* around the outside, and maximise the area made available to surfaces
* after this. Also, add an inner padding between surfaces that varies
* with the surface size (10% of its size).
*
* If we can't make a square grid, add one extra row at the bottom which
* will have a smaller number of columns.
*/
static enum exposay_layout_state
exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
{
struct workspace *workspace = shell->exposay.workspace;
struct weston_output *output = shell_output->output;
struct exposay_output *eoutput = &shell_output->eoutput;
struct weston_view *view;
struct exposay_surface *esurface, *highlight = NULL;
pixman_rectangle32_t exposay_area;
int pad, row_size, column_size, left_margin, top_margin;
int last_row_size, last_row_margin_increase;
int populated_rows;
int i;
eoutput->num_surfaces = 0;
wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
if (!get_shell_surface(view->surface))
continue;
if (view->output != output)
continue;
eoutput->num_surfaces++;
}
if (eoutput->num_surfaces == 0) {
eoutput->grid_size = 0;
eoutput->padding_inner = 0;
eoutput->surface_size = 0;
return EXPOSAY_LAYOUT_OVERVIEW;
}
/* Get exposay area and position, taking into account
* the shell panel position and size */
get_output_work_area(shell, output, &exposay_area);
/* Compute grid size */
eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
eoutput->grid_size++;
/* Compute each surface size and the inner padding between them */
exposay_surface_and_inner_pad_size(exposay_area, eoutput);
/* Compute each row/column size */
pad = eoutput->surface_size + eoutput->padding_inner;
row_size = (pad * eoutput->grid_size) - eoutput->padding_inner;
/* We may have empty rows that should be desconsidered to compute
* column size */
populated_rows = ceil(eoutput->num_surfaces / (float) eoutput->grid_size);
column_size = (pad * populated_rows) - eoutput->padding_inner;
/* The last row size can be different, since it may have less surfaces
* than the grid size. Also, its margin may be increased to centralize
* its surfaces, in the case where we don't have a perfect grid. */
last_row_size = ((eoutput->num_surfaces % eoutput->grid_size) * pad) - eoutput->padding_inner;
if (eoutput->num_surfaces % eoutput->grid_size)
last_row_margin_increase = (row_size - last_row_size) / 2;
else
last_row_margin_increase = 0;
/* Compute a top/left margin to centralize the exposay */
exposay_margin_size(shell, exposay_area, row_size, column_size, &left_margin, &top_margin);
i = 0;
wl_list_for_each(view, &workspace->layer.view_list.link, layer_link.link) {
if (!get_shell_surface(view->surface))
continue;
if (view->output != output)
continue;
esurface = malloc(sizeof(*esurface));
if (!esurface) {
exposay_set_state(shell, EXPOSAY_TARGET_CANCEL,
shell->exposay.seat);
break;
}
wl_list_insert(&shell->exposay.surface_list, &esurface->link);
esurface->shell = shell;
esurface->eoutput = eoutput;
esurface->view = view;
esurface->row = i / eoutput->grid_size;
esurface->column = i % eoutput->grid_size;
esurface->x = left_margin + (pad * esurface->column);
esurface->y = top_margin + (pad * esurface->row);
/* If this is the last row, increase left margin (it sums 0 if
* we have a perfect square) to centralize the surfaces */
if (eoutput->num_surfaces / eoutput->grid_size == esurface->row)
esurface->x += last_row_margin_increase;
if (view->surface->width > view->surface->height)
esurface->scale = eoutput->surface_size / (float) view->surface->width;
else
esurface->scale = eoutput->surface_size / (float) view->surface->height;
esurface->width = view->surface->width * esurface->scale;
esurface->height = view->surface->height * esurface->scale;
/* Surfaces are usually rectangular, but their exposay surfaces
* are square. centralize them in their own square */
if (esurface->width > esurface->height)
esurface->y += (esurface->width - esurface->height) / 2;
else
esurface->x += (esurface->height - esurface->width) / 2;
if (shell->exposay.focus_current == esurface->view)
highlight = esurface;
exposay_animate_in(esurface);
/* We want our destroy handler to be after the animation
* destroy handler in the list, this way when the view is
* destroyed, the animation can safely call the animation
* completion callback before we free the esurface in our
* destroy handler.
*/
esurface->view_destroy_listener.notify = handle_view_destroy;
wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
i++;
}
if (highlight) {
shell->exposay.focus_current = NULL;
exposay_highlight_surface(shell, highlight);
}
weston_compositor_schedule_repaint(shell->compositor);
return EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW;
}
static void
exposay_focus(struct weston_pointer_grab *grab)
{
}
static void
exposay_motion(struct weston_pointer_grab *grab,
const struct timespec *time,
struct weston_pointer_motion_event *event)
{
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_ptr);
weston_pointer_move(grab->pointer, event);
exposay_pick(shell,
wl_fixed_to_int(grab->pointer->x),
wl_fixed_to_int(grab->pointer->y));
}
static void
exposay_button(struct weston_pointer_grab *grab, const struct timespec *time,
uint32_t button, uint32_t state_w)
{
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_ptr);
struct weston_seat *seat = grab->pointer->seat;
enum wl_pointer_button_state state = state_w;
if (button != BTN_LEFT)
return;
/* Store the surface we clicked on, and don't do anything if we end up
* releasing on a different surface. */
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
shell->exposay.clicked = shell->exposay.focus_current;
return;
}
if (shell->exposay.focus_current == shell->exposay.clicked)
exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
else
shell->exposay.clicked = NULL;
}
static void
exposay_axis(struct weston_pointer_grab *grab,
const struct timespec *time,
struct weston_pointer_axis_event *event)
{
}
static void
exposay_axis_source(struct weston_pointer_grab *grab, uint32_t source)
{
}
static void
exposay_frame(struct weston_pointer_grab *grab)
{
}
static void
exposay_pointer_grab_cancel(struct weston_pointer_grab *grab)
{
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_ptr);
exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
}
static const struct weston_pointer_grab_interface exposay_ptr_grab = {
exposay_focus,
exposay_motion,
exposay_button,
exposay_axis,
exposay_axis_source,
exposay_frame,
exposay_pointer_grab_cancel,
};
static int
exposay_maybe_move(struct desktop_shell *shell, int row, int column)
{
struct exposay_surface *esurface;
wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
if (esurface->eoutput != shell->exposay.cur_output ||
esurface->row != row || esurface->column != column)
continue;
exposay_highlight_surface(shell, esurface);
return 1;
}
return 0;
}
static void
exposay_key(struct weston_keyboard_grab *grab, const struct timespec *time,
uint32_t key, uint32_t state_w)
{
struct weston_seat *seat = grab->keyboard->seat;
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_kbd);
enum wl_keyboard_key_state state = state_w;
if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
return;
switch (key) {
case KEY_ESC:
exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
break;
case KEY_ENTER:
exposay_set_state(shell, EXPOSAY_TARGET_SWITCH, seat);
break;
case KEY_UP:
exposay_maybe_move(shell, shell->exposay.row_current - 1,
shell->exposay.column_current);
break;
case KEY_DOWN:
/* Special case for trying to move to the bottom row when it
* has fewer items than all the others. */
if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
shell->exposay.column_current) &&
shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
exposay_maybe_move(shell, shell->exposay.row_current + 1,
(shell->exposay.cur_output->num_surfaces %
shell->exposay.cur_output->grid_size) - 1);
}
break;
case KEY_LEFT:
exposay_maybe_move(shell, shell->exposay.row_current,
shell->exposay.column_current - 1);
break;
case KEY_RIGHT:
exposay_maybe_move(shell, shell->exposay.row_current,
shell->exposay.column_current + 1);
break;
case KEY_TAB:
/* Try to move right, then down (and to the leftmost column),
* then if all else fails, to the top left. */
if (!exposay_maybe_move(shell, shell->exposay.row_current,
shell->exposay.column_current + 1) &&
!exposay_maybe_move(shell, shell->exposay.row_current + 1, 0))
exposay_maybe_move(shell, 0, 0);
break;
default:
break;
}
}
static void
exposay_modifier(struct weston_keyboard_grab *grab, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group)
{
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_kbd);
struct weston_seat *seat = (struct weston_seat *) grab->keyboard->seat;
/* We want to know when mod has been pressed and released.
* FIXME: There is a problem here: if mod is pressed, then a key
* is pressed and released, then mod is released, we will treat that
* as if only mod had been pressed and released. */
if (seat->modifier_state) {
if (seat->modifier_state == shell->binding_modifier) {
shell->exposay.mod_pressed = true;
} else {
shell->exposay.mod_invalid = true;
}
} else {
if (shell->exposay.mod_pressed && !shell->exposay.mod_invalid)
exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, seat);
shell->exposay.mod_invalid = false;
shell->exposay.mod_pressed = false;
}
return;
}
static void
exposay_cancel(struct weston_keyboard_grab *grab)
{
struct desktop_shell *shell =
container_of(grab, struct desktop_shell, exposay.grab_kbd);
exposay_set_state(shell, EXPOSAY_TARGET_CANCEL, shell->exposay.seat);
}
static const struct weston_keyboard_grab_interface exposay_kbd_grab = {
exposay_key,
exposay_modifier,
exposay_cancel,
};
/**
* Called when the transition from overview -> inactive has completed.
*/
static enum exposay_layout_state
exposay_set_inactive(struct desktop_shell *shell)
{
struct weston_seat *seat = shell->exposay.seat;
struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
if (pointer)
weston_pointer_end_grab(pointer);
if (keyboard) {
weston_keyboard_end_grab(keyboard);
if (keyboard->input_method_resource)
keyboard->grab = &keyboard->input_method_grab;
}
return EXPOSAY_LAYOUT_INACTIVE;
}
/**
* Begins the transition from overview to inactive. */
static enum exposay_layout_state
exposay_transition_inactive(struct desktop_shell *shell, int switch_focus)
{
struct exposay_surface *esurface;
/* Call activate() before we start the animations to avoid
* animating back the old state and then immediately transitioning
* to the new. */
if (switch_focus && shell->exposay.focus_current)
activate(shell, shell->exposay.focus_current,
shell->exposay.seat,
WESTON_ACTIVATE_FLAG_CONFIGURE);
else if (shell->exposay.focus_prev)
activate(shell, shell->exposay.focus_prev,
shell->exposay.seat,
WESTON_ACTIVATE_FLAG_CONFIGURE);
wl_list_for_each(esurface, &shell->exposay.surface_list, link)
exposay_animate_out(esurface);
weston_compositor_schedule_repaint(shell->compositor);
return EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE;
}
static enum exposay_layout_state
exposay_transition_active(struct desktop_shell *shell)
{
struct weston_seat *seat = shell->exposay.seat;
struct weston_pointer *pointer = weston_seat_get_pointer(seat);
struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
struct shell_output *shell_output;
bool animate = false;
shell->exposay.workspace = get_current_workspace(shell);
shell->exposay.focus_prev = get_default_view(keyboard->focus);
shell->exposay.focus_current = get_default_view(keyboard->focus);
shell->exposay.clicked = NULL;
wl_list_init(&shell->exposay.surface_list);
lower_fullscreen_layer(shell, NULL);
shell->exposay.grab_kbd.interface = &exposay_kbd_grab;
weston_keyboard_start_grab(keyboard,
&shell->exposay.grab_kbd);
weston_keyboard_set_focus(keyboard, NULL);
shell->exposay.grab_ptr.interface = &exposay_ptr_grab;
if (pointer) {
weston_pointer_start_grab(pointer,
&shell->exposay.grab_ptr);
weston_pointer_clear_focus(pointer);
}
wl_list_for_each(shell_output, &shell->output_list, link) {
enum exposay_layout_state state;
state = exposay_layout(shell, shell_output);
if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
animate = true;
}
return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
: EXPOSAY_LAYOUT_OVERVIEW;
}
static void
exposay_check_state(struct desktop_shell *shell)
{
enum exposay_layout_state state_new = shell->exposay.state_cur;
int do_switch = 0;
/* Don't do anything whilst animations are running, just store up
* target state changes and only act on them when the animations have
* completed. */
if (exposay_is_animating(shell))
return;
switch (shell->exposay.state_target) {
case EXPOSAY_TARGET_OVERVIEW:
switch (shell->exposay.state_cur) {
case EXPOSAY_LAYOUT_OVERVIEW:
goto out;
case EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW:
state_new = EXPOSAY_LAYOUT_OVERVIEW;
break;
default:
state_new = exposay_transition_active(shell);
break;
}
break;
case EXPOSAY_TARGET_SWITCH:
do_switch = 1; /* fallthrough */
case EXPOSAY_TARGET_CANCEL:
switch (shell->exposay.state_cur) {
case EXPOSAY_LAYOUT_INACTIVE:
goto out;
case EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE:
state_new = exposay_set_inactive(shell);
break;
default:
state_new = exposay_transition_inactive(shell, do_switch);
break;
}
break;
}
out:
shell->exposay.state_cur = state_new;
}
static void
exposay_set_state(struct desktop_shell *shell, enum exposay_target_state state,
struct weston_seat *seat)
{
shell->exposay.state_target = state;
shell->exposay.seat = seat;
exposay_check_state(shell);
}
void
exposay_binding(struct weston_keyboard *keyboard, enum weston_keyboard_modifier modifier,
void *data)
{
struct desktop_shell *shell = data;
exposay_set_state(shell, EXPOSAY_TARGET_OVERVIEW, keyboard->seat);
}
+1 -1
View File
@@ -103,8 +103,8 @@ show_input_panel_surface(struct input_panel_surface *ipsurf)
&ipsurf->view->layer_link); &ipsurf->view->layer_link);
weston_view_geometry_dirty(ipsurf->view); weston_view_geometry_dirty(ipsurf->view);
weston_view_update_transform(ipsurf->view); weston_view_update_transform(ipsurf->view);
ipsurf->surface->is_mapped = true;
ipsurf->view->is_mapped = true; ipsurf->view->is_mapped = true;
weston_surface_map(ipsurf->surface);
weston_surface_damage(ipsurf->surface); weston_surface_damage(ipsurf->surface);
if (ipsurf->anim) if (ipsurf->anim)
+1 -3
View File
@@ -3,9 +3,7 @@ if get_option('shell-desktop')
srcs_shell_desktop = [ srcs_shell_desktop = [
'shell.c', 'shell.c',
'exposay.c',
'input-panel.c', 'input-panel.c',
'../shared/shell-utils.c',
weston_desktop_shell_server_protocol_h, weston_desktop_shell_server_protocol_h,
weston_desktop_shell_protocol_c, weston_desktop_shell_protocol_c,
input_method_unstable_v1_server_protocol_h, input_method_unstable_v1_server_protocol_h,
@@ -15,8 +13,8 @@ if get_option('shell-desktop')
dep_libm, dep_libm,
dep_libexec_weston, dep_libexec_weston,
dep_libshared, dep_libshared,
dep_lib_desktop,
dep_libweston_public, dep_libweston_public,
dep_shell_utils,
] ]
plugin_shell_desktop = shared_library( plugin_shell_desktop = shared_library(
'desktop-shell', 'desktop-shell',
+317 -861
View File
File diff suppressed because it is too large Load Diff
+3 -72
View File
@@ -45,55 +45,8 @@ enum fade_type {
FADE_OUT FADE_OUT
}; };
enum exposay_target_state {
EXPOSAY_TARGET_OVERVIEW, /* show all windows */
EXPOSAY_TARGET_CANCEL, /* return to normal, same focus */
EXPOSAY_TARGET_SWITCH, /* return to normal, switch focus */
};
enum exposay_layout_state {
EXPOSAY_LAYOUT_INACTIVE = 0, /* normal desktop */
EXPOSAY_LAYOUT_ANIMATE_TO_INACTIVE, /* in transition to normal */
EXPOSAY_LAYOUT_OVERVIEW, /* show all windows */
EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW, /* in transition to all windows */
};
struct exposay_output {
int num_surfaces;
int grid_size;
int surface_size;
int padding_inner;
};
struct exposay {
/* XXX: Make these exposay_surfaces. */
struct weston_view *focus_prev;
struct weston_view *focus_current;
struct weston_view *clicked;
struct workspace *workspace;
struct weston_seat *seat;
struct wl_list surface_list;
struct weston_keyboard_grab grab_kbd;
struct weston_pointer_grab grab_ptr;
enum exposay_target_state state_target;
enum exposay_layout_state state_cur;
int in_flight; /* number of animations still running */
int row_current;
int column_current;
struct exposay_output *cur_output;
bool mod_pressed;
bool mod_invalid;
};
struct focus_surface { struct focus_surface {
struct weston_surface *surface; struct weston_curtain *curtain;
struct weston_view *view;
struct weston_transform workspace_transform;
}; };
struct workspace { struct workspace {
@@ -110,7 +63,6 @@ struct workspace {
struct shell_output { struct shell_output {
struct desktop_shell *shell; struct desktop_shell *shell;
struct weston_output *output; struct weston_output *output;
struct exposay_output eoutput;
struct wl_listener destroy_listener; struct wl_listener destroy_listener;
struct wl_list link; struct wl_list link;
@@ -121,7 +73,7 @@ struct shell_output {
struct wl_listener background_surface_listener; struct wl_listener background_surface_listener;
struct { struct {
struct weston_view *view; struct weston_curtain *curtain;
struct weston_view_animation *animation; struct weston_view_animation *animation;
enum fade_type type; enum fade_type type;
struct wl_event_source *startup_timer; struct wl_event_source *startup_timer;
@@ -175,32 +127,15 @@ struct desktop_shell {
struct weston_surface *lock_surface; struct weston_surface *lock_surface;
struct wl_listener lock_surface_listener; struct wl_listener lock_surface_listener;
struct { struct workspace workspace;
struct wl_array array;
unsigned int current;
unsigned int num;
struct wl_list client_list;
struct weston_animation animation;
struct wl_list anim_sticky_list;
int anim_dir;
struct timespec anim_timestamp;
double anim_current;
struct workspace *anim_from;
struct workspace *anim_to;
} workspaces;
struct { struct {
struct wl_resource *binding; struct wl_resource *binding;
struct wl_list surfaces; struct wl_list surfaces;
} input_panel; } input_panel;
struct exposay exposay;
bool allow_zap; bool allow_zap;
uint32_t binding_modifier; uint32_t binding_modifier;
uint32_t exposay_modifier;
enum animation_type win_animation_type; enum animation_type win_animation_type;
enum animation_type win_close_animation_type; enum animation_type win_close_animation_type;
enum animation_type startup_animation_type; enum animation_type startup_animation_type;
@@ -246,10 +181,6 @@ void
activate(struct desktop_shell *shell, struct weston_view *view, activate(struct desktop_shell *shell, struct weston_view *view,
struct weston_seat *seat, uint32_t flags); struct weston_seat *seat, uint32_t flags);
void
exposay_binding(struct weston_keyboard *keyboard,
enum weston_keyboard_modifier modifier,
void *data);
int int
input_panel_setup(struct desktop_shell *shell); input_panel_setup(struct desktop_shell *shell);
void void
+3 -296
View File
@@ -759,7 +759,7 @@ WARN_NO_PARAMDOC = NO
# a warning is encountered. # a warning is encountered.
# The default value is: NO. # The default value is: NO.
WARN_AS_ERROR = YES WARN_AS_ERROR = @MESON_WERROR@
# The WARN_FORMAT tag determines the format of the warning messages that doxygen # The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which # can produce. The string should contain the $file, $line, and $text tags, which
@@ -1486,17 +1486,6 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering # http://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
@@ -1632,241 +1621,6 @@ EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS = EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: latex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used by the
# printer.
# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
# 14 inches) and executive (7.25 x 10.5 inches).
# The default value is: a4.
# This tag requires that the tag GENERATE_LATEX is set to YES.
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. The package can be specified just
# by its name or with the correct syntax as to be used with the LaTeX
# \usepackage command. To get the times font for instance you can specify :
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
# To use the option intlimits with the amsmath package you can specify:
# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
# generated LaTeX document. The header should contain everything until the first
# chapter. If it is left blank doxygen will generate a standard header. See
# section "Doxygen usage" for information on how to let doxygen write the
# default header to a separate file.
#
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_STYLESHEET =
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
# markers available.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EXTRA_FILES =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
# contain links (just like the HTML output) instead of page references. This
# makes the output suitable for online browsing using a PDF viewer.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help. This option is also used
# when generating formulas in HTML.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BATCHMODE = NO
# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
# index chapters (such as File Index, Compound Index, etc.) in the output.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HIDE_INDICES = NO
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: rtf.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
# contain hyperlink fields. The RTF file will contain links (just like the HTML
# output) instead of page references. This makes the output suitable for online
# browsing using Word or some other Word compatible readers that support those
# fields.
#
# Note: WordPad (write) and others do not support links.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the man page output # Configuration options related to the man page output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1956,15 +1710,6 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output # Configuration options for the AutoGen Definitions output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -2143,15 +1888,6 @@ EXTERNAL_PAGES = YES
# Configuration options related to the dot tool # Configuration options related to the dot tool
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can include diagrams made with dia in doxygen documentation. Doxygen will # You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The # then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides. # DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2172,7 +1908,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO # set to NO
# The default value is: YES. # The default value is: YES.
HAVE_DOT = NO HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of # to run in parallel. When set to 0 doxygen will base this on the number of
@@ -2184,23 +1920,6 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0 DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the default font as specified with # By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag. # the path where dot can find it using this tag.
@@ -2401,7 +2120,7 @@ PLANTUML_INCLUDE_PATH =
# Minimum value: 0, maximum value: 10000, default value: 50. # Minimum value: 0, maximum value: 10000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50 DOT_GRAPH_MAX_NODES = 250
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
# generated by dot. A depth value of 3 means that only nodes reachable from the # generated by dot. A depth value of 3 means that only nodes reachable from the
@@ -2415,18 +2134,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = YES
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support # makes dot run faster, but since only newer versions of dot (>1.8.10) support
+1
View File
@@ -9,6 +9,7 @@ Welcome to Weston documentation!
toc/libweston.rst toc/libweston.rst
toc/test-suite.rst toc/test-suite.rst
toc/kiosk-shell.rst toc/kiosk-shell.rst
toc/ivi-shell.rst
Weston Weston
------ ------
+2
View File
@@ -1,5 +1,6 @@
sphinx = find_program('sphinx-build', required: true) sphinx = find_program('sphinx-build', required: true)
doxygen = find_program('doxygen', required: true) doxygen = find_program('doxygen', required: true)
dot = find_program('dot', required: true)
breathe = find_program('breathe-apidoc', required: true) breathe = find_program('breathe-apidoc', required: true)
sphinx_c = run_command(sphinx, '--version') sphinx_c = run_command(sphinx, '--version')
@@ -38,6 +39,7 @@ sphinx_conf = configure_file(
doxy_conf_data = configuration_data() doxy_conf_data = configuration_data()
doxy_conf_data.set('SRC_ROOT', meson.source_root()) doxy_conf_data.set('SRC_ROOT', meson.source_root())
doxy_conf_data.set('OUTPUT_DIR', doxygen_database) doxy_conf_data.set('OUTPUT_DIR', doxygen_database)
doxy_conf_data.set('MESON_WERROR', get_option('werror') == true ? 'YES' : 'NO')
doxygen_conf_weston = configure_file( doxygen_conf_weston = configure_file(
input: 'doxygen.ini.in', input: 'doxygen.ini.in',
output: 'doxygen.ini', output: 'doxygen.ini',
Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

+9
View File
@@ -0,0 +1,9 @@
# Sphinx does not know look for these files in the source directory, so
# they must be copied to the build directory.
files = [
'ivi-shell.png',
]
foreach file : files
configure_file(input: file, output: file, copy: true)
endforeach
+111
View File
@@ -0,0 +1,111 @@
Weston IVI-shell
================
Weston's IVI-shell is a highly customizable shell targeted at use cases which
need custom control over the shell's window layout with one or more applications
without interactive configuration of the layout by the user.
Example use cases for the IVI-shell are IVI applications or industrial human
machine interfaces. In general, whenever the user interface requires the exact
positioning of multiple application surfaces on one or more screens.
The IVI-shell also provides a means for applications to identify themselves to
the shell by application IDs via the ivi_application Wayland protocol.
IVI-shell client protocol
-------------------------
Wayland clients can implement the ``ivi_application`` Wayland protocol, which
allows them to specify an ``ivi_id`` to allow the IVI controller to identify the
application. This allows the controller to implement special behavior for
well-known applications.
The IVI-shell is able to also handle clients that use the ``xdg-shell``
protocol, but in these cases the IVI-shell needs other means to identify client
applications.
See ``ivi-application.xml`` for the protocol specification.
IVI-shell Weston modules
------------------------
The IVI-shell consists of two main components: The ``ivi-shell.so`` and custom
IVI controller (with the ``hmi-controller.so`` example implementation).
The ``ivi-shell.so`` is responsible for handling the application IDs and for
providing abstractions to configure the window layout via the
``ivi_layout_interface``. This interface is discussed in `IVI-shell compositor
implementation`.
The IVI controller uses the ``ivi_layout_interface`` to implement a window
manager and is responsible for configuring the window layout, i.e. the position
of the applications on the screens.
Due to this separation, both modules must be loaded in your ``weston.ini`` to
use the IVI-shell.
.. code-block:: ini
[core]
shell=ivi-shell.so
modules=hmi-controller.so
If you are using your custom controller, replace ``hmi-controller.so`` with the
name of your own controller module.
.. figure:: images/ivi-shell.png
:alt: IVI-shell architecture overview
Controlling the IVI-shell
-------------------------
The IVI-shell provides the ``ivi_layout_interface`` API that a controller must
use to control the window layout of the IVI-shell. See
``ivi-shell/ivi-layout-export.h`` for the definition of this API.
For the initial configuration, the controller has to create at least one
``ivi_layout_layer`` and add the ``ivi_layout_layer`` to a ``weston_output``.
The layers allow to group multiple applications surfaces and control them
together and are the main mechanism to group and organize surfaces. These are
always necessary to show something using the IVI-shell. The IVI-shell will
internally create an ``ivi_layout_screen``, but a controller always uses the
``weston_output`` directly.
To get control over the client surfaces, the controller must use notifiers that
trigger whenever there are changes to the client surfaces. The client surfaces
then show up as ``ivi_layout_surface``. These have an ID, which allows the
controller to identify the surface and reconfigure the window layout
accordingly.
The controller must add the ``ivi_layout_surface`` to an ``ivi_layout_layer``
and configure it's position and z-order wrt. the other surfaces in the layer.
Otherwise, the newly added surface will not show up on the screen.
The IVI-shell will internally create an ``ivi_layout_view`` for each layer that
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.
IVI-shell example implementation
--------------------------------
The IVI-shell comes with an example implementation of an IVI controller -- the
`hmi-controller`. The hmi-controller will usually replaced by a custom
implementation that implements the use-case-specific behavior.
The hmi-controller is split into two parts:
The ``hmi-controller.so`` is a Weston Plugin that uses the
``ivi_layout_interface`` to perform the window manager tasks. It allows some
reconfiguration of the window layout via the ``ivi_hmi_controller`` protocol.
Other implementations may keep all window management inside the module or may
expose even more window management via a custom protocol to an external process.
The ``weston-ivi-shell-user-interface`` is an example hmi-controller helper
client that serves as a user interface for controlling the hmi-controller.
The hmi-controller can be customized using the ``[ivi-shell]`` section in the
``weston.ini``. An example configuration will be generated in
``<build_dir>/ivi-shell/weston.ini``.
@@ -11,7 +11,7 @@ msc {
--- [label = "Compositor creates an output for a head"]; --- [label = "Compositor creates an output for a head"];
c box c [label = "Have an existing head to process."]; c box c [label = "Have an existing head to process."];
c => w [label = "weston_compositor_create_output_with_head()"]; c => w [label = "weston_compositor_create_output()"];
w => b [label = "weston_backend::create_output()"]; w => b [label = "weston_backend::create_output()"];
w << b [label = "an empty output, no hw resources"]; w << b [label = "an empty output, no hw resources"];
w => b [label = "weston_output::attach_head()"]; w => b [label = "weston_output::attach_head()"];
+2
View File
@@ -1,6 +1,7 @@
# you need to add here any files you add to the toc directory as well # you need to add here any files you add to the toc directory as well
files = [ files = [
'kiosk-shell.rst', 'kiosk-shell.rst',
'ivi-shell.rst',
'running-weston.rst', 'running-weston.rst',
'libweston.rst', 'libweston.rst',
'test-suite.rst', 'test-suite.rst',
@@ -11,4 +12,5 @@ foreach file : files
configure_file(input: file, output: file, copy: true) configure_file(input: file, output: file, copy: true)
endforeach endforeach
subdir('images')
subdir('libweston') subdir('libweston')
+20 -11
View File
@@ -6,7 +6,7 @@ underlying environment where it runs on. Ultimately, the back-end is
responsible for handling the input and generate an output. Weston, as a responsible for handling the input and generate an output. Weston, as a
libweston user, can be run on different back-ends, including nested, by using libweston user, can be run on different back-ends, including nested, by using
the wayland backend, but also on X11 or on a stand-alone back-end like the wayland backend, but also on X11 or on a stand-alone back-end like
DRM/KMS and now deprecated fbdev. DRM/KMS.
In most cases, people should allow Weston to choose the backend automatically In most cases, people should allow Weston to choose the backend automatically
as it will produce the best results. That happens for instance when running as it will produce the best results. That happens for instance when running
@@ -28,7 +28,6 @@ Available back-ends:
* **x11** -- run as a x11 application, nested in a X11 display server instance * **x11** -- run as a x11 application, nested in a X11 display server instance
* **rdp** -- run as an RDP server without local input or output * **rdp** -- run as an RDP server without local input or output
* **headless** -- run without input or output, useful for test suite * **headless** -- run without input or output, useful for test suite
* **fbdev** -- run stand-alone on fbdev/evdev (deprecated)
The job of gathering all the surfaces (windows) being displayed on an output and The job of gathering all the surfaces (windows) being displayed on an output and
stitching them together is performed by a *renderer*. By doing so, it is stitching them together is performed by a *renderer*. By doing so, it is
@@ -91,17 +90,20 @@ You can start Weston from a VT assuming that there's a seat manager supported by
backend to be used by ``libseat`` can optionally be selected with backend to be used by ``libseat`` can optionally be selected with
``$LIBSEAT_BACKEND``. If ``libseat`` and ``seatd`` are both installed, but ``$LIBSEAT_BACKEND``. If ``libseat`` and ``seatd`` are both installed, but
``seatd`` is not already running, it can be started with ``sudo -- seatd -g ``seatd`` is not already running, it can be started with ``sudo -- seatd -g
video``. If no seat manager supported by ``libseat`` is available, you can use video``.
the ``weston-launch`` application that can handle VT switching.
Another way of launching Weston is via ssh or a serial terminal. The simplest Launching Weston via ssh or a serial terminal is best with the ``libseat``
option here is to use the ``libseat`` launcher with ``seatd``. The process for launcher and ``seatd``. Logind will refuse to give access to local seats from
remote connections directly. The process for
setting that up is identical to the one described above, where one just need to setting that up is identical to the one described above, where one just need to
ensure that ``seatd`` is running with the appropriate arguments, after which one ensure that ``seatd`` is running with the appropriate arguments, after which one
can just run ``weston``. Another option, is to rely on logind and start weston can just run ``weston``. ``seatd`` will lend out the current VT, and if you want
as systemd user service: :ref:`weston-user-service`. Alternatively and as a last to run on a different VT you need to ``chvt`` first. Make sure nothing will try
resort, one can run Weston as root, specifying the tty to use on the command to take over the seat or VT via logind at the same time in case logind is
line: If TTY 2 is active, one would run ``weston --tty 2`` as root. running.
If you want to rely on logind, you can start weston as a systemd user service:
:ref:`weston-user-service`.
Running Weston on a different seat on a stand-alone back-end Running Weston on a different seat on a stand-alone back-end
------------------------------------------------------------ ------------------------------------------------------------
@@ -171,7 +173,14 @@ Then, weston can be run by selecting the DRM-backend and the seat ``seat-insecur
:: ::
./weston -Bdrm-backend.so --seat=seat-insecure SEATD_VTBOUND=0 ./weston -Bdrm-backend.so --seat=seat-insecure
This assumes you are using the libseat launcher of Weston with the "builtin"
backend of libseat. Libseat automatically falls back to the builtin backend if
``seatd`` is not running and a ``logind`` service is not running or refuses.
You can also force it with ``LIBSEAT_BACKEND=builtin`` if needed.
``SEATD_VTBOUND=0`` tells libseat that there is no VT associated with the
chosen seat.
If everything went well you should see weston be up-and-running on an output If everything went well you should see weston be up-and-running on an output
connected to that DRM device. connected to that DRM device.
+13 -4
View File
@@ -218,10 +218,19 @@ DRM-backend tests
DRM-backend tests require a DRM device, so they are a special case. To select a DRM-backend tests require a DRM device, so they are a special case. To select a
device the test suite will simply look at the environment variable device the test suite will simply look at the environment variable
``WESTON_TEST_SUITE_DRM_DEVICE``. So the first thing the user has to do in order ``WESTON_TEST_SUITE_DRM_DEVICE``. In Weston's CI, we set this variable to the
to run DRM-backend tests is to set this environment variable with the card that DRM node that VKMS takes (``cardX`` - X can change across each bot, as the order
should run the tests. For instance, in order to run DRM-backend tests with in which devices are loaded is not predictable).
``card0`` we need to run ``export WESTON_TEST_SUITE_DRM_DEVICE=card0``.
**IMPORTANT**: our DRM-backend tests are written specifically to run on top of
VKMS (KMS driver created to be used by headless machines in test suites, so it
aims to be more configurable and predictable than real hardware). We don't
guarantee that these tests will work on real hardware.
But if users want to run DRM-backend tests using real hardware anyway, the first
thing they need to do is to set this environment variable with the DRM node of
the card that should run the tests. For instance, in order to run DRM-backend
tests with ``card0`` we need to run ``export WESTON_TEST_SUITE_DRM_DEVICE=card0``.
Note that the card should not be in use by a desktop environment (or any other Note that the card should not be in use by a desktop environment (or any other
program that requires master status), as there can only be one user at a time program that requires master status), as there can only be one user at a time
+22 -66
View File
@@ -37,6 +37,7 @@
#include "compositor/weston.h" #include "compositor/weston.h"
#include "fullscreen-shell-unstable-v1-server-protocol.h" #include "fullscreen-shell-unstable-v1-server-protocol.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shell-utils.h"
struct fullscreen_shell { struct fullscreen_shell {
struct wl_client *client; struct wl_client *client;
@@ -80,7 +81,7 @@ struct fs_output {
struct weston_surface *surface; struct weston_surface *surface;
struct wl_listener surface_destroyed; struct wl_listener surface_destroyed;
struct weston_view *view; struct weston_view *view;
struct weston_view *black_view; struct weston_curtain *curtain;
struct weston_transform transform; /* matrix from x, y */ struct weston_transform transform; /* matrix from x, y */
int presented_for_mode; int presented_for_mode;
@@ -226,37 +227,27 @@ black_surface_committed(struct weston_surface *es, int32_t sx, int32_t sy)
{ {
} }
static struct weston_view * static struct weston_curtain *
create_black_surface(struct weston_compositor *ec, struct fs_output *fsout, create_curtain(struct weston_compositor *ec, struct fs_output *fsout,
float x, float y, int w, int h) float x, float y, int w, int h)
{ {
struct weston_surface *surface = NULL; struct weston_curtain_params curtain_params = {
struct weston_view *view; .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0,
.x = x, .y = y, .width = w, .height = h,
.surface_committed = black_surface_committed,
.get_label = NULL,
.surface_private = fsout,
.capture_input = true,
};
struct weston_curtain *curtain;
surface = weston_surface_create(ec); curtain = weston_curtain_create(ec, &curtain_params);
if (surface == NULL) { if (!curtain) {
weston_log("no memory\n");
return NULL;
}
view = weston_view_create(surface);
if (!view) {
weston_surface_destroy(surface);
weston_log("no memory\n"); weston_log("no memory\n");
return NULL; return NULL;
} }
surface->committed = black_surface_committed; return curtain;
surface->committed_private = fsout;
weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
pixman_region32_fini(&surface->opaque);
pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
pixman_region32_fini(&surface->input);
pixman_region32_init_rect(&surface->input, 0, 0, w, h);
weston_surface_set_size(surface, w, h);
weston_view_set_position(view, x, y);
return view;
} }
static void static void
@@ -333,13 +324,12 @@ fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
fsout->surface_destroyed.notify = surface_destroyed; fsout->surface_destroyed.notify = surface_destroyed;
fsout->pending.surface_destroyed.notify = pending_surface_destroyed; fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
fsout->black_view = create_black_surface(shell->compositor, fsout, fsout->curtain = create_curtain(shell->compositor, fsout,
output->x, output->y, output->x, output->y,
output->width, output->height); output->width, output->height);
fsout->black_view->surface->is_mapped = true; fsout->curtain->view->is_mapped = true;
fsout->black_view->is_mapped = true;
weston_layer_entry_insert(&shell->layer.view_list, weston_layer_entry_insert(&shell->layer.view_list,
&fsout->black_view->layer_link); &fsout->curtain->view->layer_link);
wl_list_init(&fsout->transform.link); wl_list_init(&fsout->transform.link);
if (!wl_list_empty(&shell->default_surface_list)) { if (!wl_list_empty(&shell->default_surface_list)) {
@@ -373,41 +363,6 @@ restore_output_mode(struct weston_output *output)
weston_output_mode_switch_to_native(output); weston_output_mode_switch_to_native(output);
} }
/*
* Returns the bounding box of a surface and all its sub-surfaces,
* in surface-local coordinates. */
static void
surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
int32_t *y, int32_t *w, int32_t *h) {
pixman_region32_t region;
pixman_box32_t *box;
struct weston_subsurface *subsurface;
pixman_region32_init_rect(&region, 0, 0,
surface->width,
surface->height);
wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
pixman_region32_union_rect(&region, &region,
subsurface->position.x,
subsurface->position.y,
subsurface->surface->width,
subsurface->surface->height);
}
box = pixman_region32_extents(&region);
if (x)
*x = box->x1;
if (y)
*y = box->y1;
if (w)
*w = box->x2 - box->x1;
if (h)
*h = box->y2 - box->y1;
pixman_region32_fini(&region);
}
static void static void
fs_output_center_view(struct fs_output *fsout) fs_output_center_view(struct fs_output *fsout)
{ {
@@ -520,10 +475,10 @@ fs_output_configure_simple(struct fs_output *fsout,
break; break;
} }
weston_view_set_position(fsout->black_view, weston_view_set_position(fsout->curtain->view,
fsout->output->x - surf_x, fsout->output->x - surf_x,
fsout->output->y - surf_y); fsout->output->y - surf_y);
weston_surface_set_size(fsout->black_view->surface, weston_surface_set_size(fsout->curtain->view->surface,
fsout->output->width, fsout->output->width,
fsout->output->height); fsout->output->height);
} }
@@ -670,6 +625,7 @@ fs_output_apply_pending(struct fs_output *fsout)
return; return;
} }
fsout->view->is_mapped = true; fsout->view->is_mapped = true;
fsout->surface->is_mapped = true;
wl_signal_add(&fsout->surface->destroy_signal, wl_signal_add(&fsout->surface->destroy_signal,
&fsout->surface_destroyed); &fsout->surface_destroyed);
+2 -1
View File
@@ -4,9 +4,10 @@ if get_option('shell-fullscreen')
fullscreen_shell_unstable_v1_server_protocol_h, fullscreen_shell_unstable_v1_server_protocol_h,
fullscreen_shell_unstable_v1_protocol_c, fullscreen_shell_unstable_v1_protocol_c,
] ]
deps_shell_fullscreen=[ deps_shell_fullscreen = [
dep_libweston_public, dep_libweston_public,
dep_libexec_weston, dep_libexec_weston,
dep_shell_utils,
] ]
shared_library( shared_library(
'fullscreen-shell', 'fullscreen-shell',
@@ -44,6 +44,14 @@ enum weston_desktop_surface_edge {
WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_RIGHT = 10, WESTON_DESKTOP_SURFACE_EDGE_BOTTOM_RIGHT = 10,
}; };
enum weston_top_level_tiled_orientation {
WESTON_TOP_LEVEL_TILED_ORIENTATION_NONE = 0 << 0,
WESTON_TOP_LEVEL_TILED_ORIENTATION_LEFT = 1 << 1,
WESTON_TOP_LEVEL_TILED_ORIENTATION_RIGHT = 1 << 2,
WESTON_TOP_LEVEL_TILED_ORIENTATION_TOP = 1 << 3,
WESTON_TOP_LEVEL_TILED_ORIENTATION_BOTTOM = 1 << 4,
};
struct weston_desktop; struct weston_desktop;
struct weston_desktop_client; struct weston_desktop_client;
struct weston_desktop_surface; struct weston_desktop_surface;
@@ -113,6 +121,9 @@ struct weston_desktop_api {
*/ */
void (*set_xwayland_position)(struct weston_desktop_surface *surface, void (*set_xwayland_position)(struct weston_desktop_surface *surface,
int32_t x, int32_t y, void *user_data); int32_t x, int32_t y, void *user_data);
void (*get_position)(struct weston_desktop_surface *surface,
int32_t *x, int32_t *y,
void *user_data);
}; };
void void
@@ -163,6 +174,9 @@ void
weston_desktop_surface_set_size(struct weston_desktop_surface *surface, weston_desktop_surface_set_size(struct weston_desktop_surface *surface,
int32_t width, int32_t height); int32_t width, int32_t height);
void void
weston_desktop_surface_set_orientation(struct weston_desktop_surface *surface,
enum weston_top_level_tiled_orientation tile_orientation);
void
weston_desktop_surface_close(struct weston_desktop_surface *surface); weston_desktop_surface_close(struct weston_desktop_surface *surface);
void void
weston_desktop_surface_add_metadata_listener(struct weston_desktop_surface *surface, weston_desktop_surface_add_metadata_listener(struct weston_desktop_surface *surface,
@@ -195,6 +209,19 @@ weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface);
struct weston_size struct weston_size
weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface); weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface);
bool
weston_desktop_window_menu_supported(struct weston_desktop *desktop);
bool
weston_desktop_move_supported(struct weston_desktop *desktop);
bool
weston_desktop_resize_supported(struct weston_desktop *desktop);
bool
weston_desktop_fullscreen_supported(struct weston_desktop *desktop);
bool
weston_desktop_minimize_supported(struct weston_desktop *desktop);
bool
weston_desktop_maximize_supported(struct weston_desktop *desktop);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
+23 -7
View File
@@ -35,7 +35,7 @@
extern "C" { extern "C" {
#endif #endif
#define WESTON_DRM_BACKEND_CONFIG_VERSION 4 #define WESTON_DRM_BACKEND_CONFIG_VERSION 5
struct libinput_device; struct libinput_device;
@@ -78,6 +78,21 @@ struct weston_drm_output_api {
*/ */
void (*set_seat)(struct weston_output *output, void (*set_seat)(struct weston_output *output,
const char *seat); const char *seat);
/** Set the "max bpc" KMS connector property
*
* The property is used for working around faulty sink hardware like
* monitors or media converters that mishandle the kernel driver
* chosen bits-per-channel on the physical link. When having trouble,
* try a lower value like 8. A value of 0 means that the current max
* bpc will be reprogrammed.
*
* The value actually used in KMS is silently clamped to the range the
* KMS driver claims to support. The default value is 16.
*
* This can be set only while the output is disabled.
*/
void (*set_max_bpc)(struct weston_output *output, unsigned max_bpc);
}; };
static inline const struct weston_drm_output_api * static inline const struct weston_drm_output_api *
@@ -90,7 +105,7 @@ weston_drm_output_get_api(struct weston_compositor *compositor)
return (const struct weston_drm_output_api *)api; return (const struct weston_drm_output_api *)api;
} }
#define WESTON_DRM_VIRTUAL_OUTPUT_API_NAME "weston_drm_virtual_output_api_v1" #define WESTON_DRM_VIRTUAL_OUTPUT_API_NAME "weston_drm_virtual_output_api_v2"
struct drm_fb; struct drm_fb;
typedef int (*submit_frame_cb)(struct weston_output *output, int fd, typedef int (*submit_frame_cb)(struct weston_output *output, int fd,
@@ -101,12 +116,16 @@ struct weston_drm_virtual_output_api {
* This is a low-level function, where the caller is expected to wrap * This is a low-level function, where the caller is expected to wrap
* the weston_output function pointers as necessary to make the virtual * the weston_output function pointers as necessary to make the virtual
* output useful. The caller must set up output make, model, serial, * output useful. The caller must set up output make, model, serial,
* physical size, the mode list and current mode. * physical size, the mode list and current mode. The destroy function
* pointer must not be overwritten, as it is used by the DRM backend to
* recognize its outputs. Instead, an auxiliary destroy callback has to
* be provided as a parameter.
* *
* Returns output on success, NULL on failure. * Returns output on success, NULL on failure.
*/ */
struct weston_output* (*create_output)(struct weston_compositor *c, struct weston_output* (*create_output)(struct weston_compositor *c,
char *name); char *name,
void (*destroy_func)(struct weston_output *base));
/** Set pixel format same as drm_output set_gbm_format(). /** Set pixel format same as drm_output set_gbm_format().
* *
@@ -171,9 +190,6 @@ weston_drm_virtual_output_get_api(struct weston_compositor *compositor)
struct weston_drm_backend_config { struct weston_drm_backend_config {
struct weston_backend_config base; struct weston_backend_config base;
/** The tty to be used. Set to 0 to use the current tty. */
int tty;
/** Whether to use the pixman renderer instead of the OpenGL ES renderer. */ /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
bool use_pixman; bool use_pixman;
-70
View File
@@ -1,70 +0,0 @@
/*
* Copyright © 2016 Benoit Gschwind
*
* 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.
*/
#ifndef WESTON_COMPOSITOR_FBDEV_H
#define WESTON_COMPOSITOR_FBDEV_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <libweston/libweston.h>
#define WESTON_FBDEV_BACKEND_CONFIG_VERSION 2
struct libinput_device;
struct weston_fbdev_backend_config {
struct weston_backend_config base;
int tty;
char *device;
/** Callback used to configure input devices.
*
* This function will be called by the backend when a new input device
* needs to be configured.
* If NULL the device will use the default configuration.
*/
void (*configure_device)(struct weston_compositor *compositor,
struct libinput_device *device);
/** The seat to be used for input and output.
*
* If seat_id is NULL, the seat is taken from XDG_SEAT environment
* variable. If neither is set, "seat0" is used. The backend will
* take ownership of the seat_id pointer and will free it on
* backend destruction.
*/
char *seat_id;
};
#ifdef __cplusplus
}
#endif
#endif /* WESTON_COMPOSITOR_FBDEV_H */
+13
View File
@@ -34,6 +34,7 @@ extern "C" {
#include <libweston/plugin-registry.h> #include <libweston/plugin-registry.h>
#define WESTON_RDP_OUTPUT_API_NAME "weston_rdp_output_api_v1" #define WESTON_RDP_OUTPUT_API_NAME "weston_rdp_output_api_v1"
#define RDP_DEFAULT_FREQ 60
struct weston_rdp_output_api { struct weston_rdp_output_api {
/** Initialize a RDP output with specified width and height. /** Initialize a RDP output with specified width and height.
@@ -56,6 +57,11 @@ weston_rdp_output_get_api(struct weston_compositor *compositor)
#define WESTON_RDP_BACKEND_CONFIG_VERSION 2 #define WESTON_RDP_BACKEND_CONFIG_VERSION 2
typedef void *(*rdp_audio_in_setup)(struct weston_compositor *c, void *vcm);
typedef void (*rdp_audio_in_teardown)(void *audio_private);
typedef void *(*rdp_audio_out_setup)(struct weston_compositor *c, void *vcm);
typedef void (*rdp_audio_out_teardown)(void *audio_private);
struct weston_rdp_backend_config { struct weston_rdp_backend_config {
struct weston_backend_config base; struct weston_backend_config base;
char *bind_address; char *bind_address;
@@ -66,6 +72,13 @@ struct weston_rdp_backend_config {
int env_socket; int env_socket;
int no_clients_resize; int no_clients_resize;
int force_no_compression; int force_no_compression;
bool remotefx_codec;
int external_listener_fd;
int refresh_rate;
rdp_audio_in_setup audio_in_setup;
rdp_audio_in_teardown audio_in_teardown;
rdp_audio_out_setup audio_out_setup;
rdp_audio_out_teardown audio_out_teardown;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+3 -22
View File
@@ -35,26 +35,6 @@ extern "C" {
#define WESTON_CONFIG_FILE_ENV_VAR "WESTON_CONFIG_FILE" #define WESTON_CONFIG_FILE_ENV_VAR "WESTON_CONFIG_FILE"
enum config_key_type {
CONFIG_KEY_INTEGER, /* typeof data = int */
CONFIG_KEY_UNSIGNED_INTEGER, /* typeof data = unsigned int */
CONFIG_KEY_STRING, /* typeof data = char* */
CONFIG_KEY_BOOLEAN /* typeof data = int */
};
struct config_key {
const char *name;
enum config_key_type type;
void *data;
};
struct config_section {
const char *name;
const struct config_key *keys;
int num_keys;
void (*done)(void *data);
};
enum weston_option_type { enum weston_option_type {
WESTON_OPTION_INTEGER, WESTON_OPTION_INTEGER,
WESTON_OPTION_UNSIGNED_INTEGER, WESTON_OPTION_UNSIGNED_INTEGER,
@@ -108,6 +88,9 @@ weston_config_section_get_bool(struct weston_config_section *section,
const char * const char *
weston_config_get_name_from_env(void); weston_config_get_name_from_env(void);
struct weston_config *
weston_config_parse_fp(FILE *file);
struct weston_config * struct weston_config *
weston_config_parse(const char *name); weston_config_parse(const char *name);
@@ -121,10 +104,8 @@ int weston_config_next_section(struct weston_config *config,
struct weston_config_section **section, struct weston_config_section **section,
const char **name); const char **name);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* CONFIGPARSER_H */ #endif /* CONFIGPARSER_H */
+264 -75
View File
@@ -81,6 +81,7 @@ struct weston_pointer_constraint;
struct ro_anonymous_file; struct ro_anonymous_file;
struct weston_color_profile; struct weston_color_profile;
struct weston_color_transform; struct weston_color_transform;
struct pixel_format_info;
enum weston_keyboard_modifier { enum weston_keyboard_modifier {
MODIFIER_CTRL = (1 << 0), MODIFIER_CTRL = (1 << 0),
@@ -150,21 +151,6 @@ struct weston_spring {
uint32_t clip; uint32_t clip;
}; };
struct weston_output_zoom {
bool active;
float increment;
float level;
float max_level;
float trans_x, trans_y;
struct {
double x, y;
} current;
struct weston_seat *seat;
struct weston_animation animation_z;
struct weston_spring spring_z;
struct wl_listener motion_listener;
};
/* bit compatible with drm definitions. */ /* bit compatible with drm definitions. */
enum dpms_enum { enum dpms_enum {
WESTON_DPMS_ON, WESTON_DPMS_ON,
@@ -222,6 +208,154 @@ struct weston_testsuite_data {
void *test_private_data; void *test_private_data;
}; };
/** 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))
/** CIE 1931 xy chromaticity coordinates */
struct weston_CIExy {
float x;
float y;
};
enum weston_hdr_metadata_type1_groups {
/** weston_hdr_metadata_type1::primary is set */
WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES = 0x01,
/** weston_hdr_metadata_type1::white is set */
WESTON_HDR_METADATA_TYPE1_GROUP_WHITE = 0x02,
/** weston_hdr_metadata_type1::maxDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML = 0x04,
/** weston_hdr_metadata_type1::minDML is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MINDML = 0x08,
/** weston_hdr_metadata_type1::maxCLL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL = 0x10,
/** weston_hdr_metadata_type1::maxFALL is set */
WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL = 0x20,
/** all valid bits */
WESTON_HDR_METADATA_TYPE1_GROUP_ALL_MASK = 0x3f
};
/** HDR static metadata type 1
*
* The fields are defined by CTA-861-G except here they use float encoding.
*
* In Weston used only with HDR display modes.
*/
struct weston_hdr_metadata_type1 {
/** Which fields are valid
*
* A bitmask of values from enum weston_hdr_metadata_type1_groups.
*/
uint32_t group_mask;
/* EOTF is tracked externally with enum weston_eotf_mode */
/** Chromaticities of the primaries, in any order */
struct weston_CIExy primary[3];
/** White point chromaticity */
struct weston_CIExy white;
/** Maximum display mastering luminance, 1 - 65535 cd/m² */
float maxDML;
/** Minimum display mastering luminance, 0.0001 - 6.5535 cd/m² */
float minDML;
/** Maximum content light level, 1 - 65535 cd/m² */
float maxCLL;
/** Maximum frame-average light level, 1 - 65535 cd/m² */
float maxFALL;
};
enum weston_color_characteristics_groups {
/** weston_color_characteristics::primary is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES = 0x01,
/** weston_color_characteristics::white is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE = 0x02,
/** weston_color_characteristics::max_luminance is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL = 0x04,
/** weston_color_characteristics::min_luminance is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MINL = 0x08,
/** weston_color_characteristics::maxFALL is set */
WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL = 0x10,
/** all valid bits */
WESTON_COLOR_CHARACTERISTICS_GROUP_ALL_MASK = 0x1f
};
/** Basic display color characteristics
*
* This is a simple description of a display or output (monitor) color
* characteristics. The parameters can be found in EDID, with caveats. They
* are particularly useful with HDR monitors.
*/
struct weston_color_characteristics {
/** Which fields are valid
*
* A bitmask of values from enum weston_color_characteristics_groups.
*/
uint32_t group_mask;
/* EOTF is tracked externally with enum weston_eotf_mode */
/** Chromaticities of the primaries */
struct weston_CIExy primary[3];
/** White point chromaticity */
struct weston_CIExy white;
/** Display's desired maximum content peak luminance, cd/m² */
float max_luminance;
/** Display's desired minimum content luminance, cd/m² */
float min_luminance;
/** Display's desired maximum frame-average light level, cd/m² */
float maxFALL;
};
/** Represents a head, usually a display connector /** Represents a head, usually a display connector
* *
* \rst * \rst
@@ -258,9 +392,36 @@ struct weston_head {
char *name; /**< head name, e.g. connector name */ char *name; /**< head name, e.g. connector name */
bool connected; /**< is physically connected */ bool connected; /**< is physically connected */
bool non_desktop; /**< non-desktop display, e.g. HMD */ bool non_desktop; /**< non-desktop display, e.g. HMD */
uint32_t supported_eotf_mask; /**< supported weston_eotf_mode bits */
/** Current content protection status */ /** Current content protection status */
enum weston_hdcp_protection current_protection; enum weston_hdcp_protection current_protection;
/** Opaque pointer used by backends to identify heads as theirs */
const void *backend_id;
};
/** Output properties derived from its color characteristics and profile
*
* These are constructed by a color manager.
*
* A weston_output_color_outcome owns (a reference to) everything it contains.
*
* \ingroup output
* \internal
*/
struct weston_output_color_outcome {
/** sRGB to output color space transformation */
struct weston_color_transform *from_sRGB_to_output;
/** sRGB to blending color space transformation */
struct weston_color_transform *from_sRGB_to_blend;
/** Blending to output color space transformation */
struct weston_color_transform *from_blend_to_output;
/** HDR Static Metadata Type 1 for WESTON_EOTF_MODE_ST2084 */
struct weston_hdr_metadata_type1 hdr_meta;
}; };
/** Content producer for heads /** Content producer for heads
@@ -324,7 +485,6 @@ struct weston_output {
/** For cancelling the idle_repaint callback on output destruction. */ /** For cancelling the idle_repaint callback on output destruction. */
struct wl_event_source *idle_repaint_source; struct wl_event_source *idle_repaint_source;
struct weston_output_zoom zoom;
int dirty; int dirty;
struct wl_signal frame_signal; struct wl_signal frame_signal;
struct wl_signal destroy_signal; /**< sent when disabled */ struct wl_signal destroy_signal; /**< sent when disabled */
@@ -352,11 +512,9 @@ struct weston_output {
bool allow_protection; bool allow_protection;
int (*start_repaint_loop)(struct weston_output *output); int (*start_repaint_loop)(struct weston_output *output);
int (*repaint)(struct weston_output *output, int (*repaint)(struct weston_output *output, pixman_region32_t *damage);
pixman_region32_t *damage,
void *repaint_data);
void (*destroy)(struct weston_output *output); void (*destroy)(struct weston_output *output);
void (*assign_planes)(struct weston_output *output, void *repaint_data); void (*assign_planes)(struct weston_output *output);
int (*switch_mode)(struct weston_output *output, struct weston_mode *mode); int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);
/* backlight values are on 0-255 range, where higher is brighter */ /* backlight values are on 0-255 range, where higher is brighter */
@@ -375,10 +533,12 @@ struct weston_output {
int scale; int scale;
struct weston_color_profile *color_profile; struct weston_color_profile *color_profile;
struct weston_color_transform *from_sRGB_to_output;
struct weston_color_transform *from_sRGB_to_blend;
struct weston_color_transform *from_blend_to_output;
bool from_blend_to_output_by_backend; bool from_blend_to_output_by_backend;
enum weston_eotf_mode eotf_mode;
struct weston_color_characteristics color_characteristics;
struct weston_output_color_outcome *color_outcome;
uint64_t color_outcome_serial;
int (*enable)(struct weston_output *output); int (*enable)(struct weston_output *output);
int (*disable)(struct weston_output *output); int (*disable)(struct weston_output *output);
@@ -937,39 +1097,6 @@ struct weston_plane {
struct weston_drm_format_array; struct weston_drm_format_array;
struct weston_renderer {
int (*read_pixels)(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface);
void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
void (*surface_set_color)(struct weston_surface *surface,
float red, float green,
float blue, float alpha);
void (*destroy)(struct weston_compositor *ec);
/** See weston_surface_get_content_size() */
void (*surface_get_content_size)(struct weston_surface *surface,
int *width, int *height);
/** See weston_surface_copy_content() */
int (*surface_copy_content)(struct weston_surface *surface,
void *target, size_t size,
int src_x, int src_y,
int width, int height);
/** See weston_compositor_import_dmabuf() */
bool (*import_dmabuf)(struct weston_compositor *ec,
struct linux_dmabuf_buffer *buffer);
const struct weston_drm_format_array *
(*get_supported_formats)(struct weston_compositor *ec);
};
enum weston_capability { enum weston_capability {
/* backend/renderer supports arbitrary rotation */ /* backend/renderer supports arbitrary rotation */
WESTON_CAP_ROTATION_ANY = 0x0001, WESTON_CAP_ROTATION_ANY = 0x0001,
@@ -1126,7 +1253,7 @@ struct weston_compositor {
struct weston_color_manager *color_manager; struct weston_color_manager *color_manager;
struct weston_renderer *renderer; struct weston_renderer *renderer;
pixman_format_code_t read_format; const struct pixel_format_info *read_format;
struct weston_backend *backend; struct weston_backend *backend;
struct weston_launcher *launcher; struct weston_launcher *launcher;
@@ -1137,6 +1264,7 @@ struct weston_compositor {
struct wl_list plugin_api_list; /* struct weston_plugin_api::link */ struct wl_list plugin_api_list; /* struct weston_plugin_api::link */
uint32_t output_id_pool; uint32_t output_id_pool;
bool output_flow_dirty;
struct xkb_rule_names xkb_names; struct xkb_rule_names xkb_names;
struct xkb_context *xkb_context; struct xkb_context *xkb_context;
@@ -1182,8 +1310,17 @@ struct weston_compositor {
struct weston_log_context *weston_log_ctx; struct weston_log_context *weston_log_ctx;
struct weston_log_scope *debug_scene; struct weston_log_scope *debug_scene;
struct weston_log_scope *timeline; struct weston_log_scope *timeline;
struct weston_log_scope *libseat_debug;
struct content_protection *content_protection; struct content_protection *content_protection;
/* One-time warning about a view appearing in the layer list when it
* or its surface are not mapped. */
bool warned_about_unmapped_surface_or_view;
};
struct weston_solid_buffer_values {
float r, g, b, a;
}; };
struct weston_buffer { struct weston_buffer {
@@ -1191,19 +1328,45 @@ struct weston_buffer {
struct wl_signal destroy_signal; struct wl_signal destroy_signal;
struct wl_listener destroy_listener; struct wl_listener destroy_listener;
enum {
WESTON_BUFFER_SHM,
WESTON_BUFFER_DMABUF,
WESTON_BUFFER_RENDERER_OPAQUE,
WESTON_BUFFER_SOLID,
} type;
union { union {
struct wl_shm_buffer *shm_buffer; struct wl_shm_buffer *shm_buffer;
void *dmabuf;
void *legacy_buffer; void *legacy_buffer;
struct weston_solid_buffer_values solid;
}; };
int32_t width, height; int32_t width, height;
uint32_t busy_count; uint32_t busy_count;
int y_inverted; uint32_t passive_count;
enum {
ORIGIN_TOP_LEFT, /* buffer content starts at (0,0) */
ORIGIN_BOTTOM_LEFT, /* buffer content starts at (0, height) */
} buffer_origin;
bool direct_display;
void *renderer_private;
void *backend_private; void *backend_private;
const struct pixel_format_info *pixel_format;
uint64_t format_modifier;
};
enum weston_buffer_reference_type {
BUFFER_REF_NONE,
BUFFER_MAY_BE_ACCESSED,
BUFFER_WILL_NOT_BE_ACCESSED,
}; };
struct weston_buffer_reference { struct weston_buffer_reference {
struct weston_buffer *buffer; struct weston_buffer *buffer;
struct wl_listener destroy_listener; enum weston_buffer_reference_type type;
}; };
struct weston_buffer_viewport { struct weston_buffer_viewport {
@@ -1377,6 +1540,7 @@ struct weston_surface_state {
int newly_attached; int newly_attached;
struct weston_buffer *buffer; struct weston_buffer *buffer;
struct wl_listener buffer_destroy_listener; struct wl_listener buffer_destroy_listener;
int32_t sx; int32_t sx;
int32_t sy; int32_t sy;
@@ -1762,6 +1926,21 @@ weston_surface_create(struct weston_compositor *compositor);
struct weston_view * struct weston_view *
weston_view_create(struct weston_surface *surface); weston_view_create(struct weston_surface *surface);
struct weston_buffer_reference *
weston_buffer_create_solid_rgba(struct weston_compositor *compositor,
float r, float g, float b, float a);
void
weston_surface_attach_solid(struct weston_surface *surface,
struct weston_buffer_reference *buffer_ref,
int w, int h);
void
weston_buffer_destroy_solid(struct weston_buffer_reference *buffer_ref);
bool
weston_surface_has_content(struct weston_surface *surface);
void void
weston_view_destroy(struct weston_view *view); weston_view_destroy(struct weston_view *view);
@@ -1802,6 +1981,9 @@ weston_view_damage_below(struct weston_view *view);
void void
weston_view_unmap(struct weston_view *view); weston_view_unmap(struct weston_view *view);
void
weston_surface_map(struct weston_surface *surface);
void void
weston_surface_unmap(struct weston_surface *surface); weston_surface_unmap(struct weston_surface *surface);
@@ -1835,7 +2017,8 @@ weston_surface_copy_content(struct weston_surface *surface,
int width, int height); int width, int height);
struct weston_buffer * struct weston_buffer *
weston_buffer_from_resource(struct wl_resource *resource); weston_buffer_from_resource(struct weston_compositor *ec,
struct wl_resource *resource);
void void
weston_compositor_get_time(struct timespec *time); weston_compositor_get_time(struct timespec *time);
@@ -1858,7 +2041,6 @@ weston_compositor_add_destroy_listener_once(struct weston_compositor *compositor
enum weston_compositor_backend { enum weston_compositor_backend {
WESTON_BACKEND_DRM, WESTON_BACKEND_DRM,
WESTON_BACKEND_FBDEV,
WESTON_BACKEND_HEADLESS, WESTON_BACKEND_HEADLESS,
WESTON_BACKEND_RDP, WESTON_BACKEND_RDP,
WESTON_BACKEND_WAYLAND, WESTON_BACKEND_WAYLAND,
@@ -1877,11 +2059,6 @@ void
weston_compositor_exit_with_code(struct weston_compositor *compositor, weston_compositor_exit_with_code(struct weston_compositor *compositor,
int exit_code); int exit_code);
void void
weston_output_update_zoom(struct weston_output *output);
void
weston_output_activate_zoom(struct weston_output *output,
struct weston_seat *seat);
void
weston_output_add_destroy_listener(struct weston_output *output, weston_output_add_destroy_listener(struct weston_output *output,
struct wl_listener *listener); struct wl_listener *listener);
struct wl_listener * struct wl_listener *
@@ -1960,12 +2137,11 @@ struct weston_view_animation *
weston_slide_run(struct weston_view *view, float start, float stop, weston_slide_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data); weston_view_animation_done_func_t done, void *data);
void struct weston_surface *
weston_surface_set_color(struct weston_surface *surface, weston_surface_ref(struct weston_surface *surface);
float red, float green, float blue, float alpha);
void void
weston_surface_destroy(struct weston_surface *surface); weston_surface_unref(struct weston_surface *surface);
int int
weston_output_mode_switch_to_temporary(struct weston_output *output, weston_output_mode_switch_to_temporary(struct weston_output *output,
@@ -2068,11 +2244,7 @@ weston_compositor_find_output_by_name(struct weston_compositor *compositor,
struct weston_output * struct weston_output *
weston_compositor_create_output(struct weston_compositor *compositor, weston_compositor_create_output(struct weston_compositor *compositor,
const char *name); struct weston_head *head, const char *name);
struct weston_output *
weston_compositor_create_output_with_head(struct weston_compositor *compositor,
struct weston_head *head);
void void
weston_output_destroy(struct weston_output *output); weston_output_destroy(struct weston_output *output);
@@ -2097,6 +2269,20 @@ bool
weston_output_set_color_profile(struct weston_output *output, weston_output_set_color_profile(struct weston_output *output,
struct weston_color_profile *cprof); struct weston_color_profile *cprof);
void
weston_output_set_eotf_mode(struct weston_output *output,
enum weston_eotf_mode eotf_mode);
enum weston_eotf_mode
weston_output_get_eotf_mode(const struct weston_output *output);
void
weston_output_set_color_characteristics(struct weston_output *output,
const struct weston_color_characteristics *cc);
const struct weston_color_characteristics *
weston_output_get_color_characteristics(struct weston_output *output);
void void
weston_output_init(struct weston_output *output, weston_output_init(struct weston_output *output,
struct weston_compositor *compositor, struct weston_compositor *compositor,
@@ -2111,6 +2297,9 @@ weston_output_enable(struct weston_output *output);
void void
weston_output_disable(struct weston_output *output); weston_output_disable(struct weston_output *output);
uint32_t
weston_output_get_supported_eotf_modes(struct weston_output *output);
void void
weston_compositor_flush_heads_changed(struct weston_compositor *compositor); weston_compositor_flush_heads_changed(struct weston_compositor *compositor);
-13
View File
@@ -65,19 +65,6 @@ int
weston_matrix_invert(struct weston_matrix *inverse, weston_matrix_invert(struct weston_matrix *inverse,
const struct weston_matrix *matrix); const struct weston_matrix *matrix);
#ifdef UNIT_TEST
# define MATRIX_TEST_EXPORT WL_EXPORT
int
matrix_invert(double *A, unsigned *p, const struct weston_matrix *matrix);
void
inverse_transform(const double *LU, const unsigned *p, float *v);
#else
# define MATRIX_TEST_EXPORT static
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
-1
View File
@@ -12,7 +12,6 @@ install_headers(
) )
backend_drm_h = files('backend-drm.h') backend_drm_h = files('backend-drm.h')
backend_fbdev_h = files('backend-fbdev.h')
backend_headless_h = files('backend-headless.h') backend_headless_h = files('backend-headless.h')
backend_rdp_h = files('backend-rdp.h') backend_rdp_h = files('backend-rdp.h')
backend_wayland_h = files('backend-wayland.h') backend_wayland_h = files('backend-wayland.h')
+2
View File
@@ -109,6 +109,8 @@ weston_log_subscription_complete(struct weston_log_subscription *sub);
char * char *
weston_log_scope_timestamp(struct weston_log_scope *scope, weston_log_scope_timestamp(struct weston_log_scope *scope,
char *buf, size_t len); char *buf, size_t len);
char *
weston_log_timestamp(char *buf, size_t len, int *cached_tm_mday);
void void
weston_log_subscriber_destroy(struct weston_log_subscriber *subscriber); weston_log_subscriber_destroy(struct weston_log_subscriber *subscriber);
-78
View File
@@ -1,78 +0,0 @@
In-vehicle infotainment (information and entertainment)
graphical environment support modules for Weston
IVI-shell is an alternative shell for Weston, a Wayland display server.
Window management and application interaction with the display server
are very different to that of a normal desktop, which is why this is
a separate shell and not an extension to the desktop-shell suite with
xdg_shell. As such, applications need to be specifically written to use
IVI-shell.
IVI-shell contains two main features:
- Common layout library for surface, which allow ivi-shell developer
to develop own shell, linking Common layout library.
For the time being, the library refers Genivi ilm interface.
https://at.projects.genivi.org/wiki/display/WIE/Wayland+IVI+Extension+Home
- Extension protocol; ivi-application to tie wl_surface and a given ID.
With this ID, shell can identify which wl_surface is drawn by which
application. In in-vehicle infortainment system, a shell has to update
a property of a wl_surface. E.g. there may be a use case when vehicle
starts to move, the wl_surface drawn by Car navigation is expected to
move top of surfaces.
The actual software components delivered with Weston are:
- ivi-application.xml:
Wayland protocol extension for IVI-applications; the public
shell protocol (the same concept as xdg_shell).
Implemented by ivi-shell.so.
- ivi-shell.so:
A Weston shell module that implements ivi-application.xml interfaces.
Loads ivi-layout.so.
- ivi-layout.so:
Implements the IVI window management concepts: Screen, Layer,
Surface, groups of Layers, groups of Surfaces, see:
https://at.projects.genivi.org/wiki/display/WIE/Summary+of+Layer+manager+APIs
Offers a stable API for writing IVI-controller modules like
hmi-controller.so against the IVI concepts. In other words,
it offers an API to write IVI window manager modules.
- hmi-controller.so:
A sample implementation of an IVI-controller module, usually
replaced by IVI system vendors.
Uses ivi-layout.so to perform essentially window manager tasks.
This implementation keeps all window management inside the module,
while IVI-systems may use another module that exposes all window
management via Wayland or other protocol for an external process
to control.
- ivi-hmi-controller.xml:
Wayland protocol extension for IVI display control; the private
shell protocol for weston-ivi-shell-user-interface client
(the same concept as desktop-shell.xml).
Implemented by hmi-controller.so, and usually replaced by IVI
system vendors.
- weston-ivi-shell-user-interface:
A sample implementation of an IVI shell helper client, usually
replaced by IVI system vendors.
A helper client for basic display content, similar to
weston-desktop-shell.
How to compile:
same as weston. To disable, use option: --disable-ivi-shell for configure.
How to configure weston.ini:
reference ini file will be generated in <build_dir>/ivi-shell.
How to run:
same as weston. exec weston.
How to use UI:
http://lists.freedesktop.org/archives/wayland-devel/attachments/20140625/abbfc064/attachment-0001.png
+16 -21
View File
@@ -153,13 +153,6 @@ struct launcher_info {
/***************************************************************************** /*****************************************************************************
* local functions * local functions
****************************************************************************/ ****************************************************************************/
static void *
mem_alloc(size_t size, char *file, int32_t line)
{
return fail_on_null(calloc(1, size), size, file, line);
}
#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
static int32_t static int32_t
is_surf_in_ui_widget(struct hmi_controller *hmi_ctrl, is_surf_in_ui_widget(struct hmi_controller *hmi_ctrl,
@@ -222,8 +215,8 @@ mode_divided_into_tiling(struct hmi_controller *hmi_ctrl,
int32_t surf_num = 0; int32_t surf_num = 0;
int32_t idx = 0; int32_t idx = 0;
surfaces = MEM_ALLOC(sizeof(*surfaces) * surface_length); surfaces = xcalloc(surface_length, sizeof(*surfaces));
new_order = MEM_ALLOC(sizeof(*surfaces) * surface_length); new_order = xcalloc(surface_length, sizeof(*surfaces));
for (i = 0; i < surface_length; i++) { for (i = 0; i < surface_length; i++) {
ivisurf = pp_surface[i]; ivisurf = pp_surface[i];
@@ -297,8 +290,8 @@ mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl,
int32_t surf_num = 0; int32_t surf_num = 0;
int32_t idx = 0; int32_t idx = 0;
surfaces = MEM_ALLOC(sizeof(*surfaces) * surface_length); surfaces = xcalloc(surface_length, sizeof(*surfaces));
new_order = MEM_ALLOC(sizeof(*surfaces) * surface_length); new_order = xcalloc(surface_length, sizeof(*surfaces));
for (i = 0; i < surface_length; i++) { for (i = 0; i < surface_length; i++) {
ivisurf = pp_surface[i]; ivisurf = pp_surface[i];
@@ -362,7 +355,7 @@ mode_fullscreen_someone(struct hmi_controller *hmi_ctrl,
int32_t surf_num = 0; int32_t surf_num = 0;
struct ivi_layout_surface **surfaces; struct ivi_layout_surface **surfaces;
surfaces = MEM_ALLOC(sizeof(*surfaces) * surface_length); surfaces = xcalloc(surface_length, sizeof(*surfaces));
for (i = 0; i < surface_length; i++) { for (i = 0; i < surface_length; i++) {
ivisurf = pp_surface[i]; ivisurf = pp_surface[i];
@@ -412,7 +405,7 @@ mode_random_replace(struct hmi_controller *hmi_ctrl,
int32_t i = 0; int32_t i = 0;
int32_t layer_idx = 0; int32_t layer_idx = 0;
layers = MEM_ALLOC(sizeof(*layers) * hmi_ctrl->screen_num); layers = xcalloc(hmi_ctrl->screen_num, sizeof(*layers));
wl_list_for_each(application_layer, layer_list, link) { wl_list_for_each(application_layer, layer_list, link) {
layers[layer_idx] = application_layer; layers[layer_idx] = application_layer;
@@ -689,7 +682,7 @@ set_notification_configure_desktop_surface(struct wl_listener *listener, void *d
static struct hmi_server_setting * static struct hmi_server_setting *
hmi_server_setting_create(struct weston_compositor *ec) hmi_server_setting_create(struct weston_compositor *ec)
{ {
struct hmi_server_setting *setting = MEM_ALLOC(sizeof(*setting)); struct hmi_server_setting *setting = xzalloc(sizeof(*setting));
struct weston_config *config = wet_get_config(ec); struct weston_config *config = wet_get_config(ec);
struct weston_config_section *shell_section = NULL; struct weston_config_section *shell_section = NULL;
char *ivi_ui_config; char *ivi_ui_config;
@@ -745,6 +738,8 @@ hmi_controller_destroy(struct wl_listener *listener, void *data)
struct hmi_controller *hmi_ctrl = struct hmi_controller *hmi_ctrl =
container_of(listener, struct hmi_controller, destroy_listener); container_of(listener, struct hmi_controller, destroy_listener);
wl_list_remove(&hmi_ctrl->destroy_listener.link);
wl_list_for_each_safe(link, next, wl_list_for_each_safe(link, next,
&hmi_ctrl->workspace_fade.layer_list, link) { &hmi_ctrl->workspace_fade.layer_list, link) {
wl_list_remove(&link->link); wl_list_remove(&link->link);
@@ -804,7 +799,7 @@ hmi_controller_create(struct weston_compositor *ec)
return NULL; return NULL;
} }
hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl)); hmi_ctrl = xzalloc(sizeof(*hmi_ctrl));
i = 0; i = 0;
wl_array_init(&hmi_ctrl->ui_widgets); wl_array_init(&hmi_ctrl->ui_widgets);
@@ -817,7 +812,7 @@ hmi_controller_create(struct weston_compositor *ec)
/* init base ivi_layer*/ /* init base ivi_layer*/
wl_list_init(&hmi_ctrl->base_layer_list); wl_list_init(&hmi_ctrl->base_layer_list);
wl_list_for_each(output, &ec->output_list, link) { wl_list_for_each(output, &ec->output_list, link) {
base_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer)); base_layer = xzalloc(sizeof(struct hmi_controller_layer));
base_layer->x = 0; base_layer->x = 0;
base_layer->y = 0; base_layer->y = 0;
base_layer->width = output->current_mode->width; base_layer->width = output->current_mode->width;
@@ -837,7 +832,7 @@ hmi_controller_create(struct weston_compositor *ec)
/* init application ivi_layer */ /* init application ivi_layer */
wl_list_init(&hmi_ctrl->application_layer_list); wl_list_init(&hmi_ctrl->application_layer_list);
wl_list_for_each(output, &ec->output_list, link) { wl_list_for_each(output, &ec->output_list, link) {
application_layer = MEM_ALLOC(1 * sizeof(struct hmi_controller_layer)); application_layer = xzalloc(sizeof(struct hmi_controller_layer));
application_layer->x = 0; application_layer->x = 0;
application_layer->y = 0; application_layer->y = 0;
application_layer->width = output->current_mode->width; application_layer->width = output->current_mode->width;
@@ -872,7 +867,7 @@ hmi_controller_create(struct weston_compositor *ec)
wl_list_init(&hmi_ctrl->workspace_fade.layer_list); wl_list_init(&hmi_ctrl->workspace_fade.layer_list);
tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer)); tmp_link_layer = xzalloc(sizeof(*tmp_link_layer));
tmp_link_layer->layout_layer = tmp_link_layer->layout_layer =
hmi_ctrl->workspace_background_layer.ivilayer; hmi_ctrl->workspace_background_layer.ivilayer;
wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, wl_list_insert(&hmi_ctrl->workspace_fade.layer_list,
@@ -1267,7 +1262,7 @@ ivi_hmi_controller_add_launchers(struct hmi_controller *hmi_ctrl,
hmi_ctrl->interface->layer_set_visibility(hmi_ctrl->workspace_layer.ivilayer, hmi_ctrl->interface->layer_set_visibility(hmi_ctrl->workspace_layer.ivilayer,
false); false);
tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer)); tmp_link_layer = xzalloc(sizeof(*tmp_link_layer));
tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer; tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer;
wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, wl_list_insert(&hmi_ctrl->workspace_fade.layer_list,
&tmp_link_layer->link); &tmp_link_layer->link);
@@ -1756,7 +1751,7 @@ create_workspace_pointer_move(struct weston_pointer *pointer,
struct wl_resource* resource) struct wl_resource* resource)
{ {
struct pointer_move_grab *pnt_move_grab = struct pointer_move_grab *pnt_move_grab =
MEM_ALLOC(sizeof(*pnt_move_grab)); xzalloc(sizeof(*pnt_move_grab));
pnt_move_grab->base.resource = resource; pnt_move_grab->base.resource = resource;
move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x,
@@ -1770,7 +1765,7 @@ create_workspace_touch_move(struct weston_touch *touch,
struct wl_resource* resource) struct wl_resource* resource)
{ {
struct touch_move_grab *tch_move_grab = struct touch_move_grab *tch_move_grab =
MEM_ALLOC(sizeof(*tch_move_grab)); xzalloc(sizeof(*tch_move_grab));
tch_move_grab->base.resource = resource; tch_move_grab->base.resource = resource;
tch_move_grab->is_active = 1; tch_move_grab->is_active = 1;
-4
View File
@@ -43,9 +43,6 @@
* way in In-Vehicle Infotainment system, which integrate several domains * way in In-Vehicle Infotainment system, which integrate several domains
* in one system. A layer is allocated to a domain in order to control * in one system. A layer is allocated to a domain in order to control
* application surfaces grouped to the layer all together. * application surfaces grouped to the layer all together.
*
* This API and ABI follow following specifications.
* https://at.projects.genivi.org/wiki/display/PROJ/Wayland+IVI+Extension+Design
*/ */
#ifndef _IVI_LAYOUT_EXPORT_H_ #ifndef _IVI_LAYOUT_EXPORT_H_
@@ -67,7 +64,6 @@ extern "C" {
#define IVI_INVALID_ID UINT_MAX #define IVI_INVALID_ID UINT_MAX
struct ivi_layout_layer; struct ivi_layout_layer;
struct ivi_layout_screen;
struct ivi_layout_surface; struct ivi_layout_surface;
struct ivi_layout_surface_properties struct ivi_layout_surface_properties
+2 -1
View File
@@ -44,7 +44,8 @@ ivi_layout_desktop_surface_configure(struct ivi_layout_surface *ivisurf,
int32_t width, int32_t height); int32_t width, int32_t height);
struct ivi_layout_surface* struct ivi_layout_surface*
ivi_layout_desktop_surface_create(struct weston_surface *wl_surface); ivi_layout_desktop_surface_create(struct weston_surface *wl_surface,
struct weston_desktop_surface *surface);
void void
ivi_layout_surface_configure(struct ivi_layout_surface *ivisurf, ivi_layout_surface_configure(struct ivi_layout_surface *ivisurf,
+18 -9
View File
@@ -835,7 +835,7 @@ build_view_list(struct ivi_layout *layout)
weston_layer_entry_insert(&layout->layout_layer.view_list, weston_layer_entry_insert(&layout->layout_layer.view_list,
&ivi_view->view->layer_link); &ivi_view->view->layer_link);
ivi_view->ivisurf->surface->is_mapped = true; weston_surface_map(ivi_view->ivisurf->surface);
ivi_view->view->is_mapped = true; ivi_view->view->is_mapped = true;
} }
} }
@@ -1192,14 +1192,13 @@ ivi_layout_get_layers_under_surface(struct ivi_layout_surface *ivisurf,
else else
length--; length--;
} }
} if (length == 0) {
*pLength = length;
if (!length) {
free(*ppArray); free(*ppArray);
*ppArray = NULL; *ppArray = NULL;
} }
}
*pLength = length;
return IVI_SUCCEEDED; return IVI_SUCCEEDED;
} }
@@ -1882,7 +1881,6 @@ ivi_layout_surface_set_id(struct ivi_layout_surface *ivisurf,
ivisurf->id_surface = id_surface; ivisurf->id_surface = id_surface;
wl_signal_emit(&layout->surface_notification.created, ivisurf);
wl_signal_emit(&layout->surface_notification.configure_changed, wl_signal_emit(&layout->surface_notification.configure_changed,
ivisurf); ivisurf);
@@ -1979,9 +1977,20 @@ ivi_layout_desktop_surface_configure(struct ivi_layout_surface *ivisurf,
} }
struct ivi_layout_surface* struct ivi_layout_surface*
ivi_layout_desktop_surface_create(struct weston_surface *wl_surface) ivi_layout_desktop_surface_create(struct weston_surface *wl_surface,
struct weston_desktop_surface *surface)
{ {
return surface_create(wl_surface, IVI_INVALID_ID); struct ivi_layout *layout = get_instance();
struct ivi_layout_surface *ivisurf;
ivisurf = surface_create(wl_surface, IVI_INVALID_ID);
if (ivisurf) {
ivisurf->weston_desktop_surface = surface;
wl_signal_emit(&layout->surface_notification.created, ivisurf);
}
return ivisurf;
} }
void void
+10 -4
View File
@@ -346,7 +346,6 @@ shell_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&shell->destroy_listener.link); wl_list_remove(&shell->destroy_listener.link);
wl_list_remove(&shell->wake_listener.link); wl_list_remove(&shell->wake_listener.link);
weston_desktop_destroy(shell->desktop);
wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) { wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
if (ivisurf->layout_surface != NULL) if (ivisurf->layout_surface != NULL)
@@ -357,6 +356,7 @@ shell_destroy(struct wl_listener *listener, void *data)
ivi_layout_fini(); ivi_layout_fini();
weston_desktop_destroy(shell->desktop);
free(shell); free(shell);
} }
@@ -489,13 +489,11 @@ desktop_surface_added(struct weston_desktop_surface *surface,
struct weston_surface *weston_surf = struct weston_surface *weston_surf =
weston_desktop_surface_get_surface(surface); weston_desktop_surface_get_surface(surface);
layout_surface = ivi_layout_desktop_surface_create(weston_surf); layout_surface = ivi_layout_desktop_surface_create(weston_surf, surface);
if (!layout_surface) { if (!layout_surface) {
return; return;
} }
layout_surface->weston_desktop_surface = surface;
ivisurf = zalloc(sizeof *ivisurf); ivisurf = zalloc(sizeof *ivisurf);
if (!ivisurf) { if (!ivisurf) {
return; return;
@@ -509,6 +507,8 @@ desktop_surface_added(struct weston_desktop_surface *surface,
ivisurf->layout_surface = layout_surface; ivisurf->layout_surface = layout_surface;
ivisurf->surface = weston_surf; ivisurf->surface = weston_surf;
wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
weston_desktop_surface_set_user_data(surface, ivisurf); weston_desktop_surface_set_user_data(surface, ivisurf);
} }
@@ -521,8 +521,14 @@ desktop_surface_removed(struct weston_desktop_surface *surface,
assert(ivisurf != NULL); assert(ivisurf != NULL);
weston_desktop_surface_set_user_data(surface, NULL);
if (ivisurf->layout_surface) if (ivisurf->layout_surface)
layout_surface_cleanup(ivisurf); layout_surface_cleanup(ivisurf);
wl_list_remove(&ivisurf->link);
free(ivisurf);
} }
static void static void
-1
View File
@@ -15,7 +15,6 @@ if get_option('shell-ivi')
dependencies: [ dependencies: [
dep_libm, dep_libm,
dep_libexec_weston, dep_libexec_weston,
dep_lib_desktop,
dep_libweston_public dep_libweston_public
], ],
name_prefix: '', name_prefix: '',
+47 -25
View File
@@ -33,7 +33,7 @@
#include "kiosk-shell-grab.h" #include "kiosk-shell-grab.h"
#include "compositor/weston.h" #include "compositor/weston.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/shell-utils.h" #include "shell-utils.h"
#include <libweston/xwayland-api.h> #include <libweston/xwayland-api.h>
@@ -413,6 +413,7 @@ kiosk_shell_surface_activate(struct kiosk_shell_surface *shsurf,
weston_layer_entry_insert(&shsurf->shell->normal_layer.view_list, weston_layer_entry_insert(&shsurf->shell->normal_layer.view_list,
&shsurf->view->layer_link); &shsurf->view->layer_link);
weston_view_geometry_dirty(shsurf->view); weston_view_geometry_dirty(shsurf->view);
weston_view_update_transform(shsurf->view);
weston_surface_damage(shsurf->view->surface); weston_surface_damage(shsurf->view->surface);
} }
@@ -480,13 +481,14 @@ static void
kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput) kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
{ {
struct kiosk_shell *shell = shoutput->shell; struct kiosk_shell *shell = shoutput->shell;
struct weston_compositor *ec = shell->compositor;
struct weston_output *output = shoutput->output; struct weston_output *output = shoutput->output;
struct weston_config_section *shell_section = NULL; struct weston_config_section *shell_section = NULL;
uint32_t bg_color = 0x0; uint32_t bg_color = 0x0;
struct weston_solid_color_surface solid_surface = {}; struct weston_curtain_params curtain_params = {};
if (shoutput->background_view) if (shoutput->curtain)
weston_surface_destroy(shoutput->background_view->surface); weston_curtain_destroy(shoutput->curtain);
if (!output) if (!output)
return; return;
@@ -497,31 +499,33 @@ kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
weston_config_section_get_color(shell_section, "background-color", weston_config_section_get_color(shell_section, "background-color",
&bg_color, 0x00000000); &bg_color, 0x00000000);
solid_surface.r = ((bg_color >> 16) & 0xff) / 255.0; curtain_params.r = ((bg_color >> 16) & 0xff) / 255.0;
solid_surface.g = ((bg_color >> 8) & 0xff) / 255.0; curtain_params.g = ((bg_color >> 8) & 0xff) / 255.0;
solid_surface.b = ((bg_color >> 0) & 0xff) / 255.0; curtain_params.b = ((bg_color >> 0) & 0xff) / 255.0;
curtain_params.a = 1.0;
solid_surface.get_label = kiosk_shell_background_surface_get_label; curtain_params.x = output->x;
solid_surface.surface_committed = NULL; curtain_params.y = output->y;
solid_surface.surface_private = NULL; curtain_params.width = output->width;
curtain_params.height = output->height;
shoutput->background_view = curtain_params.capture_input = true;
create_solid_color_surface(shoutput->shell->compositor,
&solid_surface,
output->x, output->y,
output->width,
output->height);
weston_surface_set_role(shoutput->background_view->surface, curtain_params.get_label = kiosk_shell_background_surface_get_label;
curtain_params.surface_committed = NULL;
curtain_params.surface_private = NULL;
shoutput->curtain = weston_curtain_create(ec, &curtain_params);
weston_surface_set_role(shoutput->curtain->view->surface,
"kiosk-shell-background", NULL, 0); "kiosk-shell-background", NULL, 0);
weston_layer_entry_insert(&shell->background_layer.view_list, weston_layer_entry_insert(&shell->background_layer.view_list,
&shoutput->background_view->layer_link); &shoutput->curtain->view->layer_link);
shoutput->background_view->is_mapped = true; shoutput->curtain->view->is_mapped = true;
shoutput->background_view->surface->is_mapped = true; shoutput->curtain->view->surface->output = output;
shoutput->background_view->surface->output = output; weston_view_set_output(shoutput->curtain->view, output);
weston_view_set_output(shoutput->background_view, output);
} }
static void static void
@@ -530,8 +534,8 @@ kiosk_shell_output_destroy(struct kiosk_shell_output *shoutput)
shoutput->output = NULL; shoutput->output = NULL;
shoutput->output_destroy_listener.notify = NULL; shoutput->output_destroy_listener.notify = NULL;
if (shoutput->background_view) if (shoutput->curtain)
weston_surface_destroy(shoutput->background_view->surface); weston_curtain_destroy(shoutput->curtain);
wl_list_remove(&shoutput->output_destroy_listener.link); wl_list_remove(&shoutput->output_destroy_listener.link);
wl_list_remove(&shoutput->link); wl_list_remove(&shoutput->link);
@@ -795,7 +799,7 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
struct kiosk_shell_seat *kiosk_seat; struct kiosk_shell_seat *kiosk_seat;
shsurf->view->is_mapped = true; shsurf->view->is_mapped = true;
surface->is_mapped = true; weston_surface_map(surface);
kiosk_seat = get_kiosk_shell_seat(seat); kiosk_seat = get_kiosk_shell_seat(seat);
if (seat && kiosk_seat) if (seat && kiosk_seat)
@@ -948,6 +952,17 @@ desktop_surface_set_xwayland_position(struct weston_desktop_surface *desktop_sur
shsurf->xwayland.is_set = true; shsurf->xwayland.is_set = true;
} }
static void
desktop_surface_get_position(struct weston_desktop_surface *desktop_surface,
int32_t *x, int32_t *y, void *shell)
{
struct kiosk_shell_surface *shsurf =
weston_desktop_surface_get_user_data(desktop_surface);
*x = shsurf->view->geometry.x;
*y = shsurf->view->geometry.y;
}
static const struct weston_desktop_api kiosk_shell_desktop_api = { static const struct weston_desktop_api kiosk_shell_desktop_api = {
.struct_size = sizeof(struct weston_desktop_api), .struct_size = sizeof(struct weston_desktop_api),
.surface_added = desktop_surface_added, .surface_added = desktop_surface_added,
@@ -962,6 +977,7 @@ static const struct weston_desktop_api kiosk_shell_desktop_api = {
.ping_timeout = desktop_surface_ping_timeout, .ping_timeout = desktop_surface_ping_timeout,
.pong = desktop_surface_pong, .pong = desktop_surface_pong,
.set_xwayland_position = desktop_surface_set_xwayland_position, .set_xwayland_position = desktop_surface_set_xwayland_position,
.get_position = desktop_surface_get_position,
}; };
/* /*
@@ -1049,6 +1065,10 @@ kiosk_shell_touch_to_activate_binding(struct weston_touch *touch,
static void static void
kiosk_shell_add_bindings(struct kiosk_shell *shell) kiosk_shell_add_bindings(struct kiosk_shell *shell)
{ {
uint32_t mod = 0;
mod = weston_shell_get_binding_modifier(shell->config, MODIFIER_SUPER);
weston_compositor_add_button_binding(shell->compositor, BTN_LEFT, 0, weston_compositor_add_button_binding(shell->compositor, BTN_LEFT, 0,
kiosk_shell_click_to_activate_binding, kiosk_shell_click_to_activate_binding,
shell); shell);
@@ -1058,6 +1078,8 @@ kiosk_shell_add_bindings(struct kiosk_shell *shell)
weston_compositor_add_touch_binding(shell->compositor, 0, weston_compositor_add_touch_binding(shell->compositor, 0,
kiosk_shell_touch_to_activate_binding, kiosk_shell_touch_to_activate_binding,
shell); shell);
weston_install_debug_key_binding(shell->compositor, mod);
} }
static void static void
+1 -1
View File
@@ -88,7 +88,7 @@ struct kiosk_shell_seat {
struct kiosk_shell_output { struct kiosk_shell_output {
struct weston_output *output; struct weston_output *output;
struct wl_listener output_destroy_listener; struct wl_listener output_destroy_listener;
struct weston_view *background_view; struct weston_curtain *curtain;
struct kiosk_shell *shell; struct kiosk_shell *shell;
struct wl_list link; struct wl_list link;
+1 -4
View File
@@ -2,9 +2,6 @@ if get_option('shell-kiosk')
srcs_shell_kiosk = [ srcs_shell_kiosk = [
'kiosk-shell.c', 'kiosk-shell.c',
'kiosk-shell-grab.c', 'kiosk-shell-grab.c',
'../shared/shell-utils.c',
weston_desktop_shell_server_protocol_h,
weston_desktop_shell_protocol_c,
input_method_unstable_v1_server_protocol_h, input_method_unstable_v1_server_protocol_h,
input_method_unstable_v1_protocol_c, input_method_unstable_v1_protocol_c,
] ]
@@ -12,8 +9,8 @@ if get_option('shell-kiosk')
dep_libm, dep_libm,
dep_libexec_weston, dep_libexec_weston,
dep_libshared, dep_libshared,
dep_lib_desktop,
dep_libweston_public, dep_libweston_public,
dep_shell_utils,
] ]
plugin_shell_kiosk = shared_library( plugin_shell_kiosk = shared_library(
'kiosk-shell', 'kiosk-shell',
-36
View File
@@ -1,36 +0,0 @@
srcs_libdesktop = [
'libweston-desktop.c',
'client.c',
'seat.c',
'surface.c',
'xwayland.c',
'wl-shell.c',
'xdg-shell.c',
'xdg-shell-v6.c',
xdg_shell_unstable_v6_server_protocol_h,
xdg_shell_unstable_v6_protocol_c,
xdg_shell_server_protocol_h,
xdg_shell_protocol_c,
]
lib_desktop = shared_library(
'weston-desktop-@0@'.format(libweston_major),
srcs_libdesktop,
include_directories: common_inc,
install: true,
version: '0.0.@0@'.format(libweston_revision),
dependencies: dep_libweston_public
)
dep_lib_desktop = declare_dependency(
link_with: lib_desktop,
dependencies: dep_libweston_public
)
pkgconfig.generate(
lib_desktop,
filebase: 'libweston-desktop-@0@'.format(libweston_major),
name: 'libweston-desktop',
version: version_weston,
description: 'Desktop shells abstraction library for libweston compositors',
requires_private: [ lib_weston, dep_wayland_server ],
subdirs: dir_include_libweston
)
-497
View File
@@ -1,497 +0,0 @@
/*
* Copyright © 2010-2012 Intel Corporation
* Copyright © 2011-2012 Collabora, Ltd.
* Copyright © 2013 Raspberry Pi Foundation
* Copyright © 2016 Quentin "Sardem FF7" Glidic
*
* 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 <wayland-server.h>
#include <libweston/libweston.h>
#include <libweston/zalloc.h>
#include <libweston-desktop/libweston-desktop.h>
#include "internal.h"
#define WD_WL_SHELL_PROTOCOL_VERSION 1
enum weston_desktop_wl_shell_surface_state {
NONE,
TOPLEVEL,
MAXIMIZED,
FULLSCREEN,
TRANSIENT,
POPUP,
};
struct weston_desktop_wl_shell_surface {
struct wl_resource *resource;
struct weston_desktop *desktop;
struct wl_display *display;
struct weston_desktop_surface *surface;
struct weston_desktop_surface *parent;
bool added;
struct weston_desktop_seat *popup_seat;
enum weston_desktop_wl_shell_surface_state state;
struct wl_listener wl_surface_resource_destroy_listener;
};
static void
weston_desktop_wl_shell_surface_set_size(struct weston_desktop_surface *dsurface,
void *user_data,
int32_t width, int32_t height)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
struct weston_surface *wsurface =
weston_desktop_surface_get_surface(surface->surface);
if ((wsurface->width == width && wsurface->height == height) ||
(width == 0 && height == 0))
return;
wl_shell_surface_send_configure(surface->resource,
WL_SHELL_SURFACE_RESIZE_NONE,
width, height);
}
static void
weston_desktop_wl_shell_surface_maybe_ungrab(struct weston_desktop_wl_shell_surface *surface)
{
if (surface->state != POPUP ||
!weston_desktop_surface_get_grab(surface->surface))
return;
weston_desktop_surface_popup_ungrab(surface->surface,
surface->popup_seat);
surface->popup_seat = NULL;
}
static void
weston_desktop_wl_shell_surface_committed(struct weston_desktop_surface *dsurface,
void *user_data,
int32_t sx, int32_t sy)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
struct weston_surface *wsurface =
weston_desktop_surface_get_surface(dsurface);
if (wsurface->buffer_ref.buffer == NULL)
weston_desktop_wl_shell_surface_maybe_ungrab(surface);
if (surface->added)
weston_desktop_api_committed(surface->desktop, surface->surface,
sx, sy);
}
static void
weston_desktop_wl_shell_surface_ping(struct weston_desktop_surface *dsurface,
uint32_t serial, void *user_data)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
wl_shell_surface_send_ping(surface->resource, serial);
}
static void
weston_desktop_wl_shell_surface_close(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
if (surface->state == POPUP)
wl_shell_surface_send_popup_done(surface->resource);
}
static bool
weston_desktop_wl_shell_surface_get_maximized(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
return surface->state == MAXIMIZED;
}
static bool
weston_desktop_wl_shell_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
return surface->state == FULLSCREEN;
}
static void
weston_desktop_wl_shell_change_state(struct weston_desktop_wl_shell_surface *surface,
enum weston_desktop_wl_shell_surface_state state,
struct weston_desktop_surface *parent,
int32_t x, int32_t y)
{
bool to_add = (parent == NULL);
assert(state != NONE);
if (to_add && surface->added) {
surface->state = state;
return;
}
if (surface->state != state) {
if (surface->state == POPUP)
weston_desktop_wl_shell_surface_maybe_ungrab(surface);
if (to_add) {
weston_desktop_surface_unset_relative_to(surface->surface);
weston_desktop_api_surface_added(surface->desktop,
surface->surface);
} else if (surface->added) {
weston_desktop_api_surface_removed(surface->desktop,
surface->surface);
}
surface->state = state;
surface->added = to_add;
}
if (parent != NULL)
weston_desktop_surface_set_relative_to(surface->surface, parent,
x, y, false);
}
static void
weston_desktop_wl_shell_surface_destroy(struct weston_desktop_surface *dsurface,
void *user_data)
{
struct weston_desktop_wl_shell_surface *surface = user_data;
wl_list_remove(&surface->wl_surface_resource_destroy_listener.link);
weston_desktop_wl_shell_surface_maybe_ungrab(surface);
weston_desktop_surface_unset_relative_to(surface->surface);
if (surface->added)
weston_desktop_api_surface_removed(surface->desktop,
surface->surface);
free(surface);
}
static void
weston_desktop_wl_shell_surface_protocol_pong(struct wl_client *wl_client,
struct wl_resource *resource,
uint32_t serial)
{
struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
weston_desktop_client_pong(weston_desktop_surface_get_client(surface), serial);
}
static void
weston_desktop_wl_shell_surface_protocol_move(struct wl_client *wl_client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_seat *seat =
wl_resource_get_user_data(seat_resource);
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
if (seat == NULL)
return;
weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
}
static void
weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial,
enum wl_shell_surface_resize edges)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
enum weston_desktop_surface_edge surf_edges =
(enum weston_desktop_surface_edge) edges;
if (seat == NULL)
return;
weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
}
static void
weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client,
struct wl_resource *resource)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL, 0, 0);
if (surface->parent == NULL)
return;
surface->parent = NULL;
weston_desktop_api_set_parent(surface->desktop, surface->surface, NULL);
}
static void
weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client,
struct wl_resource *resource,
struct wl_resource *parent_resource,
int32_t x, int32_t y,
enum wl_shell_surface_transient flags)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_surface *wparent =
wl_resource_get_user_data(parent_resource);
struct weston_desktop_surface *parent;
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
if (!weston_surface_is_desktop_surface(wparent))
return;
parent = weston_surface_get_desktop_surface(wparent);
if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
x, y);
} else {
weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
0, 0);
surface->parent = parent;
weston_desktop_api_set_parent(surface->desktop,
surface->surface, parent);
}
}
static void
weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client,
struct wl_resource *resource,
enum wl_shell_surface_fullscreen_method method,
uint32_t framerate,
struct wl_resource *output_resource)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
struct weston_output *output = NULL;
if (output_resource != NULL)
output = weston_head_from_resource(output_resource)->output;
weston_desktop_wl_shell_change_state(surface, FULLSCREEN, NULL, 0, 0);
weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
true, output);
}
static void
weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
uint32_t serial,
struct wl_resource *parent_resource,
int32_t x, int32_t y,
enum wl_shell_surface_transient flags)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
struct weston_surface *parent =
wl_resource_get_user_data(parent_resource);
struct weston_desktop_surface *parent_surface;
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
/* Check that if we have a valid wseat we also got a valid desktop seat */
if (wseat != NULL && seat == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
if (!weston_surface_is_desktop_surface(parent))
return;
parent_surface = weston_surface_get_desktop_surface(parent);
weston_desktop_wl_shell_change_state(surface, POPUP,
parent_surface, x, y);
weston_desktop_surface_popup_grab(surface->surface, seat, serial);
surface->popup_seat = seat;
}
static void
weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client,
struct wl_resource *resource,
struct wl_resource *output_resource)
{
struct weston_desktop_surface *dsurface =
wl_resource_get_user_data(resource);
struct weston_desktop_wl_shell_surface *surface =
weston_desktop_surface_get_implementation_data(dsurface);
weston_desktop_wl_shell_change_state(surface, MAXIMIZED, NULL, 0, 0);
weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
}
static void
weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client,
struct wl_resource *resource,
const char *title)
{
struct weston_desktop_surface *surface =
wl_resource_get_user_data(resource);
weston_desktop_surface_set_title(surface, title);
}
static void
weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client,
struct wl_resource *resource,
const char *class_)
{
struct weston_desktop_surface *surface =
wl_resource_get_user_data(resource);
weston_desktop_surface_set_app_id(surface, class_);
}
static const struct wl_shell_surface_interface weston_desktop_wl_shell_surface_implementation = {
.pong = weston_desktop_wl_shell_surface_protocol_pong,
.move = weston_desktop_wl_shell_surface_protocol_move,
.resize = weston_desktop_wl_shell_surface_protocol_resize,
.set_toplevel = weston_desktop_wl_shell_surface_protocol_set_toplevel,
.set_transient = weston_desktop_wl_shell_surface_protocol_set_transient,
.set_fullscreen = weston_desktop_wl_shell_surface_protocol_set_fullscreen,
.set_popup = weston_desktop_wl_shell_surface_protocol_set_popup,
.set_maximized = weston_desktop_wl_shell_surface_protocol_set_maximized,
.set_title = weston_desktop_wl_shell_surface_protocol_set_title,
.set_class = weston_desktop_wl_shell_surface_protocol_set_class,
};
static const struct weston_desktop_surface_implementation weston_desktop_wl_shell_surface_internal_implementation = {
.set_size = weston_desktop_wl_shell_surface_set_size,
.committed = weston_desktop_wl_shell_surface_committed,
.ping = weston_desktop_wl_shell_surface_ping,
.close = weston_desktop_wl_shell_surface_close,
.get_maximized = weston_desktop_wl_shell_surface_get_maximized,
.get_fullscreen = weston_desktop_wl_shell_surface_get_fullscreen,
.destroy = weston_desktop_wl_shell_surface_destroy,
};
static void
wl_surface_resource_destroyed(struct wl_listener *listener,
void *data)
{
struct weston_desktop_wl_shell_surface *surface =
wl_container_of(listener, surface,
wl_surface_resource_destroy_listener);
/* the wl_shell_surface spec says that wl_shell_surfaces are to be
* destroyed automatically when the wl_surface is destroyed. */
weston_desktop_surface_destroy(surface->surface);
}
static void
weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *surface_resource)
{
struct weston_desktop_client *client = wl_resource_get_user_data(resource);
struct weston_surface *wsurface = wl_resource_get_user_data(surface_resource);
struct weston_desktop_wl_shell_surface *surface;
if (weston_surface_set_role(wsurface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0)
return;
surface = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
if (surface == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
surface->desktop = weston_desktop_client_get_desktop(client);
surface->display = weston_desktop_get_display(surface->desktop);
surface->surface =
weston_desktop_surface_create(surface->desktop, client, wsurface,
&weston_desktop_wl_shell_surface_internal_implementation,
surface);
if (surface->surface == NULL) {
free(surface);
return;
}
surface->wl_surface_resource_destroy_listener.notify =
wl_surface_resource_destroyed;
wl_resource_add_destroy_listener(wsurface->resource,
&surface->wl_surface_resource_destroy_listener);
surface->resource =
weston_desktop_surface_add_resource(surface->surface,
&wl_shell_surface_interface,
&weston_desktop_wl_shell_surface_implementation,
id, NULL);
}
static const struct wl_shell_interface weston_desktop_wl_shell_implementation = {
.get_shell_surface = weston_desktop_wl_shell_protocol_get_shell_surface,
};
static void
weston_desktop_wl_shell_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id)
{
struct weston_desktop *desktop = data;
weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface,
&weston_desktop_wl_shell_implementation,
version, id);
}
struct wl_global *
weston_desktop_wl_shell_create(struct weston_desktop *desktop,
struct wl_display *display)
{
return wl_global_create(display,
&wl_shell_interface,
WD_WL_SHELL_PROTOCOL_VERSION, desktop,
weston_desktop_wl_shell_bind);
}
+17 -72
View File
@@ -118,8 +118,9 @@ drm_backend_create_gl_renderer(struct drm_backend *b)
int int
init_egl(struct drm_backend *b) init_egl(struct drm_backend *b)
{ {
b->gbm = create_gbm_device(b->drm.fd); struct drm_device *device = b->drm;
b->gbm = create_gbm_device(device->drm.fd);
if (!b->gbm) if (!b->gbm)
return -1; return -1;
@@ -145,6 +146,7 @@ static void drm_output_fini_cursor_egl(struct drm_output *output)
static int static int
drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b) drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
{ {
struct drm_device *device = output->device;
unsigned int i; unsigned int i;
/* No point creating cursors if we don't have a plane for them. */ /* No point creating cursors if we don't have a plane for them. */
@@ -154,14 +156,14 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) { for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
struct gbm_bo *bo; struct gbm_bo *bo;
bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height, bo = gbm_bo_create(b->gbm, device->cursor_width, device->cursor_height,
GBM_FORMAT_ARGB8888, GBM_FORMAT_ARGB8888,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
if (!bo) if (!bo)
goto err; goto err;
output->gbm_cursor_fb[i] = output->gbm_cursor_fb[i] =
drm_fb_get_from_bo(bo, b, false, BUFFER_CURSOR); drm_fb_get_from_bo(bo, device, false, BUFFER_CURSOR);
if (!output->gbm_cursor_fb[i]) { if (!output->gbm_cursor_fb[i]) {
gbm_bo_destroy(bo); gbm_bo_destroy(bo);
goto err; goto err;
@@ -173,7 +175,7 @@ drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
err: err:
weston_log("cursor buffers unavailable, using gl cursors\n"); weston_log("cursor buffers unavailable, using gl cursors\n");
b->cursors_are_broken = true; device->cursors_are_broken = true;
drm_output_fini_cursor_egl(output); drm_output_fini_cursor_egl(output);
return -1; return -1;
} }
@@ -183,6 +185,7 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
{ {
struct weston_mode *mode = output->base.current_mode; struct weston_mode *mode = output->base.current_mode;
struct drm_plane *plane = output->scanout_plane; struct drm_plane *plane = output->scanout_plane;
const struct pixel_format_info *pixel_format;
struct weston_drm_format *fmt; struct weston_drm_format *fmt;
const uint64_t *modifiers; const uint64_t *modifiers;
unsigned int num_modifiers; unsigned int num_modifiers;
@@ -190,8 +193,15 @@ create_gbm_surface(struct gbm_device *gbm, struct drm_output *output)
fmt = weston_drm_format_array_find_format(&plane->formats, fmt = weston_drm_format_array_find_format(&plane->formats,
output->gbm_format); output->gbm_format);
if (!fmt) { if (!fmt) {
pixel_format = pixel_format_get_info(output->gbm_format);
if (pixel_format)
weston_log("format %s not supported by output %s\n",
pixel_format->drm_format_name,
output->base.name);
else
weston_log("format 0x%x not supported by output %s\n", weston_log("format 0x%x not supported by output %s\n",
output->gbm_format, output->base.name); output->gbm_format,
output->base.name);
return; return;
} }
@@ -280,7 +290,7 @@ struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage) drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct gbm_bo *bo; struct gbm_bo *bo;
struct drm_fb *ret; struct drm_fb *ret;
@@ -295,7 +305,7 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
} }
/* The renderer always produces an opaque image. */ /* The renderer always produces an opaque image. */
ret = drm_fb_get_from_bo(bo, b, true, BUFFER_GBM_SURFACE); ret = drm_fb_get_from_bo(bo, device, true, BUFFER_GBM_SURFACE);
if (!ret) { if (!ret) {
weston_log("failed to get drm_fb for bo\n"); weston_log("failed to get drm_fb for bo\n");
gbm_surface_release_buffer(output->gbm_surface, bo); gbm_surface_release_buffer(output->gbm_surface, bo);
@@ -305,68 +315,3 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
return ret; return ret;
} }
static void
switch_to_gl_renderer(struct drm_backend *b)
{
struct drm_output *output;
bool dmabuf_support_inited;
bool linux_explicit_sync_inited;
if (!b->use_pixman)
return;
dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
linux_explicit_sync_inited =
b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC;
weston_log("Switching to GL renderer\n");
b->gbm = create_gbm_device(b->drm.fd);
if (!b->gbm) {
weston_log("Failed to create gbm device. "
"Aborting renderer switch\n");
return;
}
wl_list_for_each(output, &b->compositor->output_list, base.link)
pixman_renderer_output_destroy(&output->base);
b->compositor->renderer->destroy(b->compositor);
if (drm_backend_create_gl_renderer(b) < 0) {
gbm_device_destroy(b->gbm);
weston_log("Failed to create GL renderer. Quitting.\n");
/* FIXME: we need a function to shutdown cleanly */
assert(0);
}
wl_list_for_each(output, &b->compositor->output_list, base.link)
drm_output_init_egl(output, b);
b->use_pixman = 0;
if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
if (linux_dmabuf_setup(b->compositor) < 0)
weston_log("Error: initializing dmabuf "
"support failed.\n");
}
if (!linux_explicit_sync_inited &&
(b->compositor->capabilities & WESTON_CAP_EXPLICIT_SYNC)) {
if (linux_explicit_synchronization_setup(b->compositor) < 0)
weston_log("Error: initializing explicit "
" synchronization support failed.\n");
}
}
void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data)
{
struct drm_backend *b =
to_drm_backend(keyboard->seat->compositor);
switch_to_gl_renderer(b);
}
+109 -81
View File
@@ -186,6 +186,8 @@ enum wdrm_connector_property {
WDRM_CONNECTOR_CONTENT_PROTECTION, WDRM_CONNECTOR_CONTENT_PROTECTION,
WDRM_CONNECTOR_HDCP_CONTENT_TYPE, WDRM_CONNECTOR_HDCP_CONTENT_TYPE,
WDRM_CONNECTOR_PANEL_ORIENTATION, WDRM_CONNECTOR_PANEL_ORIENTATION,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
WDRM_CONNECTOR_MAX_BPC,
WDRM_CONNECTOR__COUNT WDRM_CONNECTOR__COUNT
}; };
@@ -232,11 +234,20 @@ enum wdrm_crtc_property {
*/ */
enum try_view_on_plane_failure_reasons { enum try_view_on_plane_failure_reasons {
FAILURE_REASONS_NONE = 0, FAILURE_REASONS_NONE = 0,
FAILURE_REASONS_FORCE_RENDERER = (1 << 0), FAILURE_REASONS_FORCE_RENDERER = 1 << 0,
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = (1 << 1), FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE = 1 << 1,
FAILURE_REASONS_DMABUF_MODIFIER_INVALID = (1 << 2), FAILURE_REASONS_DMABUF_MODIFIER_INVALID = 1 << 2,
FAILURE_REASONS_ADD_FB_FAILED = (1 << 3), FAILURE_REASONS_ADD_FB_FAILED = 1 << 3,
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = (1 << 4) 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_TYPE = 1 << 9,
FAILURE_REASONS_GLOBAL_ALPHA = 1 << 10,
FAILURE_REASONS_NO_GBM = 1 << 11,
FAILURE_REASONS_GBM_BO_IMPORT_FAILED = 1 << 12,
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED = 1 << 13,
}; };
/** /**
@@ -249,6 +260,48 @@ enum actions_needed_dmabuf_feedback {
ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE = (1 << 1), ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE = (1 << 1),
}; };
struct drm_device {
struct drm_backend *backend;
struct {
int id;
int fd;
char *filename;
dev_t devnum;
} drm;
/* drm_crtc::link */
struct wl_list crtc_list;
struct wl_list plane_list;
/* drm_writeback::link */
struct wl_list writeback_connector_list;
bool state_invalid;
bool atomic_modeset;
bool aspect_ratio_supported;
int32_t cursor_width;
int32_t cursor_height;
bool cursors_are_broken;
bool sprites_are_broken;
void *repaint_data;
bool fb_modifiers;
/* we need these parameters in order to not fail drmModeAddFB2()
* due to out of bounds dimensions, and then mistakenly set
* sprites_are_broken:
*/
int min_width, max_width;
int min_height, max_height;
};
struct drm_backend { struct drm_backend {
struct weston_backend base; struct weston_backend base;
struct weston_compositor *compositor; struct weston_compositor *compositor;
@@ -259,57 +312,20 @@ struct drm_backend {
struct udev_monitor *udev_monitor; struct udev_monitor *udev_monitor;
struct wl_event_source *udev_drm_source; struct wl_event_source *udev_drm_source;
struct { struct drm_device *drm;
int id;
int fd;
char *filename;
dev_t devnum;
} drm;
struct gbm_device *gbm; struct gbm_device *gbm;
struct wl_listener session_listener; struct wl_listener session_listener;
uint32_t gbm_format; uint32_t gbm_format;
/* we need these parameters in order to not fail drmModeAddFB2()
* due to out of bounds dimensions, and then mistakenly set
* sprites_are_broken:
*/
int min_width, max_width;
int min_height, max_height;
struct wl_list plane_list;
uint32_t next_plane_idx;
void *repaint_data;
bool state_invalid;
/* drm_crtc::link */
struct wl_list crtc_list;
/* drm_writeback::link */
struct wl_list writeback_connector_list;
bool sprites_are_broken;
bool cursors_are_broken;
bool atomic_modeset;
bool use_pixman; bool use_pixman;
bool use_pixman_shadow; bool use_pixman_shadow;
struct udev_input input; struct udev_input input;
int32_t cursor_width;
int32_t cursor_height;
uint32_t pageflip_timeout; uint32_t pageflip_timeout;
bool shutting_down; bool shutting_down;
bool aspect_ratio_supported;
bool fb_modifiers;
struct weston_log_scope *debug; struct weston_log_scope *debug;
}; };
@@ -373,7 +389,7 @@ struct drm_edid {
* output state will complete and be retired separately. * output state will complete and be retired separately.
*/ */
struct drm_pending_state { struct drm_pending_state {
struct drm_backend *backend; struct drm_device *device;
struct wl_list output_list; struct wl_list output_list;
}; };
@@ -396,16 +412,6 @@ struct drm_output_state {
struct wl_list plane_list; struct wl_list plane_list;
}; };
/**
* An instance of this class is created each time we believe we have a plane
* suitable to be used by a view as a direct scan-out. The list is initialized
* and populated locally.
*/
struct drm_plane_zpos {
struct drm_plane *plane;
struct wl_list link; /**< :candidate_plane_zpos_list */
};
/** /**
* Plane state holds the dynamic state for a plane: where it is positioned, * Plane state holds the dynamic state for a plane: where it is positioned,
* and which buffer it is currently displaying. * and which buffer it is currently displaying.
@@ -461,7 +467,7 @@ struct drm_plane_state {
struct drm_plane { struct drm_plane {
struct weston_plane base; struct weston_plane base;
struct drm_backend *backend; struct drm_device *device;
enum wdrm_plane_type type; enum wdrm_plane_type type;
@@ -483,7 +489,7 @@ struct drm_plane {
}; };
struct drm_connector { struct drm_connector {
struct drm_backend *backend; struct drm_device *device;
drmModeConnector *conn; drmModeConnector *conn;
uint32_t connector_id; uint32_t connector_id;
@@ -495,16 +501,15 @@ struct drm_connector {
}; };
struct drm_writeback { struct drm_writeback {
/* drm_backend::writeback_connector_list */ /* drm_device::writeback_connector_list */
struct wl_list link; struct wl_list link;
struct drm_backend *backend; struct drm_device *device;
struct drm_connector connector; struct drm_connector connector;
}; };
struct drm_head { struct drm_head {
struct weston_head base; struct weston_head base;
struct drm_backend *backend;
struct drm_connector connector; struct drm_connector connector;
struct drm_edid edid; struct drm_edid edid;
@@ -512,13 +517,17 @@ struct drm_head {
struct backlight *backlight; struct backlight *backlight;
drmModeModeInfo inherited_mode; /**< Original mode on the connector */ drmModeModeInfo inherited_mode; /**< Original mode on the connector */
uint32_t inherited_max_bpc; /**< Original max_bpc on the connector */
uint32_t inherited_crtc_id; /**< Original CRTC assignment */ uint32_t inherited_crtc_id; /**< Original CRTC assignment */
/* drm_output::disable_head */
struct wl_list disable_head_link;
}; };
struct drm_crtc { struct drm_crtc {
/* drm_backend::crtc_list */ /* drm_device::crtc_list */
struct wl_list link; struct wl_list link;
struct drm_backend *backend; struct drm_device *device;
/* The output driven by the CRTC */ /* The output driven by the CRTC */
struct drm_output *output; struct drm_output *output;
@@ -532,14 +541,18 @@ struct drm_crtc {
struct drm_output { struct drm_output {
struct weston_output base; struct weston_output base;
struct drm_backend *backend; struct drm_device *device;
struct drm_crtc *crtc; struct drm_crtc *crtc;
/* drm_head::disable_head_link */
struct wl_list disable_head;
bool page_flip_pending; bool page_flip_pending;
bool atomic_complete_pending; bool atomic_complete_pending;
bool destroy_pending; bool destroy_pending;
bool disable_pending; bool disable_pending;
bool dpms_off_pending; bool dpms_off_pending;
bool mode_switch_pending;
uint32_t gbm_cursor_handle[2]; uint32_t gbm_cursor_handle[2];
struct drm_fb *gbm_cursor_fb[2]; struct drm_fb *gbm_cursor_fb[2];
@@ -552,6 +565,11 @@ struct drm_output {
uint32_t gbm_format; uint32_t gbm_format;
uint32_t gbm_bo_flags; uint32_t gbm_bo_flags;
uint32_t hdr_output_metadata_blob_id;
uint64_t ackd_color_outcome_serial;
unsigned max_bpc;
/* Plane being displayed directly on the CRTC */ /* Plane being displayed directly on the CRTC */
struct drm_plane *scanout_plane; struct drm_plane *scanout_plane;
@@ -572,19 +590,36 @@ struct drm_output {
struct wl_event_source *pageflip_timer; struct wl_event_source *pageflip_timer;
bool virtual; bool virtual;
void (*virtual_destroy)(struct weston_output *base);
submit_frame_cb virtual_submit_frame; submit_frame_cb virtual_submit_frame;
}; };
void
drm_head_destroy(struct weston_head *head_base);
static inline struct drm_head * static inline struct drm_head *
to_drm_head(struct weston_head *base) to_drm_head(struct weston_head *base)
{ {
if (base->backend_id != drm_head_destroy)
return NULL;
return container_of(base, struct drm_head, base); return container_of(base, struct drm_head, base);
} }
void
drm_output_destroy(struct weston_output *output_base);
void
drm_virtual_output_destroy(struct weston_output *output_base);
static inline struct drm_output * static inline struct drm_output *
to_drm_output(struct weston_output *base) to_drm_output(struct weston_output *base)
{ {
if (
#ifdef BUILD_DRM_VIRTUAL
base->destroy != drm_virtual_output_destroy &&
#endif
base->destroy != drm_output_destroy)
return NULL;
return container_of(base, struct drm_output, base); return container_of(base, struct drm_output, base);
} }
@@ -617,7 +652,7 @@ drm_output_get_plane_type_name(struct drm_plane *p)
} }
struct drm_crtc * struct drm_crtc *
drm_crtc_find(struct drm_backend *b, uint32_t crtc_id); drm_crtc_find(struct drm_device *device, uint32_t crtc_id);
struct drm_head * struct drm_head *
drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id); drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id);
@@ -642,7 +677,7 @@ drm_view_transform_supported(struct weston_view *ev, struct weston_output *outpu
} }
int int
drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode); drm_mode_ensure_blob(struct drm_device *device, struct drm_mode *mode);
struct drm_mode * struct drm_mode *
drm_output_choose_mode(struct drm_output *output, drm_output_choose_mode(struct drm_output *output,
@@ -651,7 +686,7 @@ void
update_head_from_connector(struct drm_head *head); update_head_from_connector(struct drm_head *head);
void void
drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list); drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list);
void void
drm_output_print_modes(struct drm_output *output); drm_output_print_modes(struct drm_output *output);
@@ -662,7 +697,7 @@ drm_output_set_mode(struct weston_output *base,
const char *modeline); const char *modeline);
void void
drm_property_info_populate(struct drm_backend *b, drm_property_info_populate(struct drm_device *device,
const struct drm_property_info *src, const struct drm_property_info *src,
struct drm_property_info *info, struct drm_property_info *info,
unsigned int num_infos, unsigned int num_infos,
@@ -690,7 +725,7 @@ extern const struct drm_property_info connector_props[];
extern const struct drm_property_info crtc_props[]; extern const struct drm_property_info crtc_props[];
int int
init_kms_caps(struct drm_backend *b); init_kms_caps(struct drm_device *device);
int int
drm_pending_state_test(struct drm_pending_state *pending_state); drm_pending_state_test(struct drm_pending_state *pending_state);
@@ -717,15 +752,18 @@ void
drm_fb_unref(struct drm_fb *fb); drm_fb_unref(struct drm_fb *fb);
struct drm_fb * struct drm_fb *
drm_fb_create_dumb(struct drm_backend *b, int width, int height, drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format); uint32_t format);
struct drm_fb * struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend, drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type); bool is_opaque, enum drm_fb_type type);
void void
drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev); 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);
#ifdef BUILD_DRM_GBM #ifdef BUILD_DRM_GBM
extern struct drm_fb * extern struct drm_fb *
drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev, drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
@@ -749,7 +787,7 @@ drm_can_scanout_dmabuf(struct weston_compositor *ec,
#endif #endif
struct drm_pending_state * struct drm_pending_state *
drm_pending_state_alloc(struct drm_backend *backend); drm_pending_state_alloc(struct drm_device *device);
void void
drm_pending_state_free(struct drm_pending_state *pending_state); drm_pending_state_free(struct drm_pending_state *pending_state);
struct drm_output_state * struct drm_output_state *
@@ -800,7 +838,7 @@ void
drm_plane_reset_state(struct drm_plane *plane); drm_plane_reset_state(struct drm_plane *plane);
void void
drm_assign_planes(struct weston_output *output_base, void *repaint_data); drm_assign_planes(struct weston_output *output_base);
bool bool
drm_plane_is_available(struct drm_plane *plane, struct drm_output *output); drm_plane_is_available(struct drm_plane *plane, struct drm_output *output);
@@ -837,9 +875,6 @@ drm_output_fini_egl(struct drm_output *output);
struct drm_fb * struct drm_fb *
drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage); drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage);
void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data);
#else #else
inline static int inline static int
init_egl(struct drm_backend *b) init_egl(struct drm_backend *b)
@@ -864,11 +899,4 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
{ {
return NULL; return NULL;
} }
inline static void
renderer_switch_binding(struct weston_keyboard *keyboard,
const struct timespec *time, uint32_t key, void *data)
{
weston_log("Compiled without GBM/EGL support\n");
}
#endif #endif
+46 -18
View File
@@ -47,7 +47,7 @@
* CRTC's. Also, as this is a fake CRTC, it will not try to populate props. * CRTC's. Also, as this is a fake CRTC, it will not try to populate props.
*/ */
static struct drm_crtc * static struct drm_crtc *
drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output) drm_virtual_crtc_create(struct drm_device *device, struct drm_output *output)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
@@ -55,7 +55,7 @@ drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output)
if (!crtc) if (!crtc)
return NULL; return NULL;
crtc->backend = b; crtc->device = device;
crtc->output = output; crtc->output = output;
crtc->crtc_id = 0; crtc->crtc_id = 0;
@@ -81,17 +81,32 @@ drm_virtual_crtc_destroy(struct drm_crtc *crtc)
free(crtc); free(crtc);
} }
static uint32_t
get_drm_plane_index_maximum(struct drm_device *device)
{
uint32_t max = 0;
struct drm_plane *p;
wl_list_for_each(p, &device->plane_list, link) {
if (p->plane_idx > max)
max = p->plane_idx;
}
return max;
}
/** /**
* Create a drm_plane for virtual output * Create a drm_plane for virtual output
* *
* Call drm_virtual_plane_destroy to clean up the plane. * Call drm_virtual_plane_destroy to clean up the plane.
* *
* @param b DRM compositor backend * @param device DRM device
* @param output Output to create internal plane for * @param output Output to create internal plane for
*/ */
static struct drm_plane * static struct drm_plane *
drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output) drm_virtual_plane_create(struct drm_device *device, struct drm_output *output)
{ {
struct drm_backend *b = device->backend;
struct drm_plane *plane; struct drm_plane *plane;
struct weston_drm_format *fmt; struct weston_drm_format *fmt;
uint64_t mod; uint64_t mod;
@@ -103,7 +118,7 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
} }
plane->type = WDRM_PLANE_TYPE_PRIMARY; plane->type = WDRM_PLANE_TYPE_PRIMARY;
plane->backend = b; plane->device = device;
plane->state_cur = drm_plane_state_alloc(NULL, plane); plane->state_cur = drm_plane_state_alloc(NULL, plane);
plane->state_cur->complete = true; plane->state_cur->complete = true;
@@ -115,7 +130,7 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
/* If output supports linear modifier, we add it to the plane. /* If output supports linear modifier, we add it to the plane.
* Otherwise we add DRM_FORMAT_MOD_INVALID, as explicit modifiers * Otherwise we add DRM_FORMAT_MOD_INVALID, as explicit modifiers
* are not supported. */ * are not supported. */
if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && b->fb_modifiers) if ((output->gbm_bo_flags & GBM_BO_USE_LINEAR) && device->fb_modifiers)
mod = DRM_FORMAT_MOD_LINEAR; mod = DRM_FORMAT_MOD_LINEAR;
else else
mod = DRM_FORMAT_MOD_INVALID; mod = DRM_FORMAT_MOD_INVALID;
@@ -124,7 +139,8 @@ drm_virtual_plane_create(struct drm_backend *b, struct drm_output *output)
goto err; goto err;
weston_plane_init(&plane->base, b->compositor, 0, 0); weston_plane_init(&plane->base, b->compositor, 0, 0);
wl_list_insert(&b->plane_list, &plane->link); plane->plane_idx = get_drm_plane_index_maximum(device) + 1;
wl_list_insert(&device->plane_list, &plane->link);
return plane; return plane;
@@ -163,11 +179,10 @@ static int
drm_virtual_output_submit_frame(struct drm_output *output, drm_virtual_output_submit_frame(struct drm_output *output,
struct drm_fb *fb) struct drm_fb *fb)
{ {
struct drm_backend *b = to_drm_backend(output->base.compositor);
int fd, ret; int fd, ret;
assert(fb->num_planes == 1); assert(fb->num_planes == 1);
ret = drmPrimeHandleToFD(b->drm.fd, fb->handles[0], DRM_CLOEXEC, &fd); ret = drmPrimeHandleToFD(fb->fd, fb->handles[0], DRM_CLOEXEC, &fd);
if (ret) { if (ret) {
weston_log("drmPrimeHandleFD failed, errno=%d\n", errno); weston_log("drmPrimeHandleFD failed, errno=%d\n", errno);
return -1; return -1;
@@ -185,17 +200,20 @@ drm_virtual_output_submit_frame(struct drm_output *output,
static int static int
drm_virtual_output_repaint(struct weston_output *output_base, drm_virtual_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct drm_pending_state *pending_state = repaint_data;
struct drm_output_state *state = NULL; struct drm_output_state *state = NULL;
struct drm_output *output = to_drm_output(output_base); struct drm_output *output = to_drm_output(output_base);
struct drm_plane *scanout_plane = output->scanout_plane; struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_plane_state *scanout_state; struct drm_plane_state *scanout_state;
struct drm_pending_state *pending_state;
struct drm_device *device;
assert(output->virtual); assert(output->virtual);
device = output->device;
pending_state = device->repaint_data;
if (output->disable_pending || output->destroy_pending) if (output->disable_pending || output->destroy_pending)
goto err; goto err;
@@ -242,7 +260,7 @@ drm_virtual_output_deinit(struct weston_output *base)
drm_virtual_crtc_destroy(output->crtc); drm_virtual_crtc_destroy(output->crtc);
} }
static void void
drm_virtual_output_destroy(struct weston_output *base) drm_virtual_output_destroy(struct weston_output *base)
{ {
struct drm_output *output = to_drm_output(base); struct drm_output *output = to_drm_output(base);
@@ -256,6 +274,9 @@ drm_virtual_output_destroy(struct weston_output *base)
drm_output_state_free(output->state_cur); drm_output_state_free(output->state_cur);
if (output->virtual_destroy)
output->virtual_destroy(base);
free(output); free(output);
} }
@@ -263,7 +284,8 @@ static int
drm_virtual_output_enable(struct weston_output *output_base) drm_virtual_output_enable(struct weston_output *output_base)
{ {
struct drm_output *output = to_drm_output(output_base); struct drm_output *output = to_drm_output(output_base);
struct drm_backend *b = to_drm_backend(output_base->compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
assert(output->virtual); assert(output->virtual);
@@ -277,7 +299,7 @@ drm_virtual_output_enable(struct weston_output *output_base)
goto err; goto err;
} }
output->scanout_plane = drm_virtual_plane_create(b, output); output->scanout_plane = drm_virtual_plane_create(device, output);
if (!output->scanout_plane) { if (!output->scanout_plane) {
weston_log("Failed to find primary plane for output %s\n", weston_log("Failed to find primary plane for output %s\n",
output->base.name); output->base.name);
@@ -320,22 +342,27 @@ drm_virtual_output_disable(struct weston_output *base)
} }
static struct weston_output * static struct weston_output *
drm_virtual_output_create(struct weston_compositor *c, char *name) drm_virtual_output_create(struct weston_compositor *c, char *name,
void (*destroy_func)(struct weston_output *))
{ {
struct drm_output *output; struct drm_output *output;
struct drm_backend *b = to_drm_backend(c); struct drm_backend *b = to_drm_backend(c);
/* Always use the main device for virtual outputs */
struct drm_device *device = b->drm;
output = zalloc(sizeof *output); output = zalloc(sizeof *output);
if (!output) if (!output)
return NULL; return NULL;
output->crtc = drm_virtual_crtc_create(b, output); output->device = device;
output->crtc = drm_virtual_crtc_create(device, output);
if (!output->crtc) { if (!output->crtc) {
free(output); free(output);
return NULL; return NULL;
} }
output->virtual = true; output->virtual = true;
output->virtual_destroy = destroy_func;
output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING; output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
weston_output_init(&output->base, c, name); weston_output_init(&output->base, c, name);
@@ -357,7 +384,8 @@ drm_virtual_output_set_gbm_format(struct weston_output *base,
const char *gbm_format) const char *gbm_format)
{ {
struct drm_output *output = to_drm_output(base); struct drm_output *output = to_drm_output(base);
struct drm_backend *b = to_drm_backend(base->compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1) if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
output->gbm_format = b->gbm_format; output->gbm_format = b->gbm_format;
File diff suppressed because it is too large Load Diff
+72 -46
View File
@@ -69,7 +69,7 @@ drm_fb_destroy_dumb(struct drm_fb *fb)
} }
static int static int
drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb) drm_fb_addfb(struct drm_device *device, struct drm_fb *fb)
{ {
int ret = -EINVAL; int ret = -EINVAL;
uint64_t mods[4] = { }; uint64_t mods[4] = { };
@@ -77,7 +77,7 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
/* If we have a modifier set, we must only use the WithModifiers /* If we have a modifier set, we must only use the WithModifiers
* entrypoint; we cannot import it through legacy ioctls. */ * entrypoint; we cannot import it through legacy ioctls. */
if (b->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) { if (device->fb_modifiers && fb->modifier != DRM_FORMAT_MOD_INVALID) {
/* KMS demands that if a modifier is set, it must be the same /* KMS demands that if a modifier is set, it must be the same
* for all planes. */ * for all planes. */
for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++) for (i = 0; i < ARRAY_LENGTH(mods) && fb->handles[i]; i++)
@@ -98,7 +98,7 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
/* Legacy AddFB can't always infer the format from depth/bpp alone, so /* Legacy AddFB can't always infer the format from depth/bpp alone, so
* check if our format is one of the lucky ones. */ * check if our format is one of the lucky ones. */
if (!fb->format->depth || !fb->format->bpp) if (!fb->format->addfb_legacy_depth || !fb->format->bpp)
return ret; return ret;
/* Cannot fall back to AddFB for multi-planar formats either. */ /* Cannot fall back to AddFB for multi-planar formats either. */
@@ -106,13 +106,13 @@ drm_fb_addfb(struct drm_backend *b, struct drm_fb *fb)
return ret; return ret;
ret = drmModeAddFB(fb->fd, fb->width, fb->height, ret = drmModeAddFB(fb->fd, fb->width, fb->height,
fb->format->depth, fb->format->bpp, fb->format->addfb_legacy_depth, fb->format->bpp,
fb->strides[0], fb->handles[0], &fb->fb_id); fb->strides[0], fb->handles[0], &fb->fb_id);
return ret; return ret;
} }
struct drm_fb * struct drm_fb *
drm_fb_create_dumb(struct drm_backend *b, int width, int height, drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format) uint32_t format)
{ {
struct drm_fb *fb; struct drm_fb *fb;
@@ -134,7 +134,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
goto err_fb; goto err_fb;
} }
if (!fb->format->depth || !fb->format->bpp) { if (!fb->format->addfb_legacy_depth || !fb->format->bpp) {
weston_log("format 0x%lx is not compatible with dumb buffers\n", weston_log("format 0x%lx is not compatible with dumb buffers\n",
(unsigned long) format); (unsigned long) format);
goto err_fb; goto err_fb;
@@ -145,7 +145,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
create_arg.width = width; create_arg.width = width;
create_arg.height = height; create_arg.height = height;
ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); ret = drmIoctl(device->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
if (ret) if (ret)
goto err_fb; goto err_fb;
@@ -157,9 +157,9 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
fb->size = create_arg.size; fb->size = create_arg.size;
fb->width = width; fb->width = width;
fb->height = height; fb->height = height;
fb->fd = b->drm.fd; fb->fd = device->drm.fd;
if (drm_fb_addfb(b, fb) != 0) { if (drm_fb_addfb(device, fb) != 0) {
weston_log("failed to create kms fb: %s\n", strerror(errno)); weston_log("failed to create kms fb: %s\n", strerror(errno));
goto err_bo; goto err_bo;
} }
@@ -171,18 +171,18 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
goto err_add_fb; goto err_add_fb;
fb->map = mmap(NULL, fb->size, PROT_WRITE, fb->map = mmap(NULL, fb->size, PROT_WRITE,
MAP_SHARED, b->drm.fd, map_arg.offset); MAP_SHARED, device->drm.fd, map_arg.offset);
if (fb->map == MAP_FAILED) if (fb->map == MAP_FAILED)
goto err_add_fb; goto err_add_fb;
return fb; return fb;
err_add_fb: err_add_fb:
drmModeRmFB(b->drm.fd, fb->fb_id); drmModeRmFB(device->drm.fd, fb->fb_id);
err_bo: err_bo:
memset(&destroy_arg, 0, sizeof(destroy_arg)); memset(&destroy_arg, 0, sizeof(destroy_arg));
destroy_arg.handle = create_arg.handle; destroy_arg.handle = create_arg.handle;
drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); drmIoctl(device->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
err_fb: err_fb:
free(fb); free(fb);
return NULL; return NULL;
@@ -218,7 +218,7 @@ drm_fb_destroy_dmabuf(struct drm_fb *fb)
static struct drm_fb * static struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf, drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_backend *backend, bool is_opaque, struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons) uint32_t *try_view_on_plane_failure_reasons)
{ {
#ifndef HAVE_GBM_FD_IMPORT #ifndef HAVE_GBM_FD_IMPORT
@@ -227,6 +227,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
* of GBM_BO_IMPORT_FD_MODIFIER. */ * of GBM_BO_IMPORT_FD_MODIFIER. */
return NULL; return NULL;
#else #else
struct drm_backend *backend = device->backend;
struct drm_fb *fb; struct drm_fb *fb;
int i; int i;
struct gbm_import_fd_modifier_data import_mod = { struct gbm_import_fd_modifier_data import_mod = {
@@ -287,7 +288,7 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
fb->height = dmabuf->attributes.height; fb->height = dmabuf->attributes.height;
fb->modifier = dmabuf->attributes.modifier[0]; fb->modifier = dmabuf->attributes.modifier[0];
fb->size = 0; fb->size = 0;
fb->fd = backend->drm.fd; fb->fd = device->drm.fd;
ARRAY_COPY(fb->strides, dmabuf->attributes.stride); ARRAY_COPY(fb->strides, dmabuf->attributes.stride);
ARRAY_COPY(fb->offsets, dmabuf->attributes.offset); ARRAY_COPY(fb->offsets, dmabuf->attributes.offset);
@@ -302,10 +303,10 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
if (is_opaque) if (is_opaque)
fb->format = pixel_format_get_opaque_substitute(fb->format); fb->format = pixel_format_get_opaque_substitute(fb->format);
if (backend->min_width > fb->width || if (device->min_width > fb->width ||
fb->width > backend->max_width || fb->width > device->max_width ||
backend->min_height > fb->height || device->min_height > fb->height ||
fb->height > backend->max_height) { fb->height > device->max_height) {
weston_log("bo geometry out of bounds\n"); weston_log("bo geometry out of bounds\n");
goto err_free; goto err_free;
} }
@@ -315,12 +316,15 @@ drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
union gbm_bo_handle handle; union gbm_bo_handle handle;
handle = gbm_bo_get_handle_for_plane(fb->bo, i); handle = gbm_bo_get_handle_for_plane(fb->bo, i);
if (handle.s32 == -1) if (handle.s32 == -1) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED;
goto err_free; goto err_free;
}
fb->handles[i] = handle.u32; fb->handles[i] = handle.u32;
} }
if (drm_fb_addfb(backend, fb) != 0) { if (drm_fb_addfb(device, fb) != 0) {
if (try_view_on_plane_failure_reasons) if (try_view_on_plane_failure_reasons)
*try_view_on_plane_failure_reasons |= *try_view_on_plane_failure_reasons |=
FAILURE_REASONS_ADD_FB_FAILED; FAILURE_REASONS_ADD_FB_FAILED;
@@ -336,7 +340,7 @@ err_free:
} }
struct drm_fb * struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend, drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type) bool is_opaque, enum drm_fb_type type)
{ {
struct drm_fb *fb = gbm_bo_get_user_data(bo); struct drm_fb *fb = gbm_bo_get_user_data(bo);
@@ -356,7 +360,7 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
fb->type = type; fb->type = type;
fb->refcnt = 1; fb->refcnt = 1;
fb->bo = bo; fb->bo = bo;
fb->fd = backend->drm.fd; fb->fd = device->drm.fd;
fb->width = gbm_bo_get_width(bo); fb->width = gbm_bo_get_width(bo);
fb->height = gbm_bo_get_height(bo); fb->height = gbm_bo_get_height(bo);
@@ -389,15 +393,15 @@ drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
if (is_opaque) if (is_opaque)
fb->format = pixel_format_get_opaque_substitute(fb->format); fb->format = pixel_format_get_opaque_substitute(fb->format);
if (backend->min_width > fb->width || if (device->min_width > fb->width ||
fb->width > backend->max_width || fb->width > device->max_width ||
backend->min_height > fb->height || device->min_height > fb->height ||
fb->height > backend->max_height) { fb->height > device->max_height) {
weston_log("bo geometry out of bounds\n"); weston_log("bo geometry out of bounds\n");
goto err_free; goto err_free;
} }
if (drm_fb_addfb(backend, fb) != 0) { if (drm_fb_addfb(device, fb) != 0) {
if (type == BUFFER_GBM_SURFACE) if (type == BUFFER_GBM_SURFACE)
weston_log("failed to create kms fb: %s\n", weston_log("failed to create kms fb: %s\n",
strerror(errno)); strerror(errno));
@@ -453,22 +457,25 @@ drm_can_scanout_dmabuf(struct weston_compositor *ec,
{ {
struct drm_fb *fb; struct drm_fb *fb;
struct drm_backend *b = to_drm_backend(ec); struct drm_backend *b = to_drm_backend(ec);
struct drm_device *device = b->drm;
bool ret = false; bool ret = false;
uint32_t try_reason = 0x0;
fb = drm_fb_get_from_dmabuf(dmabuf, b, true, NULL); fb = drm_fb_get_from_dmabuf(dmabuf, device, true, &try_reason);
if (fb) if (fb)
ret = true; ret = true;
drm_fb_unref(fb); drm_fb_unref(fb);
drm_debug(b, "[dmabuf] dmabuf %p, import test %s\n", dmabuf, drm_debug(b, "[dmabuf] dmabuf %p, import test %s, with reason 0x%x\n", dmabuf,
ret ? "succeeded" : "failed"); ret ? "succeeded" : "failed", try_reason);
return ret; return ret;
} }
static bool static bool
drm_fb_compatible_with_plane(struct drm_fb *fb, struct drm_plane *plane) drm_fb_compatible_with_plane(struct drm_fb *fb, struct drm_plane *plane)
{ {
struct drm_backend *b = plane->backend; struct drm_device *device = plane->device;
struct drm_backend *b = device->backend;
struct weston_drm_format *fmt; struct weston_drm_format *fmt;
/* Check whether the format is supported */ /* Check whether the format is supported */
@@ -508,6 +515,8 @@ drm_fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
struct drm_buffer_fb *buf_fb = struct drm_buffer_fb *buf_fb =
container_of(listener, struct drm_buffer_fb, buffer_destroy_listener); container_of(listener, struct drm_buffer_fb, buffer_destroy_listener);
wl_list_remove(&buf_fb->buffer_destroy_listener.link);
if (buf_fb->fb) { if (buf_fb->fb) {
assert(buf_fb->fb->type == BUFFER_CLIENT || assert(buf_fb->fb->type == BUFFER_CLIENT ||
buf_fb->fb->type == BUFFER_DMABUF); buf_fb->fb->type == BUFFER_DMABUF);
@@ -523,25 +532,36 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_device *device = output->device;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer; struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
struct drm_buffer_fb *buf_fb; struct drm_buffer_fb *buf_fb;
bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox); bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
struct linux_dmabuf_buffer *dmabuf;
struct drm_fb *fb; struct drm_fb *fb;
struct drm_plane *plane; struct drm_plane *plane;
if (ev->alpha != 1.0f) if (ev->alpha != 1.0f) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_GLOBAL_ALPHA;
return NULL; return NULL;
}
if (!drm_view_transform_supported(ev, &output->base)) if (!drm_view_transform_supported(ev, &output->base)) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INCOMPATIBLE_TRANSFORM;
return NULL; return NULL;
}
if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED && if (ev->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED &&
ev->surface->desired_protection > output->base.current_protection) ev->surface->desired_protection > output->base.current_protection) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_INADEQUATE_CONTENT_PROTECTION;
return NULL; return NULL;
}
if (!buffer) if (!buffer) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_BUFFER;
return NULL; return NULL;
}
if (buffer->backend_private) { if (buffer->backend_private) {
buf_fb = buffer->backend_private; buf_fb = buffer->backend_private;
@@ -554,20 +574,18 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
buf_fb->buffer_destroy_listener.notify = drm_fb_handle_buffer_destroy; buf_fb->buffer_destroy_listener.notify = drm_fb_handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &buf_fb->buffer_destroy_listener); wl_signal_add(&buffer->destroy_signal, &buf_fb->buffer_destroy_listener);
if (wl_shm_buffer_get(buffer->resource))
goto unsuitable;
/* GBM is used for dmabuf import as well as from client wl_buffer. */ /* GBM is used for dmabuf import as well as from client wl_buffer. */
if (!b->gbm) if (!b->gbm) {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_NO_GBM;
goto unsuitable; goto unsuitable;
}
dmabuf = linux_dmabuf_buffer_get(buffer->resource); if (buffer->type == WESTON_BUFFER_DMABUF) {
if (dmabuf) { fb = drm_fb_get_from_dmabuf(buffer->dmabuf, device, is_opaque,
fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque,
&buf_fb->failure_reasons); &buf_fb->failure_reasons);
if (!fb) if (!fb)
goto unsuitable; goto unsuitable;
} else { } else if (buffer->type == WESTON_BUFFER_RENDERER_OPAQUE) {
struct gbm_bo *bo; struct gbm_bo *bo;
bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER, bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
@@ -575,16 +593,24 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
if (!bo) if (!bo)
goto unsuitable; goto unsuitable;
fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT); fb = drm_fb_get_from_bo(bo, device, is_opaque, BUFFER_CLIENT);
if (!fb) { if (!fb) {
*try_view_on_plane_failure_reasons |=
(1 << FAILURE_REASONS_ADD_FB_FAILED);
gbm_bo_destroy(bo); gbm_bo_destroy(bo);
goto unsuitable; goto unsuitable;
} }
} else {
*try_view_on_plane_failure_reasons |= FAILURE_REASONS_BUFFER_TYPE;
goto unsuitable;
} }
/* Check if this buffer can ever go on any planes. If it can't, we have /* Check if this buffer can ever go on any planes. If it can't, we have
* no reason to ever have a drm_fb, so we fail it here. */ * no reason to ever have a drm_fb, so we fail it here. */
wl_list_for_each(plane, &b->plane_list, link) { wl_list_for_each(plane, &device->plane_list, link) {
/* only SHM buffers can go into cursor planes */
if (plane->type == WDRM_PLANE_TYPE_CURSOR)
continue;
if (drm_fb_compatible_with_plane(fb, plane)) if (drm_fb_compatible_with_plane(fb, plane))
fb->plane_mask |= (1 << plane->plane_idx); fb->plane_mask |= (1 << plane->plane_idx);
} }
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright 2021-2022 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 <libweston/libweston.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include "drm-internal.h"
static inline uint16_t
color_xy_to_u16(float v)
{
assert(v >= 0.0f);
assert(v <= 1.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* chromaticity coordinate encoding
*/
return (uint16_t)round(v * 50000.0);
}
static inline uint16_t
nits_to_u16(float nits)
{
assert(nits >= 1.0f);
assert(nits <= 65535.0f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* max display mastering luminance, max content light level,
* max frame-average light level
*/
return (uint16_t)round(nits);
}
static inline uint16_t
nits_to_u16_dark(float nits)
{
assert(nits >= 0.0001f);
assert(nits <= 6.5535f);
/*
* CTA-861-G
* 6.9.1 Static Metadata Type 1
* min display mastering luminance
*/
return (uint16_t)round(nits * 10000.0);
}
static void
weston_hdr_metadata_type1_to_kms(struct hdr_metadata_infoframe *dst,
const struct weston_hdr_metadata_type1 *src)
{
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
dst->display_primaries[i].x = color_xy_to_u16(src->primary[i].x);
dst->display_primaries[i].y = color_xy_to_u16(src->primary[i].y);
}
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_WHITE) {
dst->white_point.x = color_xy_to_u16(src->white.x);
dst->white_point.y = color_xy_to_u16(src->white.y);
}
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML)
dst->max_display_mastering_luminance = nits_to_u16(src->maxDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MINDML)
dst->min_display_mastering_luminance = nits_to_u16_dark(src->minDML);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL)
dst->max_cll = nits_to_u16(src->maxCLL);
if (src->group_mask & WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL)
dst->max_fall = nits_to_u16(src->maxFALL);
}
int
drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output)
{
struct drm_device *device = output->device;
const struct weston_hdr_metadata_type1 *src;
struct hdr_output_metadata meta;
uint32_t blob_id = 0;
int ret;
if (output->hdr_output_metadata_blob_id &&
output->ackd_color_outcome_serial == output->base.color_outcome_serial)
return 0;
src = weston_output_get_hdr_metadata_type1(&output->base);
/*
* Set up the data for Dynamic Range and Mastering InfoFrame,
* CTA-861-G, a.k.a the static HDR metadata.
*/
memset(&meta, 0, sizeof meta);
meta.metadata_type = 0; /* Static Metadata Type 1 */
/* Duplicated field in UABI struct */
meta.hdmi_metadata_type1.metadata_type = meta.metadata_type;
switch (output->base.eotf_mode) {
case WESTON_EOTF_MODE_NONE:
assert(0 && "bad eotf_mode: none");
return -1;
case WESTON_EOTF_MODE_SDR:
/*
* Do not send any static HDR metadata. Video sinks should
* respond by switching to traditional SDR mode. If they
* do not, the kernel should fix that up.
*/
assert(output->hdr_output_metadata_blob_id == 0);
return 0;
case WESTON_EOTF_MODE_TRADITIONAL_HDR:
meta.hdmi_metadata_type1.eotf = 1; /* from CTA-861-G */
break;
case WESTON_EOTF_MODE_ST2084:
meta.hdmi_metadata_type1.eotf = 2; /* from CTA-861-G */
weston_hdr_metadata_type1_to_kms(&meta.hdmi_metadata_type1, src);
break;
case WESTON_EOTF_MODE_HLG:
meta.hdmi_metadata_type1.eotf = 3; /* from CTA-861-G */
break;
}
if (meta.hdmi_metadata_type1.eotf == 0) {
assert(0 && "bad eotf_mode");
return -1;
}
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",
output->base.name, strerror(-ret));
return -1;
}
drmModeDestroyPropertyBlob(device->drm.fd,
output->hdr_output_metadata_blob_id);
output->hdr_output_metadata_blob_id = blob_id;
output->ackd_color_outcome_serial = output->base.color_outcome_serial;
return 0;
}
+173 -126
View File
@@ -143,6 +143,10 @@ const struct drm_property_info connector_props[] = {
.enum_values = panel_orientation_enums, .enum_values = panel_orientation_enums,
.num_enum_values = WDRM_PANEL_ORIENTATION__COUNT, .num_enum_values = WDRM_PANEL_ORIENTATION__COUNT,
}, },
[WDRM_CONNECTOR_HDR_OUTPUT_METADATA] = {
.name = "HDR_OUTPUT_METADATA",
},
[WDRM_CONNECTOR_MAX_BPC] = { .name = "max bpc", },
}; };
const struct drm_property_info crtc_props[] = { const struct drm_property_info crtc_props[] = {
@@ -272,14 +276,14 @@ drm_property_get_range_values(struct drm_property_info *info,
* The values given in enum_names are searched for, and stored in the * The values given in enum_names are searched for, and stored in the
* same-indexed field of the map array. * same-indexed field of the map array.
* *
* @param b DRM backend object * @param device DRM device object
* @param src DRM property info array to source from * @param src DRM property info array to source from
* @param info DRM property info array to copy into * @param info DRM property info array to copy into
* @param num_infos Number of entries in the source array * @param num_infos Number of entries in the source array
* @param props DRM object properties for the object * @param props DRM object properties for the object
*/ */
void void
drm_property_info_populate(struct drm_backend *b, drm_property_info_populate(struct drm_device *device,
const struct drm_property_info *src, const struct drm_property_info *src,
struct drm_property_info *info, struct drm_property_info *info,
unsigned int num_infos, unsigned int num_infos,
@@ -311,7 +315,7 @@ drm_property_info_populate(struct drm_backend *b,
for (i = 0; i < props->count_props; i++) { for (i = 0; i < props->count_props; i++) {
unsigned int k; unsigned int k;
prop = drmModeGetProperty(b->drm.fd, props->props[i]); prop = drmModeGetProperty(device->drm.fd, props->props[i]);
if (!prop) if (!prop)
continue; continue;
@@ -411,19 +415,6 @@ drm_property_info_free(struct drm_property_info *info, int num_props)
memset(info, 0, sizeof(*info) * num_props); memset(info, 0, sizeof(*info) * num_props);
} }
static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob *blob)
{
return (uint32_t *)(((char *)blob) + blob->formats_offset);
}
static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob *blob)
{
return (struct drm_format_modifier *)
(((char *)blob) + blob->modifiers_offset);
}
/** /**
* Populates the plane's formats array, using either the IN_FORMATS blob * Populates the plane's formats array, using either the IN_FORMATS blob
* property (if available), or the plane's format list if not. * property (if available), or the plane's format list if not.
@@ -433,13 +424,11 @@ drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
const drmModeObjectProperties *props, const drmModeObjectProperties *props,
const bool use_modifiers) const bool use_modifiers)
{ {
unsigned i, j; struct drm_device *device = plane->device;
uint32_t i, blob_id, fmt_prev = DRM_FORMAT_INVALID;
drmModeFormatModifierIterator drm_iter = {0};
struct weston_drm_format *fmt = NULL;
drmModePropertyBlobRes *blob = NULL; drmModePropertyBlobRes *blob = NULL;
struct drm_format_modifier_blob *fmt_mod_blob;
struct drm_format_modifier *blob_modifiers;
uint32_t *blob_formats;
uint32_t blob_id;
struct weston_drm_format *fmt;
int ret = 0; int ret = 0;
if (!use_modifiers) if (!use_modifiers)
@@ -451,39 +440,26 @@ drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane,
if (blob_id == 0) if (blob_id == 0)
goto fallback; goto fallback;
blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id); blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (!blob) if (!blob)
goto fallback; goto fallback;
fmt_mod_blob = blob->data; while (drmModeFormatModifierBlobIterNext(blob, &drm_iter)) {
blob_formats = formats_ptr(fmt_mod_blob); if (fmt_prev != drm_iter.fmt) {
blob_modifiers = modifiers_ptr(fmt_mod_blob);
assert(kplane->count_formats == fmt_mod_blob->count_formats);
for (i = 0; i < fmt_mod_blob->count_formats; i++) {
fmt = weston_drm_format_array_add_format(&plane->formats, fmt = weston_drm_format_array_add_format(&plane->formats,
blob_formats[i]); drm_iter.fmt);
if (!fmt) { if (!fmt) {
ret = -1; ret = -1;
goto out; goto out;
} }
for (j = 0; j < fmt_mod_blob->count_modifiers; j++) { fmt_prev = drm_iter.fmt;
struct drm_format_modifier *mod = &blob_modifiers[j];
if ((i < mod->offset) || (i > mod->offset + 63))
continue;
if (!(mod->formats & (1 << (i - mod->offset))))
continue;
ret = weston_drm_format_add_modifier(fmt, mod->modifier);
if (ret < 0)
goto out;
} }
if (fmt->modifiers.size == 0) ret = weston_drm_format_add_modifier(fmt, drm_iter.mod);
weston_drm_format_array_remove_latest_format(&plane->formats); if (ret < 0)
goto out;
} }
out: out:
@@ -510,14 +486,15 @@ drm_output_set_gamma(struct weston_output *output_base,
{ {
int rc; int rc;
struct drm_output *output = to_drm_output(output_base); struct drm_output *output = to_drm_output(output_base);
struct drm_backend *backend = struct drm_device *device = output->device;
to_drm_backend(output->base.compositor);
assert(output);
/* check */ /* check */
if (output_base->gamma_size != size) if (output_base->gamma_size != size)
return; return;
rc = drmModeCrtcSetGamma(backend->drm.fd, rc = drmModeCrtcSetGamma(device->drm.fd,
output->crtc->crtc_id, output->crtc->crtc_id,
size, r, g, b); size, r, g, b);
if (rc) if (rc)
@@ -535,7 +512,8 @@ drm_output_assign_state(struct drm_output_state *state,
enum drm_state_apply_mode mode) enum drm_state_apply_mode mode)
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *plane_state; struct drm_plane_state *plane_state;
struct drm_head *head; struct drm_head *head;
@@ -552,13 +530,13 @@ drm_output_assign_state(struct drm_output_state *state,
output->state_cur = state; output->state_cur = state;
if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) { if (device->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) {
drm_debug(b, "\t[CRTC:%u] setting pending flip\n", drm_debug(b, "\t[CRTC:%u] setting pending flip\n",
output->crtc->crtc_id); output->crtc->crtc_id);
output->atomic_complete_pending = true; output->atomic_complete_pending = true;
} }
if (b->atomic_modeset && if (device->atomic_modeset &&
state->protection == WESTON_HDCP_DISABLE) state->protection == WESTON_HDCP_DISABLE)
wl_list_for_each(head, &output->base.head_list, base.output_link) wl_list_for_each(head, &output->base.head_list, base.output_link)
weston_head_set_content_protection_status(&head->base, weston_head_set_content_protection_status(&head->base,
@@ -580,7 +558,7 @@ drm_output_assign_state(struct drm_output_state *state,
continue; continue;
} }
if (b->atomic_modeset) if (device->atomic_modeset)
continue; continue;
assert(plane->type != WDRM_PLANE_TYPE_OVERLAY); assert(plane->type != WDRM_PLANE_TYPE_OVERLAY);
@@ -593,7 +571,7 @@ static void
drm_output_set_cursor(struct drm_output_state *output_state) drm_output_set_cursor(struct drm_output_state *output_state)
{ {
struct drm_output *output = output_state->output; struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_crtc *crtc = output->crtc; struct drm_crtc *crtc = output->crtc;
struct drm_plane *plane = output->cursor_plane; struct drm_plane *plane = output->cursor_plane;
struct drm_plane_state *state; struct drm_plane_state *state;
@@ -609,7 +587,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
if (!state->fb) { if (!state->fb) {
pixman_region32_fini(&plane->base.damage); pixman_region32_fini(&plane->base.damage);
pixman_region32_init(&plane->base.damage); pixman_region32_init(&plane->base.damage);
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0); drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
return; return;
} }
@@ -618,8 +596,8 @@ drm_output_set_cursor(struct drm_output_state *output_state)
handle = output->gbm_cursor_handle[output->current_cursor]; handle = output->gbm_cursor_handle[output->current_cursor];
if (plane->state_cur->fb != state->fb) { if (plane->state_cur->fb != state->fb) {
if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle, if (drmModeSetCursor(device->drm.fd, crtc->crtc_id, handle,
b->cursor_width, b->cursor_height)) { device->cursor_width, device->cursor_height)) {
weston_log("failed to set cursor: %s\n", weston_log("failed to set cursor: %s\n",
strerror(errno)); strerror(errno));
goto err; goto err;
@@ -629,7 +607,7 @@ drm_output_set_cursor(struct drm_output_state *output_state)
pixman_region32_fini(&plane->base.damage); pixman_region32_fini(&plane->base.damage);
pixman_region32_init(&plane->base.damage); pixman_region32_init(&plane->base.damage);
if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id, if (drmModeMoveCursor(device->drm.fd, crtc->crtc_id,
state->dest_x, state->dest_y)) { state->dest_x, state->dest_y)) {
weston_log("failed to move cursor: %s\n", strerror(errno)); weston_log("failed to move cursor: %s\n", strerror(errno));
goto err; goto err;
@@ -638,15 +616,16 @@ drm_output_set_cursor(struct drm_output_state *output_state)
return; return;
err: err:
b->cursors_are_broken = true; device->cursors_are_broken = true;
drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0); drmModeSetCursor(device->drm.fd, crtc->crtc_id, 0, 0, 0);
} }
static int static int
drm_output_apply_state_legacy(struct drm_output_state *state) drm_output_apply_state_legacy(struct drm_output_state *state)
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *backend = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *backend = device->backend;
struct drm_plane *scanout_plane = output->scanout_plane; struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_crtc *crtc = output->crtc; struct drm_crtc *crtc = output->crtc;
struct drm_property_info *dpms_prop; struct drm_property_info *dpms_prop;
@@ -678,14 +657,14 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (state->dpms != WESTON_DPMS_ON) { if (state->dpms != WESTON_DPMS_ON) {
if (output->cursor_plane) { if (output->cursor_plane) {
ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id, ret = drmModeSetCursor(device->drm.fd, crtc->crtc_id,
0, 0, 0); 0, 0, 0);
if (ret) if (ret)
weston_log("drmModeSetCursor failed disable: %s\n", weston_log("drmModeSetCursor failed disable: %s\n",
strerror(errno)); strerror(errno));
} }
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0, ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL); NULL, 0, NULL);
if (ret) if (ret)
weston_log("drmModeSetCrtc failed disabling: %s\n", weston_log("drmModeSetCrtc failed disabling: %s\n",
@@ -719,12 +698,12 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
assert(scanout_state->in_fence_fd == -1); assert(scanout_state->in_fence_fd == -1);
mode = to_drm_mode(output->base.current_mode); mode = to_drm_mode(output->base.current_mode);
if (backend->state_invalid || if (device->state_invalid ||
!scanout_plane->state_cur->fb || !scanout_plane->state_cur->fb ||
scanout_plane->state_cur->fb->strides[0] != scanout_plane->state_cur->fb->strides[0] !=
scanout_state->fb->strides[0]) { scanout_state->fb->strides[0]) {
ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id, scanout_state->fb->fb_id,
0, 0, 0, 0,
connectors, n_conn, connectors, n_conn,
@@ -740,7 +719,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
crtc->crtc_id, scanout_state->plane->plane_id, crtc->crtc_id, scanout_state->plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN"); pinfo ? pinfo->drm_format_name : "UNKNOWN");
if (drmModePageFlip(backend->drm.fd, crtc->crtc_id, if (drmModePageFlip(device->drm.fd, crtc->crtc_id,
scanout_state->fb->fb_id, scanout_state->fb->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) { DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
weston_log("queueing pageflip failed: %s\n", strerror(errno)); weston_log("queueing pageflip failed: %s\n", strerror(errno));
@@ -761,7 +740,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (dpms_prop->prop_id == 0) if (dpms_prop->prop_id == 0)
continue; continue;
ret = drmModeConnectorSetProperty(backend->drm.fd, ret = drmModeConnectorSetProperty(device->drm.fd,
head->connector.connector_id, head->connector.connector_id,
dpms_prop->prop_id, dpms_prop->prop_id,
state->dpms); state->dpms);
@@ -786,6 +765,8 @@ static int
crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc, crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
enum wdrm_crtc_property prop, uint64_t val) enum wdrm_crtc_property prop, uint64_t val)
{ {
struct drm_device *device = crtc->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &crtc->props_crtc[prop]; struct drm_property_info *info = &crtc->props_crtc[prop];
int ret; int ret;
@@ -794,7 +775,7 @@ crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc,
ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id, ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id,
val); val);
drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n", drm_debug(b, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) crtc->crtc_id, (unsigned long) crtc->crtc_id,
(unsigned long) info->prop_id, info->name, (unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val); (unsigned long long) val, (unsigned long long) val);
@@ -805,6 +786,8 @@ static int
connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector, connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
enum wdrm_connector_property prop, uint64_t val) enum wdrm_connector_property prop, uint64_t val)
{ {
struct drm_device *device = connector->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &connector->props[prop]; struct drm_property_info *info = &connector->props[prop];
uint32_t connector_id = connector->connector_id; uint32_t connector_id = connector->connector_id;
int ret; int ret;
@@ -813,7 +796,7 @@ connector_add_prop(drmModeAtomicReq *req, struct drm_connector *connector,
return -1; return -1;
ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val); ret = drmModeAtomicAddProperty(req, connector_id, info->prop_id, val);
drm_debug(connector->backend, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n", drm_debug(b, "\t\t\t[CONN:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) connector_id, (unsigned long) connector_id,
(unsigned long) info->prop_id, info->name, (unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val); (unsigned long long) val, (unsigned long long) val);
@@ -824,6 +807,8 @@ static int
plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane, plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
enum wdrm_plane_property prop, uint64_t val) enum wdrm_plane_property prop, uint64_t val)
{ {
struct drm_device *device = plane->device;
struct drm_backend *b = device->backend;
struct drm_property_info *info = &plane->props[prop]; struct drm_property_info *info = &plane->props[prop];
int ret; int ret;
@@ -832,7 +817,7 @@ plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id, ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
val); val);
drm_debug(plane->backend, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n", drm_debug(b, "\t\t\t[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
(unsigned long) plane->plane_id, (unsigned long) plane->plane_id,
(unsigned long) info->prop_id, info->name, (unsigned long) info->prop_id, info->name,
(unsigned long long) val, (unsigned long long) val); (unsigned long long) val, (unsigned long long) val);
@@ -921,17 +906,52 @@ drm_connector_set_hdcp_property(struct drm_connector *connector,
assert(ret == 0); assert(ret == 0);
} }
static int
drm_connector_set_max_bpc(struct drm_connector *connector,
struct drm_output *output,
drmModeAtomicReq *req)
{
const struct drm_property_info *info;
struct drm_head *head;
struct drm_backend *backend = output->device->backend;
uint64_t max_bpc;
uint64_t a, b;
if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_MAX_BPC))
return 0;
if (output->max_bpc == 0) {
/* A value of 0 means that the current max_bpc must be programmed. */
head = drm_head_find_by_connector(backend, connector->connector_id);
max_bpc = head->inherited_max_bpc;
} else {
info = &connector->props[WDRM_CONNECTOR_MAX_BPC];
assert(info->flags & DRM_MODE_PROP_RANGE);
assert(info->num_range_values == 2);
a = info->range_values[0];
b = info->range_values[1];
assert(a <= b);
max_bpc = MAX(a, MIN(output->max_bpc, b));
}
return connector_add_prop(req, connector,
WDRM_CONNECTOR_MAX_BPC, max_bpc);
}
static int static int
drm_output_apply_state_atomic(struct drm_output_state *state, drm_output_apply_state_atomic(struct drm_output_state *state,
drmModeAtomicReq *req, drmModeAtomicReq *req,
uint32_t *flags) uint32_t *flags)
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_crtc *crtc = output->crtc; struct drm_crtc *crtc = output->crtc;
struct drm_plane_state *plane_state; struct drm_plane_state *plane_state;
struct drm_mode *current_mode = to_drm_mode(output->base.current_mode); struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
struct drm_head *head; struct drm_head *head;
struct drm_head *tmp;
int ret = 0; int ret = 0;
drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n", drm_debug(b, "\t\t[atomic] %s output %lu (%s) state\n",
@@ -944,7 +964,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
} }
if (state->dpms == WESTON_DPMS_ON) { if (state->dpms == WESTON_DPMS_ON) {
ret = drm_mode_ensure_blob(b, current_mode); ret = drm_mode_ensure_blob(device, current_mode);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -968,12 +988,30 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
wl_list_for_each(head, &output->base.head_list, base.output_link) wl_list_for_each(head, &output->base.head_list, base.output_link)
ret |= connector_add_prop(req, &head->connector, ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_CRTC_ID, 0); 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);
wl_list_remove(&head->disable_head_link);
wl_list_init(&head->disable_head_link);
}
} }
wl_list_for_each(head, &output->base.head_list, base.output_link) wl_list_for_each(head, &output->base.head_list, base.output_link) {
drm_connector_set_hdcp_property(&head->connector, drm_connector_set_hdcp_property(&head->connector,
state->protection, req); state->protection, req);
if (drm_connector_has_prop(&head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) {
ret |= connector_add_prop(req, &head->connector,
WDRM_CONNECTOR_HDR_OUTPUT_METADATA,
output->hdr_output_metadata_blob_id);
}
ret |= drm_connector_set_max_bpc(&head->connector, output, req);
}
if (ret != 0) { if (ret != 0) {
weston_log("couldn't set atomic CRTC/connector state\n"); weston_log("couldn't set atomic CRTC/connector state\n");
return ret; return ret;
@@ -1010,7 +1048,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
if (plane_state->fb && plane_state->fb->format) if (plane_state->fb && plane_state->fb->format)
pinfo = plane_state->fb->format; pinfo = plane_state->fb->format;
drm_debug(plane->backend, "\t\t\t[PLANE:%lu] FORMAT: %s\n", drm_debug(b, "\t\t\t[PLANE:%lu] FORMAT: %s\n",
(unsigned long) plane->plane_id, (unsigned long) plane->plane_id,
pinfo ? pinfo->drm_format_name : "UNKNOWN"); pinfo ? pinfo->drm_format_name : "UNKNOWN");
@@ -1044,7 +1082,8 @@ static int
drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
enum drm_state_apply_mode mode) enum drm_state_apply_mode mode)
{ {
struct drm_backend *b = pending_state->backend; struct drm_device *device = pending_state->device;
struct drm_backend *b = device->backend;
struct drm_output_state *output_state, *tmp; struct drm_output_state *output_state, *tmp;
struct drm_plane *plane; struct drm_plane *plane;
drmModeAtomicReq *req = drmModeAtomicAlloc(); drmModeAtomicReq *req = drmModeAtomicAlloc();
@@ -1066,7 +1105,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
break; break;
} }
if (b->state_invalid) { if (device->state_invalid) {
struct weston_head *head_base; struct weston_head *head_base;
struct drm_head *head; struct drm_head *head;
struct drm_crtc *crtc; struct drm_crtc *crtc;
@@ -1082,12 +1121,16 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
wl_list_for_each(head_base, wl_list_for_each(head_base,
&b->compositor->head_list, compositor_link) { &b->compositor->head_list, compositor_link) {
struct drm_property_info *info; struct drm_property_info *info;
head = to_drm_head(head_base);
if (!head)
continue;
if (weston_head_is_enabled(head_base)) if (weston_head_is_enabled(head_base))
continue; continue;
head = to_drm_head(head_base);
connector_id = head->connector.connector_id; connector_id = head->connector.connector_id;
if (head->connector.device != device)
continue;
drm_debug(b, "\t\t[atomic] disabling inactive head %s\n", drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
head_base->name); head_base->name);
@@ -1103,7 +1146,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
ret = -1; ret = -1;
} }
wl_list_for_each(crtc, &b->crtc_list, link) { wl_list_for_each(crtc, &device->crtc_list, link) {
struct drm_property_info *info; struct drm_property_info *info;
drmModeObjectProperties *props; drmModeObjectProperties *props;
uint64_t active; uint64_t active;
@@ -1116,7 +1159,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
* off, as the kernel will refuse to generate an event * off, as the kernel will refuse to generate an event
* for an off->off state and fail the commit. * for an off->off state and fail the commit.
*/ */
props = drmModeObjectGetProperties(b->drm.fd, props = drmModeObjectGetProperties(device->drm.fd,
crtc->crtc_id, crtc->crtc_id,
DRM_MODE_OBJECT_CRTC); DRM_MODE_OBJECT_CRTC);
if (!props) { if (!props) {
@@ -1139,7 +1182,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
/* Disable all the planes; planes which are being used will /* Disable all the planes; planes which are being used will
* override this state in the output-state application. */ * override this state in the output-state application. */
wl_list_for_each(plane, &b->plane_list, link) { wl_list_for_each(plane, &device->plane_list, link) {
drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n", drm_debug(b, "\t\t[atomic] starting with plane %lu disabled\n",
(unsigned long) plane->plane_id); (unsigned long) plane->plane_id);
plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0); plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
@@ -1162,7 +1205,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
goto out; goto out;
} }
ret = drmModeAtomicCommit(b->drm.fd, req, flags, b); ret = drmModeAtomicCommit(device->drm.fd, req, flags, device);
drm_debug(b, "[atomic] drmModeAtomicCommit\n"); drm_debug(b, "[atomic] drmModeAtomicCommit\n");
/* Test commits do not take ownership of the state; return /* Test commits do not take ownership of the state; return
@@ -1182,7 +1225,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
link) link)
drm_output_assign_state(output_state, mode); drm_output_assign_state(output_state, mode);
b->state_invalid = false; device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list)); assert(wl_list_empty(&pending_state->output_list));
@@ -1213,9 +1256,9 @@ out:
int int
drm_pending_state_test(struct drm_pending_state *pending_state) drm_pending_state_test(struct drm_pending_state *pending_state)
{ {
struct drm_backend *b = pending_state->backend; struct drm_device *device = pending_state->device;
if (b->atomic_modeset) if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state, return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_TEST_ONLY); DRM_STATE_TEST_ONLY);
@@ -1234,24 +1277,25 @@ drm_pending_state_test(struct drm_pending_state *pending_state)
int int
drm_pending_state_apply(struct drm_pending_state *pending_state) drm_pending_state_apply(struct drm_pending_state *pending_state)
{ {
struct drm_backend *b = pending_state->backend; struct drm_device *device = pending_state->device;
struct drm_backend *b = device->backend;
struct drm_output_state *output_state, *tmp; struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
if (b->atomic_modeset) if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state, return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_ASYNC); DRM_STATE_APPLY_ASYNC);
if (b->state_invalid) { if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've /* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly * just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables * disable all the CRTCs we aren't using. This also disables
* all connectors on these CRTCs, so we don't need to do that * all connectors on these CRTCs, so we don't need to do that
* separately with the pre-atomic API. */ * separately with the pre-atomic API. */
wl_list_for_each(crtc, &b->crtc_list, link) { wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output) if (crtc->output)
continue; continue;
drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0, drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL); NULL, 0, NULL);
} }
} }
@@ -1274,7 +1318,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
weston_output_repaint_failed(&output->base); weston_output_repaint_failed(&output->base);
drm_output_state_free(output->state_cur); drm_output_state_free(output->state_cur);
output->state_cur = drm_output_state_alloc(output, NULL); output->state_cur = drm_output_state_alloc(output, NULL);
b->state_invalid = true; device->state_invalid = true;
if (!b->use_pixman) { if (!b->use_pixman) {
drm_output_fini_egl(output); drm_output_fini_egl(output);
drm_output_init_egl(output, b); drm_output_init_egl(output, b);
@@ -1282,7 +1326,7 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
} }
} }
b->state_invalid = false; device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list)); assert(wl_list_empty(&pending_state->output_list));
@@ -1301,24 +1345,24 @@ drm_pending_state_apply(struct drm_pending_state *pending_state)
int int
drm_pending_state_apply_sync(struct drm_pending_state *pending_state) drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
{ {
struct drm_backend *b = pending_state->backend; struct drm_device *device = pending_state->device;
struct drm_output_state *output_state, *tmp; struct drm_output_state *output_state, *tmp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
if (b->atomic_modeset) if (device->atomic_modeset)
return drm_pending_state_apply_atomic(pending_state, return drm_pending_state_apply_atomic(pending_state,
DRM_STATE_APPLY_SYNC); DRM_STATE_APPLY_SYNC);
if (b->state_invalid) { if (device->state_invalid) {
/* If we need to reset all our state (e.g. because we've /* If we need to reset all our state (e.g. because we've
* just started, or just been VT-switched in), explicitly * just started, or just been VT-switched in), explicitly
* disable all the CRTCs we aren't using. This also disables * disable all the CRTCs we aren't using. This also disables
* all connectors on these CRTCs, so we don't need to do that * all connectors on these CRTCs, so we don't need to do that
* separately with the pre-atomic API. */ * separately with the pre-atomic API. */
wl_list_for_each(crtc, &b->crtc_list, link) { wl_list_for_each(crtc, &device->crtc_list, link) {
if (crtc->output) if (crtc->output)
continue; continue;
drmModeSetCrtc(b->drm.fd, crtc->crtc_id, 0, 0, 0, drmModeSetCrtc(device->drm.fd, crtc->crtc_id, 0, 0, 0,
NULL, 0, NULL); NULL, 0, NULL);
} }
} }
@@ -1335,7 +1379,7 @@ drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
} }
} }
b->state_invalid = false; device->state_invalid = false;
assert(wl_list_empty(&pending_state->output_list)); assert(wl_list_empty(&pending_state->output_list));
@@ -1360,14 +1404,14 @@ page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data) unsigned int sec, unsigned int usec, void *data)
{ {
struct drm_output *output = data; struct drm_output *output = data;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
drm_output_update_msc(output, frame); drm_output_update_msc(output, frame);
assert(!b->atomic_modeset); assert(!device->atomic_modeset);
assert(output->page_flip_pending); assert(output->page_flip_pending);
output->page_flip_pending = false; output->page_flip_pending = false;
@@ -1378,14 +1422,15 @@ static void
atomic_flip_handler(int fd, unsigned int frame, unsigned int sec, atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, unsigned int crtc_id, void *data) unsigned int usec, unsigned int crtc_id, void *data)
{ {
struct drm_backend *b = data; struct drm_device *device = data;
struct drm_backend *b = device->backend;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_output *output; struct drm_output *output;
uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
crtc = drm_crtc_find(b, crtc_id); crtc = drm_crtc_find(device, crtc_id);
assert(crtc); assert(crtc);
output = crtc->output; output = crtc->output;
@@ -1399,7 +1444,7 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
drm_output_update_msc(output, frame); drm_output_update_msc(output, frame);
drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id); drm_debug(b, "[atomic][CRTC:%u] flip processing started\n", crtc_id);
assert(b->atomic_modeset); assert(device->atomic_modeset);
assert(output->atomic_complete_pending); assert(output->atomic_complete_pending);
output->atomic_complete_pending = false; output->atomic_complete_pending = false;
@@ -1410,12 +1455,12 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
int int
on_drm_input(int fd, uint32_t mask, void *data) on_drm_input(int fd, uint32_t mask, void *data)
{ {
struct drm_backend *b = data; struct drm_device *device = data;
drmEventContext evctx; drmEventContext evctx;
memset(&evctx, 0, sizeof evctx); memset(&evctx, 0, sizeof evctx);
evctx.version = 3; evctx.version = 3;
if (b->atomic_modeset) if (device->atomic_modeset)
evctx.page_flip_handler2 = atomic_flip_handler; evctx.page_flip_handler2 = atomic_flip_handler;
else else
evctx.page_flip_handler = page_flip_handler; evctx.page_flip_handler = page_flip_handler;
@@ -1425,61 +1470,63 @@ on_drm_input(int fd, uint32_t mask, void *data)
} }
int int
init_kms_caps(struct drm_backend *b) init_kms_caps(struct drm_device *device)
{ {
struct drm_backend *b = device->backend;
struct weston_compositor *compositor = b->compositor;
uint64_t cap; uint64_t cap;
int ret; int ret;
weston_log("using %s\n", b->drm.filename); weston_log("using %s\n", device->drm.filename);
ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap); ret = drmGetCap(device->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
if (ret != 0 || cap != 1) { if (ret != 0 || cap != 1) {
weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n"); weston_log("Error: kernel DRM KMS does not support DRM_CAP_TIMESTAMP_MONOTONIC.\n");
return -1; return -1;
} }
if (weston_compositor_set_presentation_clock(b->compositor, CLOCK_MONOTONIC) < 0) { if (weston_compositor_set_presentation_clock(compositor, CLOCK_MONOTONIC) < 0) {
weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n"); weston_log("Error: failed to set presentation clock to CLOCK_MONOTONIC.\n");
return -1; return -1;
} }
ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap); ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
if (ret == 0) if (ret == 0)
b->cursor_width = cap; device->cursor_width = cap;
else else
b->cursor_width = 64; device->cursor_width = 64;
ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap); ret = drmGetCap(device->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
if (ret == 0) if (ret == 0)
b->cursor_height = cap; device->cursor_height = cap;
else else
b->cursor_height = 64; device->cursor_height = 64;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret) { if (ret) {
weston_log("Error: drm card doesn't support universal planes!\n"); weston_log("Error: drm card doesn't support universal planes!\n");
return -1; return -1;
} }
if (!getenv("WESTON_DISABLE_ATOMIC")) { if (!getenv("WESTON_DISABLE_ATOMIC")) {
ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap); ret = drmGetCap(device->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
if (ret != 0) if (ret != 0)
cap = 0; cap = 0;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1); ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
b->atomic_modeset = ((ret == 0) && (cap == 1)); device->atomic_modeset = ((ret == 0) && (cap == 1));
} }
weston_log("DRM: %s atomic modesetting\n", weston_log("DRM: %s atomic modesetting\n",
b->atomic_modeset ? "supports" : "does not support"); device->atomic_modeset ? "supports" : "does not support");
if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) { if (!getenv("WESTON_DISABLE_GBM_MODIFIERS")) {
ret = drmGetCap(b->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap); ret = drmGetCap(device->drm.fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
if (ret == 0) if (ret == 0)
b->fb_modifiers = cap; device->fb_modifiers = cap;
} }
weston_log("DRM: %s GBM modifiers\n", weston_log("DRM: %s GBM modifiers\n",
b->fb_modifiers ? "supports" : "does not support"); device->fb_modifiers ? "supports" : "does not support");
drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
/* /*
* KMS support for hardware planes cannot properly synchronize * KMS support for hardware planes cannot properly synchronize
@@ -1489,13 +1536,13 @@ init_kms_caps(struct drm_backend *b)
* to a fraction. For cursors, it's not so bad, so they are * to a fraction. For cursors, it's not so bad, so they are
* enabled. * enabled.
*/ */
if (!b->atomic_modeset || getenv("WESTON_FORCE_RENDERER")) if (!device->atomic_modeset || getenv("WESTON_FORCE_RENDERER"))
b->sprites_are_broken = true; device->sprites_are_broken = true;
ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1); ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ASPECT_RATIO, 1);
b->aspect_ratio_supported = (ret == 0); device->aspect_ratio_supported = (ret == 0);
weston_log("DRM: %s picture aspect ratio\n", weston_log("DRM: %s picture aspect ratio\n",
b->aspect_ratio_supported ? "supports" : "does not support"); device->aspect_ratio_supported ? "supports" : "does not support");
return 0; return 0;
} }
+19 -8
View File
@@ -53,8 +53,10 @@ static long backlight_get(struct backlight *backlight, char *node)
int fd, value; int fd, value;
long ret; long ret;
if (asprintf(&path, "%s/%s", backlight->path, node) < 0) str_printf(&path, "%s/%s", backlight->path, node);
if (!path)
return -ENOMEM; return -ENOMEM;
fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
if (fd < 0) { if (fd < 0) {
ret = -1; ret = -1;
@@ -67,6 +69,9 @@ static long backlight_get(struct backlight *backlight, char *node)
goto out; goto out;
} }
if (buffer[ret - 1] == '\n')
buffer[ret - 1] = '\0';
if (!safe_strtoint(buffer, &value)) { if (!safe_strtoint(buffer, &value)) {
ret = -1; ret = -1;
goto out; goto out;
@@ -103,7 +108,8 @@ long backlight_set_brightness(struct backlight *backlight, long brightness)
int fd; int fd;
long ret; long ret;
if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0) str_printf(&path, "%s/%s", backlight->path, "brightness");
if (!path)
return -ENOMEM; return -ENOMEM;
fd = open(path, O_RDWR); fd = open(path, O_RDWR);
@@ -118,7 +124,8 @@ long backlight_set_brightness(struct backlight *backlight, long brightness)
goto out; goto out;
} }
if (asprintf(&buffer, "%ld", brightness) < 0) { str_printf(&buffer, "%ld", brightness);
if (!buffer) {
ret = -1; ret = -1;
goto out; goto out;
} }
@@ -171,7 +178,8 @@ struct backlight *backlight_init(struct udev_device *drm_device,
if (!syspath) if (!syspath)
return NULL; return NULL;
if (asprintf(&path, "%s/%s", syspath, "device") < 0) str_printf(&path, "%s/%s", syspath, "device");
if (!path)
return NULL; return NULL;
ret = readlink(path, buffer, sizeof(buffer) - 1); ret = readlink(path, buffer, sizeof(buffer) - 1);
@@ -214,11 +222,13 @@ struct backlight *backlight_init(struct udev_device *drm_device,
if (entry->d_name[0] == '.') if (entry->d_name[0] == '.')
continue; continue;
if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight", str_printf(&backlight_path, "%s/%s", "/sys/class/backlight",
entry->d_name) < 0) entry->d_name);
if (!backlight_path)
goto err; goto err;
if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) { str_printf(&path, "%s/%s", backlight_path, "type");
if (!path) {
free(backlight_path); free(backlight_path);
goto err; goto err;
} }
@@ -255,7 +265,8 @@ struct backlight *backlight_init(struct udev_device *drm_device,
free (path); free (path);
if (asprintf(&path, "%s/%s", backlight_path, "device") < 0) str_printf(&path, "%s/%s", backlight_path, "device");
if (!path)
goto err; goto err;
ret = readlink(path, buffer, sizeof(buffer) - 1); ret = readlink(path, buffer, sizeof(buffer) - 1);
+2
View File
@@ -24,6 +24,7 @@ srcs_drm = [
'fb.c', 'fb.c',
'modes.c', 'modes.c',
'kms.c', 'kms.c',
'kms-color.c',
'state-helpers.c', 'state-helpers.c',
'state-propose.c', 'state-propose.c',
linux_dmabuf_unstable_v1_protocol_c, linux_dmabuf_unstable_v1_protocol_c,
@@ -32,6 +33,7 @@ srcs_drm = [
] ]
deps_drm = [ deps_drm = [
dep_libm,
dep_libdl, dep_libdl,
dep_libweston_private, dep_libweston_private,
dep_session_helper, dep_session_helper,
+47 -25
View File
@@ -98,14 +98,15 @@ drm_subpixel_to_wayland(int drm_value)
} }
int int
drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode) drm_mode_ensure_blob(struct drm_device *device, struct drm_mode *mode)
{ {
struct drm_backend *backend = device->backend;
int ret; int ret;
if (mode->blob_id) if (mode->blob_id)
return 0; return 0;
ret = drmModeCreatePropertyBlob(backend->drm.fd, ret = drmModeCreatePropertyBlob(device->drm.fd,
&mode->mode_info, &mode->mode_info,
sizeof(mode->mode_info), sizeof(mode->mode_info),
&mode->blob_id); &mode->blob_id);
@@ -304,6 +305,8 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
* \param[out] make The monitor make (PNP ID). * \param[out] make The monitor make (PNP ID).
* \param[out] model The monitor model (name). * \param[out] model The monitor model (name).
* \param[out] serial_number The monitor serial number. * \param[out] serial_number The monitor serial number.
* \param[out] eotf_mask The monitor supported EOTF modes, combination of
* enum weston_eotf_mode bits.
* *
* Each of \c *make, \c *model and \c *serial_number are set only if the * Each of \c *make, \c *model and \c *serial_number are set only if the
* information is found in the EDID. The pointers they are set to must not * information is found in the EDID. The pointers they are set to must not
@@ -315,8 +318,10 @@ find_and_parse_output_edid(struct drm_head *head,
drmModeObjectPropertiesPtr props, drmModeObjectPropertiesPtr props,
const char **make, const char **make,
const char **model, const char **model,
const char **serial_number) const char **serial_number,
uint32_t *eotf_mask)
{ {
struct drm_device *device = head->connector.device;
drmModePropertyBlobPtr edid_blob = NULL; drmModePropertyBlobPtr edid_blob = NULL;
uint32_t blob_id; uint32_t blob_id;
int rc; int rc;
@@ -328,7 +333,7 @@ find_and_parse_output_edid(struct drm_head *head,
if (!blob_id) if (!blob_id)
return; return;
edid_blob = drmModeGetPropertyBlob(head->backend->drm.fd, blob_id); edid_blob = drmModeGetPropertyBlob(device->drm.fd, blob_id);
if (!edid_blob) if (!edid_blob)
return; return;
@@ -344,6 +349,21 @@ find_and_parse_output_edid(struct drm_head *head,
*serial_number = head->edid.serial_number; *serial_number = head->edid.serial_number;
} }
drmModeFreePropertyBlob(edid_blob); drmModeFreePropertyBlob(edid_blob);
/* TODO: parse this from EDID */
*eotf_mask = WESTON_EOTF_MODE_ALL_MASK;
}
static void
prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask)
{
const struct drm_property_info *info;
/* Without the KMS property, cannot do anything but SDR. */
info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA];
if (!head->connector.device->atomic_modeset || info->prop_id == 0)
*eotf_mask = WESTON_EOTF_MODE_SDR;
} }
static uint32_t static uint32_t
@@ -406,26 +426,26 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
* Destroys a mode, and removes it from the list. * Destroys a mode, and removes it from the list.
*/ */
static void static void
drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode) drm_output_destroy_mode(struct drm_device *device, struct drm_mode *mode)
{ {
if (mode->blob_id) if (mode->blob_id)
drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id); drmModeDestroyPropertyBlob(device->drm.fd, mode->blob_id);
wl_list_remove(&mode->base.link); wl_list_remove(&mode->base.link);
free(mode); free(mode);
} }
/** Destroy a list of drm_modes /** Destroy a list of drm_modes
* *
* @param backend The backend for releasing mode property blobs. * @param device The device for releasing mode property blobs.
* @param mode_list The list linked by drm_mode::base.link. * @param mode_list The list linked by drm_mode::base.link.
*/ */
void void
drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list) drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list)
{ {
struct drm_mode *mode, *next; struct drm_mode *mode, *next;
wl_list_for_each_safe(mode, next, mode_list, base.link) wl_list_for_each_safe(mode, next, mode_list, base.link)
drm_output_destroy_mode(backend, mode); drm_output_destroy_mode(device, mode);
} }
void void
@@ -469,16 +489,16 @@ drm_output_choose_mode(struct drm_output *output,
struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode; struct drm_mode *tmp_mode = NULL, *mode_fall_back = NULL, *mode;
enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE; enum weston_mode_aspect_ratio src_aspect = WESTON_MODE_PIC_AR_NONE;
enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE; enum weston_mode_aspect_ratio target_aspect = WESTON_MODE_PIC_AR_NONE;
struct drm_backend *b; struct drm_device *device;
b = to_drm_backend(output->base.compositor); device = output->device;
target_aspect = target_mode->aspect_ratio; target_aspect = target_mode->aspect_ratio;
src_aspect = output->base.current_mode->aspect_ratio; src_aspect = output->base.current_mode->aspect_ratio;
if (output->base.current_mode->width == target_mode->width && if (output->base.current_mode->width == target_mode->width &&
output->base.current_mode->height == target_mode->height && output->base.current_mode->height == target_mode->height &&
(output->base.current_mode->refresh == target_mode->refresh || (output->base.current_mode->refresh == target_mode->refresh ||
target_mode->refresh == 0)) { target_mode->refresh == 0)) {
if (!b->aspect_ratio_supported || src_aspect == target_aspect) if (!device->aspect_ratio_supported || src_aspect == target_aspect)
return to_drm_mode(output->base.current_mode); return to_drm_mode(output->base.current_mode);
} }
@@ -489,7 +509,7 @@ drm_output_choose_mode(struct drm_output *output,
mode->mode_info.vdisplay == target_mode->height) { mode->mode_info.vdisplay == target_mode->height) {
if (mode->base.refresh == target_mode->refresh || if (mode->base.refresh == target_mode->refresh ||
target_mode->refresh == 0) { target_mode->refresh == 0) {
if (!b->aspect_ratio_supported || if (!device->aspect_ratio_supported ||
src_aspect == target_aspect) src_aspect == target_aspect)
return mode; return mode;
else if (!mode_fall_back) else if (!mode_fall_back)
@@ -515,9 +535,12 @@ update_head_from_connector(struct drm_head *head)
const char *make = "unknown"; const char *make = "unknown";
const char *model = "unknown"; const char *model = "unknown";
const char *serial_number = "unknown"; const char *serial_number = "unknown";
uint32_t eotf_mask = WESTON_EOTF_MODE_SDR;
find_and_parse_output_edid(head, props, &make, &model, &serial_number); find_and_parse_output_edid(head, props, &make, &model, &serial_number, &eotf_mask);
weston_head_set_monitor_strings(&head->base, make, model, serial_number); weston_head_set_monitor_strings(&head->base, make, model, serial_number);
prune_eotf_modes_by_kms_support(head, &eotf_mask);
weston_head_set_supported_eotf_mask(&head->base, eotf_mask);
weston_head_set_non_desktop(&head->base, weston_head_set_non_desktop(&head->base,
check_non_desktop(connector, props)); check_non_desktop(connector, props));
weston_head_set_subpixel(&head->base, weston_head_set_subpixel(&head->base,
@@ -539,7 +562,7 @@ update_head_from_connector(struct drm_head *head)
* Find the most suitable mode to use for initial setup (or reconfiguration on * Find the most suitable mode to use for initial setup (or reconfiguration on
* hotplug etc) for a DRM output. * hotplug etc) for a DRM output.
* *
* @param backend the DRM backend * @param device the DRM device
* @param output DRM output to choose mode for * @param output DRM output to choose mode for
* @param mode Strategy and preference to use when choosing mode * @param mode Strategy and preference to use when choosing mode
* @param modeline Manually-entered mode (may be NULL) * @param modeline Manually-entered mode (may be NULL)
@@ -547,7 +570,7 @@ update_head_from_connector(struct drm_head *head)
* @returns A mode from the output's mode list, or NULL if none available * @returns A mode from the output's mode list, or NULL if none available
*/ */
static struct drm_mode * static struct drm_mode *
drm_output_choose_initial_mode(struct drm_backend *backend, drm_output_choose_initial_mode(struct drm_device *device,
struct drm_output *output, struct drm_output *output,
enum weston_drm_backend_output_mode mode, enum weston_drm_backend_output_mode mode,
const char *modeline, const char *modeline,
@@ -571,7 +594,7 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) { if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && modeline) {
n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height, n = sscanf(modeline, "%dx%d@%d %u:%u", &width, &height,
&refresh, &aspect_width, &aspect_height); &refresh, &aspect_width, &aspect_height);
if (backend->aspect_ratio_supported && n == 5) { if (device->aspect_ratio_supported && n == 5) {
if (aspect_width == 4 && aspect_height == 3) if (aspect_width == 4 && aspect_height == 3)
aspect_ratio = WESTON_MODE_PIC_AR_4_3; aspect_ratio = WESTON_MODE_PIC_AR_4_3;
else if (aspect_width == 16 && aspect_height == 9) else if (aspect_width == 16 && aspect_height == 9)
@@ -602,7 +625,7 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
if (width == drm_mode->base.width && if (width == drm_mode->base.width &&
height == drm_mode->base.height && height == drm_mode->base.height &&
(refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) { (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) {
if (!backend->aspect_ratio_supported || if (!device->aspect_ratio_supported ||
aspect_ratio == drm_mode->base.aspect_ratio) aspect_ratio == drm_mode->base.aspect_ratio)
configured = drm_mode; configured = drm_mode;
else else
@@ -714,7 +737,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
{ {
struct weston_mode *base; struct weston_mode *base;
struct drm_mode *mode = NULL; struct drm_mode *mode = NULL;
struct drm_backend *backend; struct drm_device *device = output->device;
const drmModeModeInfo *chosen = NULL; const drmModeModeInfo *chosen = NULL;
assert(info); assert(info);
@@ -728,8 +751,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
if (chosen == info) { if (chosen == info) {
assert(mode); assert(mode);
backend = to_drm_backend(output->base.compositor); drm_output_destroy_mode(device, mode);
drm_output_destroy_mode(backend, mode);
chosen = NULL; chosen = NULL;
} }
@@ -756,7 +778,7 @@ drm_output_try_add_mode(struct drm_output *output, const drmModeModeInfo *info)
static int static int
drm_output_update_modelist_from_heads(struct drm_output *output) drm_output_update_modelist_from_heads(struct drm_output *output)
{ {
struct drm_backend *backend = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct weston_head *head_base; struct weston_head *head_base;
struct drm_head *head; struct drm_head *head;
drmModeConnector *conn; drmModeConnector *conn;
@@ -765,7 +787,7 @@ drm_output_update_modelist_from_heads(struct drm_output *output)
assert(!output->base.enabled); assert(!output->base.enabled);
drm_mode_list_destroy(backend, &output->base.mode_list); drm_mode_list_destroy(device, &output->base.mode_list);
wl_list_for_each(head_base, &output->base.head_list, output_link) { wl_list_for_each(head_base, &output->base.head_list, output_link) {
head = to_drm_head(head_base); head = to_drm_head(head_base);
@@ -786,7 +808,7 @@ drm_output_set_mode(struct weston_output *base,
const char *modeline) const char *modeline)
{ {
struct drm_output *output = to_drm_output(base); struct drm_output *output = to_drm_output(base);
struct drm_backend *b = to_drm_backend(base->compositor); struct drm_device *device = output->device;
struct drm_head *head = to_drm_head(weston_output_get_first_head(base)); struct drm_head *head = to_drm_head(weston_output_get_first_head(base));
struct drm_mode *current; struct drm_mode *current;
@@ -797,7 +819,7 @@ drm_output_set_mode(struct weston_output *base,
if (drm_output_update_modelist_from_heads(output) < 0) if (drm_output_update_modelist_from_heads(output) < 0)
return -1; return -1;
current = drm_output_choose_initial_mode(b, output, mode, modeline, current = drm_output_choose_initial_mode(device, output, mode, modeline,
&head->inherited_mode); &head->inherited_mode);
if (!current) if (!current)
return -1; return -1;
+22 -7
View File
@@ -73,6 +73,8 @@ drm_plane_state_alloc(struct drm_output_state *state_output,
void void
drm_plane_state_free(struct drm_plane_state *state, bool force) drm_plane_state_free(struct drm_plane_state *state, bool force)
{ {
struct drm_device *device;
if (!state) if (!state)
return; return;
@@ -86,14 +88,17 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
* by the kernel, which means we can safely discard it. * by the kernel, which means we can safely discard it.
*/ */
if (state->damage_blob_id != 0) { if (state->damage_blob_id != 0) {
drmModeDestroyPropertyBlob(state->plane->backend->drm.fd, device = state->plane->device;
drmModeDestroyPropertyBlob(device->drm.fd,
state->damage_blob_id); state->damage_blob_id);
state->damage_blob_id = 0; state->damage_blob_id = 0;
} }
if (force || state != state->plane->state_cur) { if (force || state != state->plane->state_cur) {
drm_fb_unref(state->fb); drm_fb_unref(state->fb);
weston_buffer_reference(&state->fb_ref.buffer, NULL); weston_buffer_reference(&state->fb_ref.buffer, NULL,
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release, NULL); weston_buffer_release_reference(&state->fb_ref.release, NULL);
free(state); free(state);
} }
@@ -135,10 +140,20 @@ drm_plane_state_duplicate(struct drm_output_state *state_output,
* buffer, then we must also transfer the reference on the client * buffer, then we must also transfer the reference on the client
* buffer. */ * buffer. */
if (src->fb) { if (src->fb) {
struct weston_buffer *buffer;
dst->fb = drm_fb_ref(src->fb); dst->fb = drm_fb_ref(src->fb);
memset(&dst->fb_ref, 0, sizeof(dst->fb_ref)); memset(&dst->fb_ref, 0, sizeof(dst->fb_ref));
weston_buffer_reference(&dst->fb_ref.buffer,
src->fb_ref.buffer.buffer); if (src->fb->type == BUFFER_CLIENT ||
src->fb->type == BUFFER_DMABUF) {
buffer = src->fb_ref.buffer.buffer;
} else {
buffer = NULL;
}
weston_buffer_reference(&dst->fb_ref.buffer, buffer,
buffer ? BUFFER_MAY_BE_ACCESSED :
BUFFER_WILL_NOT_BE_ACCESSED);
weston_buffer_release_reference(&dst->fb_ref.release, weston_buffer_release_reference(&dst->fb_ref.release,
src->fb_ref.release.buffer_release); src->fb_ref.release.buffer_release);
} else { } else {
@@ -421,11 +436,11 @@ drm_output_state_free(struct drm_output_state *state)
* Allocate a new, empty, 'pending state' structure to be used across a * Allocate a new, empty, 'pending state' structure to be used across a
* repaint cycle or similar. * repaint cycle or similar.
* *
* @param backend DRM backend * @param device DRM device
* @returns Newly-allocated pending state structure * @returns Newly-allocated pending state structure
*/ */
struct drm_pending_state * struct drm_pending_state *
drm_pending_state_alloc(struct drm_backend *backend) drm_pending_state_alloc(struct drm_device *device)
{ {
struct drm_pending_state *ret; struct drm_pending_state *ret;
@@ -433,7 +448,7 @@ drm_pending_state_alloc(struct drm_backend *backend)
if (!ret) if (!ret)
return NULL; return NULL;
ret->backend = backend; ret->device = device;
wl_list_init(&ret->output_list); wl_list_init(&ret->output_list);
return ret; return ret;
+245 -417
View File
@@ -41,6 +41,7 @@
#include "color.h" #include "color.h"
#include "linux-dmabuf.h" #include "linux-dmabuf.h"
#include "presentation-time-server-protocol.h" #include "presentation-time-server-protocol.h"
#include "linux-dmabuf-unstable-v1-server-protocol.h"
enum drm_output_propose_state_mode { enum drm_output_propose_state_mode {
DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */ DRM_OUTPUT_PROPOSE_STATE_MIXED, /**< mix renderer & planes */
@@ -63,55 +64,6 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
return drm_output_propose_state_mode_as_string[mode]; return drm_output_propose_state_mode_as_string[mode];
} }
static void
drm_output_add_zpos_plane(struct drm_plane *plane, struct wl_list *planes)
{
struct drm_backend *b = plane->backend;
struct drm_plane_zpos *h_plane;
struct drm_plane_zpos *plane_zpos;
plane_zpos = zalloc(sizeof(*plane_zpos));
if (!plane_zpos)
return;
plane_zpos->plane = plane;
drm_debug(b, "\t\t\t\t[plane] plane %d added to candidate list\n",
plane->plane_id);
if (wl_list_empty(planes)) {
wl_list_insert(planes, &plane_zpos->link);
return;
}
h_plane = wl_container_of(planes->next, h_plane, link);
if (h_plane->plane->zpos_max >= plane->zpos_max) {
wl_list_insert(planes->prev, &plane_zpos->link);
} else {
struct drm_plane_zpos *p_zpos = NULL;
if (wl_list_length(planes) == 1) {
wl_list_insert(planes->prev, &plane_zpos->link);
return;
}
wl_list_for_each(p_zpos, planes, link) {
if (p_zpos->plane->zpos_max >
plane_zpos->plane->zpos_max)
break;
}
wl_list_insert(p_zpos->link.prev, &plane_zpos->link);
}
}
static void
drm_output_destroy_zpos_plane(struct drm_plane_zpos *plane_zpos)
{
wl_list_remove(&plane_zpos->link);
free(plane_zpos);
}
static bool static bool
drm_output_check_plane_has_view_assigned(struct drm_plane *plane, drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
struct drm_output_state *output_state) struct drm_output_state *output_state)
@@ -125,87 +77,79 @@ drm_output_check_plane_has_view_assigned(struct drm_plane *plane,
} }
static struct drm_plane_state * static struct drm_plane_state *
drm_output_prepare_overlay_view(struct drm_plane *plane, drm_output_try_view_on_plane(struct drm_plane *plane,
struct drm_output_state *output_state, struct drm_output_state *output_state,
struct weston_view *ev, struct weston_view *ev,
enum drm_output_propose_state_mode mode, enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos) struct drm_fb *fb, uint64_t zpos)
{ {
struct drm_output *output = output_state->output; struct drm_output *output = output_state->output;
struct weston_compositor *ec = output->base.compositor; struct weston_surface *surface = ev->surface;
struct drm_backend *b = to_drm_backend(ec); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *state = NULL; struct drm_plane_state *state = NULL;
int ret;
assert(!b->sprites_are_broken); assert(!device->sprites_are_broken);
assert(b->atomic_modeset); assert(device->atomic_modeset);
assert(fb);
if (!fb) { assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ||
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: " (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED &&
" couldn't get fb\n", ev); plane->type == WDRM_PLANE_TYPE_OVERLAY));
return NULL;
}
state = drm_output_state_get_plane(output_state, plane); state = drm_output_state_get_plane(output_state, plane);
/* we can't have a 'pending' framebuffer as never set one before reaching here */ /* we can't have a 'pending' framebuffer as never set one before reaching here */
assert(!state->fb); assert(!state->fb);
state->ev = ev;
state->output = output; state->output = output;
if (!drm_plane_state_coords_for_view(state, ev, zpos)) { if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: " drm_debug(b, "\t\t\t\t[view] not placing view %p on plane: "
"unsuitable transform\n", ev); "unsuitable transform\n", ev);
drm_plane_state_put_back(state);
state = NULL;
goto out; goto out;
} }
/* If the surface buffer has an in-fence fd, but the plane /* Should've been ensured by weston_view_matches_entire_output. */
* doesn't support fences, we can't place the buffer on this if (plane->type == WDRM_PLANE_TYPE_PRIMARY) {
* plane. */ assert(state->dest_x == 0 && state->dest_y == 0 &&
if (ev->surface->acquire_fence_fd >= 0 && state->dest_w == (unsigned) output->base.current_mode->width &&
plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) { state->dest_h == (unsigned) output->base.current_mode->height);
drm_debug(b, "\t\t\t\t[overlay] not placing view %p on overlay: "
"no in-fence support\n", ev);
drm_plane_state_put_back(state);
state = NULL;
goto out;
} }
/* We hold one reference for the lifetime of this function; from /* We hold one reference for the lifetime of this function; from
* calling drm_fb_get_from_view() in drm_output_prepare_plane_view(), * calling drm_fb_get_from_view() in drm_output_prepare_plane_view(),
* so, we take another reference here to live within the state. */ * so, we take another reference here to live within the state. */
state->ev = ev;
state->fb = drm_fb_ref(fb); state->fb = drm_fb_ref(fb);
state->in_fence_fd = ev->surface->acquire_fence_fd; state->in_fence_fd = ev->surface->acquire_fence_fd;
/* In planes-only mode, we don't have an incremental state to /* In planes-only mode, we don't have an incremental state to
* test against, so we just hope it'll work. */ * test against, so we just hope it'll work. */
if (mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) { if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY &&
drm_debug(b, "\t\t\t[overlay] provisionally placing " drm_pending_state_test(output_state->pending_state) != 0) {
"view %p on overlay %lu in planes-only mode\n", drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
"atomic test failed\n",
ev, (unsigned long) plane->plane_id); ev, (unsigned long) plane->plane_id);
goto out; goto out;
} }
ret = drm_pending_state_test(output_state->pending_state); drm_debug(b, "\t\t\t[view] provisionally placing view %p on plane %lu\n",
if (ret == 0) {
drm_debug(b, "\t\t\t[overlay] provisionally placing "
"view %p on overlay %d in mixed mode\n",
ev, plane->plane_id);
goto out;
}
drm_debug(b, "\t\t\t[overlay] not placing view %p on overlay %lu "
"in mixed mode: kernel test failed\n",
ev, (unsigned long) plane->plane_id); ev, (unsigned long) plane->plane_id);
drm_plane_state_put_back(state); /* Take a reference on the buffer so that we don't release it
state = NULL; * back to the client until we're done with it; cursor buffers
* don't require a reference since we copy them. */
assert(state->fb_ref.buffer.buffer == NULL);
assert(state->fb_ref.release.buffer_release == NULL);
weston_buffer_reference(&state->fb_ref.buffer,
surface->buffer_ref.buffer,
BUFFER_MAY_BE_ACCESSED);
weston_buffer_release_reference(&state->fb_ref.release,
surface->buffer_release_ref.buffer_release);
return state;
out: out:
return state; drm_plane_state_put_back(state);
return NULL;
} }
#ifdef BUILD_DRM_GBM #ifdef BUILD_DRM_GBM
@@ -218,18 +162,18 @@ out:
static void static void
cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev) cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
{ {
struct drm_backend *b = plane_state->plane->backend; struct drm_output *output = plane_state->output;
struct drm_device *device = output->device;
struct gbm_bo *bo = plane_state->fb->bo; struct gbm_bo *bo = plane_state->fb->bo;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer; struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
uint32_t buf[b->cursor_width * b->cursor_height]; uint32_t buf[device->cursor_width * device->cursor_height];
int32_t stride; int32_t stride;
uint8_t *s; uint8_t *s;
int i; int i;
assert(buffer && buffer->shm_buffer); assert(buffer && buffer->shm_buffer);
assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource)); assert(buffer->width <= device->cursor_width);
assert(buffer->width <= b->cursor_width); assert(buffer->height <= device->cursor_height);
assert(buffer->height <= b->cursor_height);
memset(buf, 0, sizeof buf); memset(buf, 0, sizeof buf);
stride = wl_shm_buffer_get_stride(buffer->shm_buffer); stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
@@ -237,7 +181,7 @@ cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
wl_shm_buffer_begin_access(buffer->shm_buffer); wl_shm_buffer_begin_access(buffer->shm_buffer);
for (i = 0; i < buffer->height; i++) for (i = 0; i < buffer->height; i++)
memcpy(buf + i * b->cursor_width, memcpy(buf + i * device->cursor_width,
s + i * stride, s + i * stride,
buffer->width * 4); buffer->width * 4);
wl_shm_buffer_end_access(buffer->shm_buffer); wl_shm_buffer_end_access(buffer->shm_buffer);
@@ -251,32 +195,23 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
struct weston_view *ev, uint64_t zpos) struct weston_view *ev, uint64_t zpos)
{ {
struct drm_output *output = output_state->output; struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane *plane = output->cursor_plane; struct drm_plane *plane = output->cursor_plane;
struct drm_plane_state *plane_state; struct drm_plane_state *plane_state;
bool needs_update = false; bool needs_update = false;
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
const char *p_name = drm_output_get_plane_type_name(plane); const char *p_name = drm_output_get_plane_type_name(plane);
assert(!b->cursors_are_broken); assert(!device->cursors_are_broken);
assert(plane);
if (!plane) assert(plane->state_cur->complete);
return NULL; assert(!plane->state_cur->output || plane->state_cur->output == output);
if (!plane->state_cur->complete)
return NULL;
if (plane->state_cur->output && plane->state_cur->output != output)
return NULL;
/* We use GBM to import SHM buffers. */ /* We use GBM to import SHM buffers. */
if (b->gbm == NULL) assert(b->gbm);
return NULL;
plane_state = drm_output_state_get_plane(output_state, plane); plane_state = drm_output_state_get_plane(output_state, plane);
assert(!plane_state->fb);
if (plane_state && plane_state->fb)
return NULL;
/* We can't scale with the legacy API, and we don't try to account for /* We can't scale with the legacy API, and we don't try to account for
* simple cropping/translation in cursor_bo_update. */ * simple cropping/translation in cursor_bo_update. */
@@ -287,19 +222,9 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
goto err; goto err;
} }
if (buffer->width > b->cursor_width ||
buffer->height > b->cursor_height) {
drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
"(surface buffer (%dx%d) larger than permitted"
" (%dx%d))\n", p_name, ev, p_name,
buffer->width, buffer->height,
b->cursor_width, b->cursor_height);
goto err;
}
if (plane_state->src_x != 0 || plane_state->src_y != 0 || if (plane_state->src_x != 0 || plane_state->src_y != 0 ||
plane_state->src_w > (unsigned) b->cursor_width << 16 || plane_state->src_w > (unsigned) device->cursor_width << 16 ||
plane_state->src_h > (unsigned) b->cursor_height << 16 || plane_state->src_h > (unsigned) device->cursor_height << 16 ||
plane_state->src_w != plane_state->dest_w << 16 || plane_state->src_w != plane_state->dest_w << 16 ||
plane_state->src_h != plane_state->dest_h << 16) { plane_state->src_h != plane_state->dest_h << 16) {
drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane " drm_debug(b, "\t\t\t\t[%s] not assigning view %p to %s plane "
@@ -338,10 +263,10 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
* a buffer which is always cursor_width x cursor_height, even if the * a buffer which is always cursor_width x cursor_height, even if the
* surface we want to promote is actually smaller than this. Manually * surface we want to promote is actually smaller than this. Manually
* mangle the plane state to deal with this. */ * mangle the plane state to deal with this. */
plane_state->src_w = b->cursor_width << 16; plane_state->src_w = device->cursor_width << 16;
plane_state->src_h = b->cursor_height << 16; plane_state->src_h = device->cursor_height << 16;
plane_state->dest_w = b->cursor_width; plane_state->dest_w = device->cursor_width;
plane_state->dest_h = b->cursor_height; plane_state->dest_h = device->cursor_height;
drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n", drm_debug(b, "\t\t\t\t[%s] provisionally assigned view %p to cursor\n",
p_name, ev); p_name, ev);
@@ -361,190 +286,6 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
} }
#endif #endif
static struct drm_plane_state *
drm_output_prepare_scanout_view(struct drm_output_state *output_state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
{
struct drm_output *output = output_state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_plane *scanout_plane = output->scanout_plane;
struct drm_plane_state *state;
const char *p_name = drm_output_get_plane_type_name(scanout_plane);
assert(!b->sprites_are_broken);
assert(b->atomic_modeset);
assert(mode == DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY);
/* Check the view spans exactly the output size, calculated in the
* logical co-ordinate space. */
if (!weston_view_matches_output_entirely(ev, &output->base)) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" view does not match output entirely\n",
p_name, ev, p_name);
return NULL;
}
/* If the surface buffer has an in-fence fd, but the plane doesn't
* support fences, we can't place the buffer on this plane. */
if (ev->surface->acquire_fence_fd >= 0 &&
scanout_plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"no in-fence support\n", p_name, ev, p_name);
return NULL;
}
if (!fb) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" couldn't get fb\n", p_name, ev, p_name);
return NULL;
}
state = drm_output_state_get_plane(output_state, scanout_plane);
/* The only way we can already have a buffer in the scanout plane is
* if we are in mixed mode, or if a client buffer has already been
* placed into scanout. The former case will never call into here,
* and in the latter case, the view must have been marked as occluded,
* meaning we should never have ended up here. */
assert(!state->fb);
/* take another reference here to live within the state */
state->fb = drm_fb_ref(fb);
state->ev = ev;
state->output = output;
if (!drm_plane_state_coords_for_view(state, ev, zpos)) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"unsuitable transform\n", p_name, ev, p_name);
goto err;
}
if (state->dest_x != 0 || state->dest_y != 0 ||
state->dest_w != (unsigned) output->base.current_mode->width ||
state->dest_h != (unsigned) output->base.current_mode->height) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
" invalid plane state\n", p_name, ev, p_name);
goto err;
}
state->in_fence_fd = ev->surface->acquire_fence_fd;
/* In plane-only mode, we don't need to test the state now, as we
* will only test it once at the end. */
return state;
err:
drm_plane_state_put_back(state);
return NULL;
}
static struct drm_plane_state *
drm_output_try_view_on_plane(struct drm_plane *plane,
struct drm_output_state *state,
struct weston_view *ev,
enum drm_output_propose_state_mode mode,
struct drm_fb *fb, uint64_t zpos)
{
struct drm_backend *b = state->pending_state->backend;
struct weston_output *wet_output = &state->output->base;
bool view_matches_entire_output, scanout_has_view_assigned;
struct drm_plane *scanout_plane = state->output->scanout_plane;
struct drm_plane_state *ps = NULL;
const char *p_name = drm_output_get_plane_type_name(plane);
struct weston_surface *surface = ev->surface;
enum {
NO_PLANES, /* generic err-handle */
NO_PLANES_ACCEPTED,
PLACED_ON_PLANE,
} availability = NO_PLANES;
/* sanity checks in case we over/underflow zpos or pass incorrect
* values */
assert(zpos <= plane->zpos_max ||
zpos != DRM_PLANE_ZPOS_INVALID_PLANE);
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
if (b->cursors_are_broken) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_cursor_view(state, ev, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
case WDRM_PLANE_TYPE_OVERLAY:
/* do not attempt to place it in the overlay if we don't have
* anything in the scanout/primary and the view doesn't cover
* the entire output */
view_matches_entire_output =
weston_view_matches_output_entirely(ev, wet_output);
scanout_has_view_assigned =
drm_output_check_plane_has_view_assigned(scanout_plane,
state);
if (view_matches_entire_output && !scanout_has_view_assigned) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_overlay_view(plane, state, ev, mode,
fb, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
case WDRM_PLANE_TYPE_PRIMARY:
if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY) {
availability = NO_PLANES_ACCEPTED;
goto out;
}
ps = drm_output_prepare_scanout_view(state, ev, mode,
fb, zpos);
if (ps)
availability = PLACED_ON_PLANE;
break;
default:
assert(0);
break;
}
out:
switch (availability) {
case NO_PLANES:
/* set initial to this catch-all case, such that
* prepare_cursor/overlay/scanout() should have/contain the
* reason for failling */
break;
case NO_PLANES_ACCEPTED:
drm_debug(b, "\t\t\t\t[plane] plane %d refusing to "
"place view %p in %s\n",
plane->plane_id, ev, p_name);
break;
case PLACED_ON_PLANE:
/* Take a reference on the buffer so that we don't release it
* back to the client until we're done with it; cursor buffers
* don't require a reference since we copy them. */
assert(ps->fb_ref.buffer.buffer == NULL);
assert(ps->fb_ref.release.buffer_release == NULL);
if (ps->plane->type == WDRM_PLANE_TYPE_CURSOR) {
assert(ps->fb->type == BUFFER_CURSOR);
} else if (fb->type == BUFFER_CLIENT || fb->type == BUFFER_DMABUF) {
assert(ps->fb == fb);
weston_buffer_reference(&ps->fb_ref.buffer,
surface->buffer_ref.buffer);
weston_buffer_release_reference(&ps->fb_ref.release,
surface->buffer_release_ref.buffer_release);
}
break;
}
return ps;
}
static void static void
drm_output_check_zpos_plane_states(struct drm_output_state *state) drm_output_check_zpos_plane_states(struct drm_output_state *state)
{ {
@@ -585,12 +326,13 @@ drm_output_check_zpos_plane_states(struct drm_output_state *state)
} }
static bool static bool
dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev, dmabuf_feedback_maybe_update(struct drm_device *device, struct weston_view *ev,
uint32_t try_view_on_plane_failure_reasons) uint32_t try_view_on_plane_failure_reasons)
{ {
struct weston_dmabuf_feedback *dmabuf_feedback = ev->surface->dmabuf_feedback; struct weston_dmabuf_feedback *dmabuf_feedback = ev->surface->dmabuf_feedback;
struct weston_dmabuf_feedback_tranche *scanout_tranche; struct weston_dmabuf_feedback_tranche *scanout_tranche;
dev_t scanout_dev = b->drm.devnum; struct drm_backend *b = device->backend;
dev_t scanout_dev = device->drm.devnum;
uint32_t scanout_flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT; uint32_t scanout_flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT;
uint32_t action_needed = ACTION_NEEDED_NONE; uint32_t action_needed = ACTION_NEEDED_NONE;
struct timespec current_time, delta_time; struct timespec current_time, delta_time;
@@ -603,7 +345,8 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
(FAILURE_REASONS_ADD_FB_FAILED | (FAILURE_REASONS_ADD_FB_FAILED |
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE | FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE |
FAILURE_REASONS_DMABUF_MODIFIER_INVALID | FAILURE_REASONS_DMABUF_MODIFIER_INVALID |
FAILURE_REASONS_GBM_BO_IMPORT_FAILED)) FAILURE_REASONS_GBM_BO_IMPORT_FAILED |
FAILURE_REASONS_GBM_BO_GET_HANDLE_FAILED))
action_needed |= ACTION_NEEDED_ADD_SCANOUT_TRANCHE; action_needed |= ACTION_NEEDED_ADD_SCANOUT_TRANCHE;
assert(action_needed != (ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE | assert(action_needed != (ACTION_NEEDED_REMOVE_SCANOUT_TRANCHE |
@@ -681,58 +424,161 @@ dmabuf_feedback_maybe_update(struct drm_backend *b, struct weston_view *ev,
} }
static struct drm_plane_state * static struct drm_plane_state *
drm_output_prepare_plane_view(struct drm_output_state *state, drm_output_find_plane_for_view(struct drm_output_state *state,
struct weston_view *ev, struct weston_paint_node *pnode,
enum drm_output_propose_state_mode mode, enum drm_output_propose_state_mode mode,
struct drm_plane_state *scanout_state, struct drm_plane_state *scanout_state,
uint64_t current_lowest_zpos, uint64_t current_lowest_zpos)
uint32_t *try_view_on_plane_failure_reasons)
{ {
struct drm_output *output = state->output; struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_plane_state *ps = NULL; struct drm_plane_state *ps = NULL;
struct drm_plane *plane; struct drm_plane *plane;
struct drm_plane_zpos *p_zpos, *p_zpos_next;
struct wl_list zpos_candidate_list;
struct weston_view *ev = pnode->view;
struct weston_buffer *buffer; struct weston_buffer *buffer;
struct wl_shm_buffer *shmbuf; struct drm_fb *fb = NULL;
struct drm_fb *fb;
wl_list_init(&zpos_candidate_list); bool view_matches_entire_output, scanout_has_view_assigned;
uint32_t possible_plane_mask = 0;
pnode->try_view_on_plane_failure_reasons = FAILURE_REASONS_NONE;
/* check view for valid buffer, doesn't make sense to even try */ /* check view for valid buffer, doesn't make sense to even try */
if (!weston_view_has_valid_buffer(ev)) if (!weston_view_has_valid_buffer(ev)) {
return ps; pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
buffer = ev->surface->buffer_ref.buffer; buffer = ev->surface->buffer_ref.buffer;
shmbuf = wl_shm_buffer_get(buffer->resource); if (buffer->type == WESTON_BUFFER_SOLID) {
fb = drm_fb_get_from_view(state, ev, try_view_on_plane_failure_reasons); pnode->try_view_on_plane_failure_reasons |=
if (!shmbuf && !fb) FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL; return NULL;
} else if (buffer->type == WESTON_BUFFER_SHM) {
if (!output->cursor_plane || device->cursors_are_broken) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
/* Even though this is a SHM buffer, pixel_format stores the
* format code as DRM FourCC */
if (buffer->pixel_format->format != DRM_FORMAT_ARGB8888) {
drm_debug(b, "\t\t\t\t[view] not placing view %p on "
"plane; SHM buffers must be ARGB8888 for "
"cursor view\n", ev);
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
if (buffer->width > device->cursor_width ||
buffer->height > device->cursor_height) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(buffer (%dx%d) too large for cursor plane)\n",
ev, buffer->width, buffer->height);
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
return NULL;
}
possible_plane_mask = (1 << output->cursor_plane->plane_idx);
} else {
if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p "
"to plane: renderer-only mode\n", ev);
return NULL;
}
fb = drm_fb_get_from_view(state, ev,
&pnode->try_view_on_plane_failure_reasons);
if (!fb) {
drm_debug(b, "\t\t\t[view] couldn't get FB for view: 0x%lx\n",
(unsigned long) pnode->try_view_on_plane_failure_reasons);
return NULL;
}
possible_plane_mask = fb->plane_mask;
}
view_matches_entire_output =
weston_view_matches_output_entirely(ev, &output->base);
scanout_has_view_assigned =
drm_output_check_plane_has_view_assigned(output->scanout_plane,
state);
/* assemble a list with possible candidates */ /* assemble a list with possible candidates */
wl_list_for_each(plane, &b->plane_list, link) { wl_list_for_each(plane, &device->plane_list, link) {
const char *p_name = drm_output_get_plane_type_name(plane);
uint64_t zpos;
if (possible_plane_mask == 0)
break;
if (!(possible_plane_mask & (1 << plane->plane_idx)))
continue;
possible_plane_mask &= ~(1 << plane->plane_idx);
switch (plane->type) {
case WDRM_PLANE_TYPE_CURSOR:
assert(buffer->shm_buffer);
assert(plane == output->cursor_plane);
break;
case WDRM_PLANE_TYPE_PRIMARY:
assert(fb);
if (plane != output->scanout_plane)
continue;
if (mode != DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY)
continue;
if (!view_matches_entire_output)
continue;
break;
case WDRM_PLANE_TYPE_OVERLAY:
assert(fb);
assert(mode != DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY);
/* if the view covers the whole output, put it in the
* scanout plane, not overlay */
if (view_matches_entire_output &&
!scanout_has_view_assigned)
continue;
break;
default:
assert(false && "unknown plane type");
}
if (!drm_plane_is_available(plane, output)) if (!drm_plane_is_available(plane, output))
continue; continue;
if (drm_output_check_plane_has_view_assigned(plane, state)) { if (drm_output_check_plane_has_view_assigned(plane, state)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to" drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
" candidate list: view already assigned " "another view already assigned\n",
"to a plane\n", plane->plane_id); plane->plane_id);
continue; continue;
} }
if (plane->zpos_min >= current_lowest_zpos) { if (plane->zpos_min >= current_lowest_zpos) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to " drm_debug(b, "\t\t\t\t[plane] not trying plane %d: "
"candidate list: minimum zpos (%"PRIu64") " "plane's minimum zpos (%"PRIu64") above "
"plane's above current lowest zpos " "current lowest zpos (%"PRIu64")\n",
"(%"PRIu64")\n", plane->plane_id, plane->plane_id, plane->zpos_min,
plane->zpos_min, current_lowest_zpos); current_lowest_zpos);
continue; continue;
} }
/* If the surface buffer has an in-fence fd, but the plane doesn't
* support fences, we can't place the buffer on this plane. */
if (ev->surface->acquire_fence_fd >= 0 &&
plane->props[WDRM_PLANE_IN_FENCE_FD].prop_id == 0) {
drm_debug(b, "\t\t\t\t[%s] not placing view %p on %s: "
"no in-fence support\n", p_name, ev, p_name);
return NULL;
}
if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) { if (mode == DRM_OUTPUT_PROPOSE_STATE_MIXED) {
assert(scanout_state != NULL); assert(scanout_state != NULL);
if (scanout_state->zpos >= plane->zpos_max) { if (scanout_state->zpos >= plane->zpos_max) {
@@ -746,49 +592,6 @@ drm_output_prepare_plane_view(struct drm_output_state *state,
} }
} }
if (mode == DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY &&
(plane->type == WDRM_PLANE_TYPE_OVERLAY ||
plane->type == WDRM_PLANE_TYPE_PRIMARY)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: renderer-only mode\n",
plane->plane_id);
continue;
}
if (plane->type == WDRM_PLANE_TYPE_CURSOR &&
(!shmbuf || wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)) {
drm_debug(b, "\t\t\t\t[plane] not adding plane %d, type cursor to "
"candidate list: cursor planes only support ARGB8888"
"wl_shm buffers and the view buffer is of another type\n",
plane->plane_id);
continue;
}
if (plane->type != WDRM_PLANE_TYPE_CURSOR &&
(!fb || !(fb->plane_mask & (1 << plane->plane_idx)))) {
*try_view_on_plane_failure_reasons |=
FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
drm_debug(b, "\t\t\t\t[plane] not adding plane %d to "
"candidate list: invalid pixel format\n",
plane->plane_id);
continue;
}
drm_output_add_zpos_plane(plane, &zpos_candidate_list);
}
/* go over the potential candidate list and try to find a possible
* plane suitable for \c ev; start with the highest zpos value of a
* plane to maximize our chances, but do note we pass the zpos value
* based on current tracked value by \c current_lowest_zpos_in_use */
while (!wl_list_empty(&zpos_candidate_list)) {
struct drm_plane_zpos *head_p_zpos =
wl_container_of(zpos_candidate_list.next,
head_p_zpos, link);
struct drm_plane *plane = head_p_zpos->plane;
const char *p_name = drm_output_get_plane_type_name(plane);
uint64_t zpos;
if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE) if (current_lowest_zpos == DRM_PLANE_ZPOS_INVALID_PLANE)
zpos = plane->zpos_max; zpos = plane->zpos_max;
else else
@@ -798,20 +601,32 @@ drm_output_prepare_plane_view(struct drm_output_state *state,
"from candidate list, type: %s\n", "from candidate list, type: %s\n",
plane->plane_id, p_name); plane->plane_id, p_name);
if (plane->type == WDRM_PLANE_TYPE_CURSOR) {
ps = drm_output_prepare_cursor_view(state, ev, zpos);
} else {
ps = drm_output_try_view_on_plane(plane, state, ev, ps = drm_output_try_view_on_plane(plane, state, ev,
mode, fb, zpos); mode, fb, zpos);
drm_output_destroy_zpos_plane(head_p_zpos); }
if (ps) { if (ps) {
drm_debug(b, "\t\t\t\t[view] view %p has been placed to " drm_debug(b, "\t\t\t\t[view] view %p has been placed to "
"%s plane with computed zpos %"PRIu64"\n", "%s plane with computed zpos %"PRIu64"\n",
ev, p_name, zpos); ev, p_name, zpos);
break; break;
} }
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_PLANES_REJECTED;
} }
wl_list_for_each_safe(p_zpos, p_zpos_next, &zpos_candidate_list, link) if (!ps &&
drm_output_destroy_zpos_plane(p_zpos); pnode->try_view_on_plane_failure_reasons == FAILURE_REASONS_NONE) {
pnode->try_view_on_plane_failure_reasons |=
FAILURE_REASONS_NO_PLANES_AVAILABLE;
}
/* if we have a plane state, it has its own ref to the fb; if not then
* we drop ours here */
drm_fb_unref(fb); drm_fb_unref(fb);
return ps; return ps;
} }
@@ -822,7 +637,8 @@ drm_output_propose_state(struct weston_output *output_base,
enum drm_output_propose_state_mode mode) enum drm_output_propose_state_mode mode)
{ {
struct drm_output *output = to_drm_output(output_base); struct drm_output *output = to_drm_output(output_base);
struct drm_backend *b = to_drm_backend(output->base.compositor); struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct weston_paint_node *pnode; struct weston_paint_node *pnode;
struct drm_output_state *state; struct drm_output_state *state;
struct drm_plane_state *scanout_state = NULL; struct drm_plane_state *scanout_state = NULL;
@@ -957,12 +773,29 @@ drm_output_propose_state(struct weston_output *output_base,
force_renderer = true; force_renderer = true;
} }
if (!b->gbm) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(GBM not available)\n", ev);
force_renderer = true;
}
if (!weston_view_has_valid_buffer(ev)) { if (!weston_view_has_valid_buffer(ev)) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane " drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(no buffer available)\n", ev); "(no buffer available)\n", ev);
force_renderer = true; force_renderer = true;
} }
/* We can support this with the 'CRTC background colour' property,
* if it is fullscreen (i.e. we disable the primary plane), and
* opaque (as it is only shown in the absence of any covering
* plane, not as a replacement for the primary plane per se). */
if (ev->surface->buffer_ref.buffer &&
ev->surface->buffer_ref.buffer->type == WESTON_BUFFER_SOLID) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
"(solid-colour surface)\n", ev);
force_renderer = true;
}
if (pnode->surf_xform.transform != NULL || if (pnode->surf_xform.transform != NULL ||
!pnode->surf_xform.identity_pipeline) { !pnode->surf_xform.identity_pipeline) {
drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane " drm_debug(b, "\t\t\t\t[view] not assigning view %p to plane "
@@ -996,15 +829,9 @@ drm_output_propose_state(struct weston_output *output_base,
if (!force_renderer) { if (!force_renderer) {
drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n", drm_debug(b, "\t\t\t[plane] started with zpos %"PRIu64"\n",
current_lowest_zpos); current_lowest_zpos);
ps = drm_output_prepare_plane_view(state, ev, mode, ps = drm_output_find_plane_for_view(state, pnode, mode,
scanout_state, scanout_state,
current_lowest_zpos, current_lowest_zpos);
&pnode->try_view_on_plane_failure_reasons);
/* If we were able to place the view in a plane, set
* failure reasons to none. */
if (ps)
pnode->try_view_on_plane_failure_reasons =
FAILURE_REASONS_NONE;
} else { } else {
/* We are forced to place the view in the renderer, set /* We are forced to place the view in the renderer, set
* the failure reason accordingly. */ * the failure reason accordingly. */
@@ -1088,21 +915,24 @@ err:
} }
void void
drm_assign_planes(struct weston_output *output_base, void *repaint_data) drm_assign_planes(struct weston_output *output_base)
{ {
struct drm_backend *b = to_drm_backend(output_base->compositor);
struct drm_pending_state *pending_state = repaint_data;
struct drm_output *output = to_drm_output(output_base); struct drm_output *output = to_drm_output(output_base);
struct drm_device *device = output->device;
struct drm_backend *b = device->backend;
struct drm_pending_state *pending_state = device->repaint_data;
struct drm_output_state *state = NULL; struct drm_output_state *state = NULL;
struct drm_plane_state *plane_state; struct drm_plane_state *plane_state;
struct weston_paint_node *pnode; struct weston_paint_node *pnode;
struct weston_plane *primary = &output_base->compositor->primary_plane; struct weston_plane *primary = &output_base->compositor->primary_plane;
enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY; enum drm_output_propose_state_mode mode = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY;
assert(output);
drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n", drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
output_base->name, (unsigned long) output_base->id); output_base->name, (unsigned long) output_base->id);
if (!b->sprites_are_broken && !output->virtual) { if (!device->sprites_are_broken && !output->virtual && b->gbm) {
drm_debug(b, "\t[repaint] trying planes-only build state\n"); drm_debug(b, "\t[repaint] trying planes-only build state\n");
state = drm_output_propose_state(output_base, pending_state, mode); state = drm_output_propose_state(output_base, pending_state, mode);
if (!state) { if (!state) {
@@ -1144,26 +974,24 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
/* Update dmabuf-feedback if needed */ /* Update dmabuf-feedback if needed */
if (ev->surface->dmabuf_feedback) if (ev->surface->dmabuf_feedback)
dmabuf_feedback_maybe_update(b, ev, dmabuf_feedback_maybe_update(device, ev,
pnode->try_view_on_plane_failure_reasons); pnode->try_view_on_plane_failure_reasons);
pnode->try_view_on_plane_failure_reasons = FAILURE_REASONS_NONE; pnode->try_view_on_plane_failure_reasons = FAILURE_REASONS_NONE;
/* Test whether this buffer can ever go into a plane: /* Test whether this buffer can ever go into a plane:
* non-shm, or small enough to be a cursor. * non-shm, or small enough to be a cursor. */
*
* Also, keep a reference when using the pixman renderer.
* That makes it possible to do a seamless switch to the GL
* renderer and since the pixman renderer keeps a reference
* to the buffer anyway, there is no side effects.
*/
if (b->use_pixman ||
(weston_view_has_valid_buffer(ev) &&
(!wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
(ev->surface->width <= b->cursor_width &&
ev->surface->height <= b->cursor_height))))
ev->surface->keep_buffer = true;
else
ev->surface->keep_buffer = false; ev->surface->keep_buffer = false;
if (weston_view_has_valid_buffer(ev)) {
struct weston_buffer *buffer =
ev->surface->buffer_ref.buffer;
if (buffer->type == WESTON_BUFFER_DMABUF ||
buffer->type == WESTON_BUFFER_RENDERER_OPAQUE)
ev->surface->keep_buffer = true;
else if (buffer->type == WESTON_BUFFER_SHM &&
(ev->surface->width <= device->cursor_width &&
ev->surface->height <= device->cursor_height))
ev->surface->keep_buffer = true;
}
/* This is a bit unpleasant, but lacking a temporary place to /* This is a bit unpleasant, but lacking a temporary place to
* hang a plane off the view, we have to do a nested walk. * hang a plane off the view, we have to do a nested walk.
-998
View File
@@ -1,998 +0,0 @@
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2012 Raspberry Pi Foundation
* Copyright © 2013 Philip Withnall
*
* 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 <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <assert.h>
#include <libudev.h>
#include "shared/helpers.h"
#include <libweston/libweston.h>
#include <libweston/backend-fbdev.h>
#include "launcher-util.h"
#include "pixman-renderer.h"
#include "libinput-seat.h"
#include "presentation-time-server-protocol.h"
struct fbdev_backend {
struct weston_backend base;
struct weston_compositor *compositor;
uint32_t prev_state;
struct udev *udev;
struct udev_input input;
uint32_t output_transform;
struct wl_listener session_listener;
};
struct fbdev_screeninfo {
unsigned int x_resolution; /* pixels, visible area */
unsigned int y_resolution; /* pixels, visible area */
unsigned int width_mm; /* visible screen width in mm */
unsigned int height_mm; /* visible screen height in mm */
unsigned int bits_per_pixel;
size_t buffer_length; /* length of frame buffer memory in bytes */
size_t line_length; /* length of a line in bytes */
char id[16]; /* screen identifier */
pixman_format_code_t pixel_format; /* frame buffer pixel format */
unsigned int refresh_rate; /* Hertz */
};
struct fbdev_head {
struct weston_head base;
/* Frame buffer details. */
char *device;
struct fbdev_screeninfo fb_info;
};
struct fbdev_output {
struct fbdev_backend *backend;
struct weston_output base;
struct weston_mode mode;
struct wl_event_source *finish_frame_timer;
/* framebuffer mmap details */
size_t buffer_length;
void *fb;
/* pixman details. */
pixman_image_t *hw_surface;
};
static const char default_seat[] = "seat0";
static inline struct fbdev_head *
to_fbdev_head(struct weston_head *base)
{
return container_of(base, struct fbdev_head, base);
}
static inline struct fbdev_output *
to_fbdev_output(struct weston_output *base)
{
return container_of(base, struct fbdev_output, base);
}
static inline struct fbdev_backend *
to_fbdev_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct fbdev_backend, base);
}
static struct fbdev_head *
fbdev_output_get_head(struct fbdev_output *output)
{
if (wl_list_length(&output->base.head_list) != 1)
return NULL;
return container_of(output->base.head_list.next,
struct fbdev_head, base.output_link);
}
static int
fbdev_output_start_repaint_loop(struct weston_output *output)
{
struct timespec ts;
weston_compositor_read_presentation_clock(output->compositor, &ts);
weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
return 0;
}
static int
fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
void *repaint_data)
{
struct fbdev_output *output = to_fbdev_output(base);
struct weston_compositor *ec = output->base.compositor;
/* Repaint the damaged region onto the back buffer. */
pixman_renderer_output_set_buffer(base, output->hw_surface);
ec->renderer->repaint_output(base, damage);
/* Update the damage region. */
pixman_region32_subtract(&ec->primary_plane.damage,
&ec->primary_plane.damage, damage);
/* Schedule the end of the frame. We do not sync this to the frame
* buffer clock because users who want that should be using the DRM
* compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
* panning, which is broken in most kernel drivers.
*
* Finish the frame synchronised to the specified refresh rate. The
* refresh rate is given in mHz and the interval in ms. */
wl_event_source_timer_update(output->finish_frame_timer,
1000000 / output->mode.refresh);
return 0;
}
static int
finish_frame_handler(void *data)
{
struct fbdev_output *output = data;
struct timespec ts;
weston_compositor_read_presentation_clock(output->base.compositor, &ts);
weston_output_finish_frame(&output->base, &ts, 0);
return 1;
}
static pixman_format_code_t
calculate_pixman_format(struct fb_var_screeninfo *vinfo,
struct fb_fix_screeninfo *finfo)
{
/* Calculate the pixman format supported by the frame buffer from the
* buffer's metadata. Return 0 if no known pixman format is supported
* (since this has depth 0 it's guaranteed to not conflict with any
* actual pixman format).
*
* Documentation on the vinfo and finfo structures:
* http://www.mjmwired.net/kernel/Documentation/fb/api.txt
*
* TODO: Try a bit harder to support other formats, including setting
* the preferred format in the hardware. */
int type;
weston_log("Calculating pixman format from:\n"
STAMP_SPACE " - type: %i (aux: %i)\n"
STAMP_SPACE " - visual: %i\n"
STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
finfo->type, finfo->type_aux, finfo->visual,
vinfo->bits_per_pixel, vinfo->grayscale,
vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
vinfo->green.offset, vinfo->green.length,
vinfo->green.msb_right,
vinfo->blue.offset, vinfo->blue.length,
vinfo->blue.msb_right,
vinfo->transp.offset, vinfo->transp.length,
vinfo->transp.msb_right);
/* We only handle packed formats at the moment. */
if (finfo->type != FB_TYPE_PACKED_PIXELS)
return 0;
/* We only handle true-colour frame buffers at the moment. */
switch(finfo->visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_DIRECTCOLOR:
if (vinfo->grayscale != 0)
return 0;
break;
default:
return 0;
}
/* We only support formats with MSBs on the left. */
if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
vinfo->blue.msb_right != 0)
return 0;
/* Work out the format type from the offsets. We only support RGBA, ARGB
* and ABGR at the moment. */
type = PIXMAN_TYPE_OTHER;
if ((vinfo->transp.offset >= vinfo->red.offset ||
vinfo->transp.length == 0) &&
vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset)
type = PIXMAN_TYPE_ARGB;
else if (vinfo->red.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->blue.offset &&
vinfo->blue.offset >= vinfo->transp.offset)
type = PIXMAN_TYPE_RGBA;
else if (vinfo->transp.offset >= vinfo->blue.offset &&
vinfo->blue.offset >= vinfo->green.offset &&
vinfo->green.offset >= vinfo->red.offset)
type = PIXMAN_TYPE_ABGR;
if (type == PIXMAN_TYPE_OTHER)
return 0;
/* Build the format. */
return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
vinfo->transp.length,
vinfo->red.length,
vinfo->green.length,
vinfo->blue.length);
}
static int
calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
{
uint64_t quot;
/* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
quot *= vinfo->pixclock;
if (quot > 0) {
uint64_t refresh_rate;
refresh_rate = 1000000000000000LLU / quot;
if (refresh_rate > 200000)
refresh_rate = 200000; /* cap at 200 Hz */
if (refresh_rate >= 1000) /* at least 1 Hz */
return refresh_rate;
}
return 60 * 1000; /* default to 60 Hz */
}
static int
fbdev_query_screen_info(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
struct fb_fix_screeninfo fixinfo;
/* Probe the device for screen information. */
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Store the pertinent data. */
info->x_resolution = varinfo.xres;
info->y_resolution = varinfo.yres;
info->width_mm = varinfo.width;
info->height_mm = varinfo.height;
info->bits_per_pixel = varinfo.bits_per_pixel;
info->buffer_length = fixinfo.smem_len;
info->line_length = fixinfo.line_length;
strncpy(info->id, fixinfo.id, sizeof(info->id));
info->id[sizeof(info->id)-1] = '\0';
info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
info->refresh_rate = calculate_refresh_rate(&varinfo);
if (info->pixel_format == 0) {
weston_log("Frame buffer uses an unsupported format.\n");
return -1;
}
return 1;
}
static int
fbdev_set_screen_info(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
/* Grab the current screen information. */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* Update the information. */
varinfo.xres = info->x_resolution;
varinfo.yres = info->y_resolution;
varinfo.width = info->width_mm;
varinfo.height = info->height_mm;
varinfo.bits_per_pixel = info->bits_per_pixel;
/* Try to set up an ARGB (x8r8g8b8) pixel format. */
varinfo.grayscale = 0;
varinfo.transp.offset = 24;
varinfo.transp.length = 0;
varinfo.transp.msb_right = 0;
varinfo.red.offset = 16;
varinfo.red.length = 8;
varinfo.red.msb_right = 0;
varinfo.green.offset = 8;
varinfo.green.length = 8;
varinfo.green.msb_right = 0;
varinfo.blue.offset = 0;
varinfo.blue.length = 8;
varinfo.blue.msb_right = 0;
/* Set the device's screen information. */
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
return -1;
}
return 1;
}
static int
fbdev_wakeup_screen(int fd, struct fbdev_screeninfo *info)
{
struct fb_var_screeninfo varinfo;
/* Grab the current screen information. */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
return -1;
}
/* force the framebuffer to wake up */
varinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
/* Set the device's screen information. */
if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
return -1;
}
return 1;
}
/* Returns an FD for the frame buffer device. */
static int
fbdev_frame_buffer_open(const char *fb_dev,
struct fbdev_screeninfo *screen_info)
{
int fd = -1;
weston_log("Opening fbdev frame buffer.\n");
/* Open the frame buffer device. */
fd = open(fb_dev, O_RDWR | O_CLOEXEC);
if (fd < 0) {
weston_log("Failed to open frame buffer device %s: %s\n",
fb_dev, strerror(errno));
return -1;
}
/* Grab the screen info. */
if (fbdev_query_screen_info(fd, screen_info) < 0) {
weston_log("Failed to get frame buffer info: %s\n",
strerror(errno));
close(fd);
return -1;
}
/* Attempt to wake up the framebuffer device, needed for secondary
* framebuffer devices */
if (fbdev_wakeup_screen(fd, screen_info) < 0) {
weston_log("Failed to activate framebuffer display. "
"Attempting to open output anyway.\n");
}
return fd;
}
/* Closes the FD on success or failure. */
static int
fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
{
struct fbdev_head *head;
int retval = -1;
head = fbdev_output_get_head(output);
weston_log("Mapping fbdev frame buffer.\n");
/* Map the frame buffer. Write-only mode, since we don't want to read
* anything back (because it's slow). */
output->buffer_length = head->fb_info.buffer_length;
output->fb = mmap(NULL, output->buffer_length,
PROT_WRITE, MAP_SHARED, fd, 0);
if (output->fb == MAP_FAILED) {
weston_log("Failed to mmap frame buffer: %s\n",
strerror(errno));
output->fb = NULL;
goto out_close;
}
/* Create a pixman image to wrap the memory mapped frame buffer. */
output->hw_surface =
pixman_image_create_bits(head->fb_info.pixel_format,
head->fb_info.x_resolution,
head->fb_info.y_resolution,
output->fb,
head->fb_info.line_length);
if (output->hw_surface == NULL) {
weston_log("Failed to create surface for frame buffer.\n");
goto out_unmap;
}
/* Success! */
retval = 0;
out_unmap:
if (retval != 0 && output->fb != NULL) {
munmap(output->fb, output->buffer_length);
output->fb = NULL;
}
out_close:
if (fd >= 0)
close(fd);
return retval;
}
static void
fbdev_frame_buffer_unmap(struct fbdev_output *output)
{
if (!output->fb) {
assert(!output->hw_surface);
return;
}
weston_log("Unmapping fbdev frame buffer.\n");
if (output->hw_surface)
pixman_image_unref(output->hw_surface);
output->hw_surface = NULL;
if (munmap(output->fb, output->buffer_length) < 0)
weston_log("Failed to munmap frame buffer: %s\n",
strerror(errno));
output->fb = NULL;
}
static int
fbdev_output_attach_head(struct weston_output *output_base,
struct weston_head *head_base)
{
struct fbdev_output *output = to_fbdev_output(output_base);
struct fbdev_head *head = to_fbdev_head(head_base);
/* Clones not supported. */
if (!wl_list_empty(&output->base.head_list))
return -1;
/* only one static mode in list */
output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
output->mode.width = head->fb_info.x_resolution;
output->mode.height = head->fb_info.y_resolution;
output->mode.refresh = head->fb_info.refresh_rate;
wl_list_init(&output->base.mode_list);
wl_list_insert(&output->base.mode_list, &output->mode.link);
output->base.current_mode = &output->mode;
return 0;
}
static void fbdev_output_destroy(struct weston_output *base);
static int
fbdev_output_enable(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
struct fbdev_head *head;
int fb_fd;
struct wl_event_loop *loop;
const struct pixman_renderer_output_options options = {
.use_shadow = true,
};
head = fbdev_output_get_head(output);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
return -1;
}
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
return -1;
}
output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
output->base.repaint = fbdev_output_repaint;
if (pixman_renderer_output_create(&output->base, &options) < 0)
goto out_hw_surface;
loop = wl_display_get_event_loop(backend->compositor->wl_display);
output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output);
weston_log("fbdev output %d×%d px\n",
output->mode.width, output->mode.height);
weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
output->mode.refresh / 1000);
return 0;
out_hw_surface:
fbdev_frame_buffer_unmap(output);
return -1;
}
static int
fbdev_output_disable(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
if (!base->enabled)
return 0;
wl_event_source_remove(output->finish_frame_timer);
output->finish_frame_timer = NULL;
pixman_renderer_output_destroy(&output->base);
fbdev_frame_buffer_unmap(output);
return 0;
}
static struct fbdev_head *
fbdev_head_create(struct fbdev_backend *backend, const char *device)
{
struct fbdev_head *head;
int fb_fd;
head = zalloc(sizeof *head);
if (!head)
return NULL;
head->device = strdup(device);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer head failed.\n");
goto out_free;
}
close(fb_fd);
weston_head_init(&head->base, "fbdev");
weston_head_set_connection_status(&head->base, true);
weston_head_set_monitor_strings(&head->base, "unknown",
head->fb_info.id, NULL);
weston_head_set_subpixel(&head->base, WL_OUTPUT_SUBPIXEL_UNKNOWN);
weston_head_set_physical_size(&head->base, head->fb_info.width_mm,
head->fb_info.height_mm);
weston_compositor_add_head(backend->compositor, &head->base);
weston_log("Created head '%s' for device %s (%s)\n",
head->base.name, head->device, head->base.model);
return head;
out_free:
free(head->device);
free(head);
return NULL;
}
static void
fbdev_head_destroy(struct fbdev_head *head)
{
weston_head_release(&head->base);
free(head->device);
free(head);
}
static struct weston_output *
fbdev_output_create(struct weston_compositor *compositor,
const char *name)
{
struct fbdev_output *output;
weston_log("Creating fbdev output.\n");
output = zalloc(sizeof *output);
if (output == NULL)
return NULL;
output->backend = to_fbdev_backend(compositor);
weston_output_init(&output->base, compositor, name);
output->base.destroy = fbdev_output_destroy;
output->base.disable = fbdev_output_disable;
output->base.enable = fbdev_output_enable;
output->base.attach_head = fbdev_output_attach_head;
weston_compositor_add_pending_output(&output->base, compositor);
return &output->base;
}
static void
fbdev_output_destroy(struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
weston_log("Destroying fbdev output.\n");
fbdev_output_disable(base);
/* Remove the output. */
weston_output_release(&output->base);
free(output);
}
/* strcmp()-style return values. */
static int
compare_screen_info (const struct fbdev_screeninfo *a,
const struct fbdev_screeninfo *b)
{
if (a->x_resolution == b->x_resolution &&
a->y_resolution == b->y_resolution &&
a->width_mm == b->width_mm &&
a->height_mm == b->height_mm &&
a->bits_per_pixel == b->bits_per_pixel &&
a->pixel_format == b->pixel_format &&
a->refresh_rate == b->refresh_rate)
return 0;
return 1;
}
static int
fbdev_output_reenable(struct fbdev_backend *backend,
struct weston_output *base)
{
struct fbdev_output *output = to_fbdev_output(base);
struct fbdev_head *head;
struct fbdev_screeninfo new_screen_info;
int fb_fd;
head = fbdev_output_get_head(output);
weston_log("Re-enabling fbdev output.\n");
assert(output->base.enabled);
/* Create the frame buffer. */
fb_fd = fbdev_frame_buffer_open(head->device, &new_screen_info);
if (fb_fd < 0) {
weston_log("Creating frame buffer failed.\n");
return -1;
}
/* Check whether the frame buffer details have changed since we were
* disabled. */
if (compare_screen_info(&head->fb_info, &new_screen_info) != 0) {
/* Perform a mode-set to restore the old mode. */
if (fbdev_set_screen_info(fb_fd, &head->fb_info) < 0) {
weston_log("Failed to restore mode settings. "
"Attempting to re-open output anyway.\n");
}
close(fb_fd);
/* Disable and enable the output so that resources depending on
* the frame buffer X/Y resolution (such as the shadow buffer)
* are re-initialised. */
fbdev_output_disable(&output->base);
return fbdev_output_enable(&output->base);
}
/* Map the device if it has the same details as before. */
if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
weston_log("Mapping frame buffer failed.\n");
return -1;
}
return 0;
}
static void
fbdev_backend_destroy(struct weston_compositor *base)
{
struct fbdev_backend *backend = to_fbdev_backend(base);
struct weston_head *head, *next;
udev_input_destroy(&backend->input);
/* Destroy the output. */
weston_compositor_shutdown(base);
wl_list_for_each_safe(head, next, &base->head_list, compositor_link)
fbdev_head_destroy(to_fbdev_head(head));
/* Chain up. */
weston_launcher_destroy(base->launcher);
udev_unref(backend->udev);
free(backend);
}
static void
session_notify(struct wl_listener *listener, void *data)
{
struct weston_compositor *compositor = data;
struct fbdev_backend *backend = to_fbdev_backend(compositor);
struct weston_output *output;
if (compositor->session_active) {
weston_log("entering VT\n");
compositor->state = backend->prev_state;
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_output_reenable(backend, output);
}
weston_compositor_damage_all(compositor);
udev_input_enable(&backend->input);
} else {
weston_log("leaving VT\n");
udev_input_disable(&backend->input);
wl_list_for_each(output, &compositor->output_list, link) {
fbdev_frame_buffer_unmap(to_fbdev_output(output));
}
backend->prev_state = compositor->state;
weston_compositor_offscreen(compositor);
/* If we have a repaint scheduled (from the idle handler), make
* sure we cancel that so we don't try to pageflip when we're
* vt switched away. The OFFSCREEN state will prevent
* further attempts at repainting. When we switch
* back, we schedule a repaint, which will process
* pending frame callbacks. */
wl_list_for_each(output,
&compositor->output_list, link) {
output->repaint_needed = false;
}
}
}
static char *
find_framebuffer_device(struct fbdev_backend *b, const char *seat)
{
struct udev_enumerate *e;
struct udev_list_entry *entry;
const char *path, *device_seat, *id;
char *fb_device_path = NULL;
struct udev_device *device, *fb_device, *pci;
e = udev_enumerate_new(b->udev);
udev_enumerate_add_match_subsystem(e, "graphics");
udev_enumerate_add_match_sysname(e, "fb[0-9]*");
udev_enumerate_scan_devices(e);
fb_device = NULL;
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
bool is_boot_vga = false;
path = udev_list_entry_get_name(entry);
device = udev_device_new_from_syspath(b->udev, path);
if (!device)
continue;
device_seat = udev_device_get_property_value(device, "ID_SEAT");
if (!device_seat)
device_seat = default_seat;
if (strcmp(device_seat, seat)) {
udev_device_unref(device);
continue;
}
pci = udev_device_get_parent_with_subsystem_devtype(device,
"pci", NULL);
if (pci) {
id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && !strcmp(id, "1"))
is_boot_vga = true;
}
/* If a framebuffer device was found, and this device isn't
* the boot-VGA device, don't use it. */
if (!is_boot_vga && fb_device) {
udev_device_unref(device);
continue;
}
/* There can only be one boot_vga device. Try to use it
* at all costs. */
if (is_boot_vga) {
if (fb_device)
udev_device_unref(fb_device);
fb_device = device;
break;
}
/* Per the (!is_boot_vga && fb_device) test above, only
* trump existing saved devices with boot-VGA devices, so if
* the test ends up here, this must be the first device seen. */
assert(!fb_device);
fb_device = device;
}
udev_enumerate_unref(e);
if (fb_device) {
fb_device_path = strdup(udev_device_get_devnode(fb_device));
udev_device_unref(fb_device);
}
return fb_device_path;
}
static struct fbdev_backend *
fbdev_backend_create(struct weston_compositor *compositor,
struct weston_fbdev_backend_config *param)
{
struct fbdev_backend *backend;
const char *seat_id = default_seat;
const char *session_seat;
session_seat = getenv("XDG_SEAT");
if (session_seat)
seat_id = session_seat;
if (param->seat_id)
seat_id = param->seat_id;
weston_log("initializing fbdev backend\n");
weston_log("warning: the fbdev backend is deprecated, please migrate "
"to the DRM backend\n");
backend = zalloc(sizeof *backend);
if (backend == NULL)
return NULL;
backend->compositor = compositor;
compositor->backend = &backend->base;
if (weston_compositor_set_presentation_clock_software(
compositor) < 0)
goto out_compositor;
backend->udev = udev_new();
if (backend->udev == NULL) {
weston_log("Failed to initialize udev context.\n");
goto out_compositor;
}
if (!param->device)
param->device = find_framebuffer_device(backend, seat_id);
if (!param->device) {
weston_log("fatal: no framebuffer devices detected.\n");
goto out_udev;
}
/* Set up the TTY. */
backend->session_listener.notify = session_notify;
wl_signal_add(&compositor->session_signal,
&backend->session_listener);
compositor->launcher =
weston_launcher_connect(compositor, param->tty, seat_id, false);
if (!compositor->launcher) {
weston_log("fatal: fbdev backend should be run using "
"weston-launch binary, or your system should "
"provide the logind D-Bus API.\n");
goto out_udev;
}
backend->base.destroy = fbdev_backend_destroy;
backend->base.create_output = fbdev_output_create;
backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
weston_setup_vt_switch_bindings(compositor);
if (pixman_renderer_init(compositor) < 0)
goto out_launcher;
if (!fbdev_head_create(backend, param->device))
goto out_launcher;
free(param->device);
udev_input_init(&backend->input, compositor, backend->udev,
seat_id, param->configure_device);
return backend;
out_launcher:
free(param->device);
weston_launcher_destroy(compositor->launcher);
out_udev:
udev_unref(backend->udev);
out_compositor:
weston_compositor_shutdown(compositor);
free(backend);
return NULL;
}
static void
config_init_to_defaults(struct weston_fbdev_backend_config *config)
{
config->tty = 0; /* default to current tty */
config->device = NULL;
config->seat_id = NULL;
}
WL_EXPORT int
weston_backend_init(struct weston_compositor *compositor,
struct weston_backend_config *config_base)
{
struct fbdev_backend *b;
struct weston_fbdev_backend_config config = {{ 0, }};
if (config_base == NULL ||
config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
weston_log("fbdev backend config structure is invalid\n");
return -1;
}
config_init_to_defaults(&config);
memcpy(&config, config_base, config_base->struct_size);
b = fbdev_backend_create(compositor, &config);
if (b == NULL)
return -1;
return 0;
}
-33
View File
@@ -1,33 +0,0 @@
if not get_option('deprecated-backend-fbdev')
subdir_done()
endif
warning('Support for the deprecated fbdev backend is enabled.')
warning('This feature will be removed in a future version.')
config_h.set('BUILD_FBDEV_COMPOSITOR', '1')
srcs_fbdev = [
'fbdev.c',
presentation_time_server_protocol_h,
]
deps_fbdev = [
dep_libweston_private,
dep_session_helper,
dep_libinput_backend,
dependency('libudev', version: '>= 136'),
]
plugin_fbdev = shared_library(
'fbdev-backend',
srcs_fbdev,
include_directories: common_inc,
dependencies: deps_fbdev,
name_prefix: '',
install: true,
install_dir: dir_module_libweston
)
env_modmap += 'fbdev-backend.so=@0@;'.format(plugin_fbdev.full_path())
install_headers(backend_fbdev_h, subdir: dir_include_libweston_install)
+54 -19
View File
@@ -37,6 +37,7 @@
#include <libweston/backend-headless.h> #include <libweston/backend-headless.h>
#include "shared/helpers.h" #include "shared/helpers.h"
#include "linux-explicit-synchronization.h" #include "linux-explicit-synchronization.h"
#include "pixel-formats.h"
#include "pixman-renderer.h" #include "pixman-renderer.h"
#include "renderer-gl/gl-renderer.h" #include "renderer-gl/gl-renderer.h"
#include "shared/weston-drm-fourcc.h" #include "shared/weston-drm-fourcc.h"
@@ -70,24 +71,33 @@ struct headless_output {
struct weston_mode mode; struct weston_mode mode;
struct wl_event_source *finish_frame_timer; struct wl_event_source *finish_frame_timer;
uint32_t *image_buf;
pixman_image_t *image; pixman_image_t *image;
}; };
static const uint32_t headless_formats[] = { static const uint32_t headless_formats[] = {
DRM_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, /* default for pixman-renderer */
DRM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888,
}; };
static void
headless_head_destroy(struct weston_head *base);
static inline struct headless_head * static inline struct headless_head *
to_headless_head(struct weston_head *base) to_headless_head(struct weston_head *base)
{ {
if (base->backend_id != headless_head_destroy)
return NULL;
return container_of(base, struct headless_head, base); return container_of(base, struct headless_head, base);
} }
static void
headless_output_destroy(struct weston_output *base);
static inline struct headless_output * static inline struct headless_output *
to_headless_output(struct weston_output *base) to_headless_output(struct weston_output *base)
{ {
if (base->destroy != headless_output_destroy)
return NULL;
return container_of(base, struct headless_output, base); return container_of(base, struct headless_output, base);
} }
@@ -122,11 +132,14 @@ finish_frame_handler(void *data)
static int static int
headless_output_repaint(struct weston_output *output_base, headless_output_repaint(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct headless_output *output = to_headless_output(output_base); struct headless_output *output = to_headless_output(output_base);
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
ec->renderer->repaint_output(&output->base, damage); ec->renderer->repaint_output(&output->base, damage);
@@ -152,18 +165,21 @@ headless_output_disable_pixman(struct headless_output *output)
{ {
pixman_renderer_output_destroy(&output->base); pixman_renderer_output_destroy(&output->base);
pixman_image_unref(output->image); pixman_image_unref(output->image);
free(output->image_buf);
} }
static int static int
headless_output_disable(struct weston_output *base) headless_output_disable(struct weston_output *base)
{ {
struct headless_output *output = to_headless_output(base); struct headless_output *output = to_headless_output(base);
struct headless_backend *b = to_headless_backend(base->compositor); struct headless_backend *b;
assert(output);
if (!output->base.enabled) if (!output->base.enabled)
return 0; return 0;
b = to_headless_backend(base->compositor);
wl_event_source_remove(output->finish_frame_timer); wl_event_source_remove(output->finish_frame_timer);
switch (b->renderer_type) { switch (b->renderer_type) {
@@ -185,6 +201,8 @@ headless_output_destroy(struct weston_output *base)
{ {
struct headless_output *output = to_headless_output(base); struct headless_output *output = to_headless_output(base);
assert(output);
headless_output_disable(&output->base); headless_output_disable(&output->base);
weston_output_release(&output->base); weston_output_release(&output->base);
@@ -214,20 +232,20 @@ headless_output_enable_gl(struct headless_output *output)
static int static int
headless_output_enable_pixman(struct headless_output *output) headless_output_enable_pixman(struct headless_output *output)
{ {
const struct pixel_format_info *pfmt;
const struct pixman_renderer_output_options options = { const struct pixman_renderer_output_options options = {
.use_shadow = true, .use_shadow = true,
}; };
output->image_buf = malloc(output->base.current_mode->width * pfmt = pixel_format_get_info(headless_formats[0]);
output->base.current_mode->height * 4);
if (!output->image_buf)
return -1;
output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8, output->image =
pixman_image_create_bits_no_clear(pfmt->pixman_format,
output->base.current_mode->width, output->base.current_mode->width,
output->base.current_mode->height, output->base.current_mode->height,
output->image_buf, NULL, 0);
output->base.current_mode->width * 4); if (!output->image)
return -1;
if (pixman_renderer_output_create(&output->base, &options) < 0) if (pixman_renderer_output_create(&output->base, &options) < 0)
goto err_renderer; goto err_renderer;
@@ -238,7 +256,6 @@ headless_output_enable_pixman(struct headless_output *output)
err_renderer: err_renderer:
pixman_image_unref(output->image); pixman_image_unref(output->image);
free(output->image_buf);
return -1; return -1;
} }
@@ -247,10 +264,14 @@ static int
headless_output_enable(struct weston_output *base) headless_output_enable(struct weston_output *base)
{ {
struct headless_output *output = to_headless_output(base); struct headless_output *output = to_headless_output(base);
struct headless_backend *b = to_headless_backend(base->compositor); struct headless_backend *b;
struct wl_event_loop *loop; struct wl_event_loop *loop;
int ret = 0; int ret = 0;
assert(output);
b = to_headless_backend(base->compositor);
loop = wl_display_get_event_loop(b->compositor->wl_display); loop = wl_display_get_event_loop(b->compositor->wl_display);
output->finish_frame_timer = output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output); wl_event_loop_add_timer(loop, finish_frame_handler, output);
@@ -287,6 +308,9 @@ headless_output_set_size(struct weston_output *base,
struct weston_head *head; struct weston_head *head;
int output_width, output_height; int output_width, output_height;
if (!output)
return -1;
/* We can only be called once. */ /* We can only be called once. */
assert(!output->base.current_mode); assert(!output->base.current_mode);
@@ -361,7 +385,12 @@ headless_head_create(struct weston_compositor *compositor,
return -1; return -1;
weston_head_init(&head->base, name); weston_head_init(&head->base, name);
head->base.backend_id = headless_head_destroy;
weston_head_set_connection_status(&head->base, true); weston_head_set_connection_status(&head->base, true);
weston_head_set_supported_eotf_mask(&head->base,
WESTON_EOTF_MODE_ALL_MASK);
/* Ideally all attributes of the head would be set here, so that the /* Ideally all attributes of the head would be set here, so that the
* user has all the information when deciding to create outputs. * user has all the information when deciding to create outputs.
@@ -374,8 +403,12 @@ headless_head_create(struct weston_compositor *compositor,
} }
static void static void
headless_head_destroy(struct headless_head *head) headless_head_destroy(struct weston_head *base)
{ {
struct headless_head *head = to_headless_head(base);
assert(head);
weston_head_release(&head->base); weston_head_release(&head->base);
free(head); free(head);
} }
@@ -388,8 +421,10 @@ headless_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec); weston_compositor_shutdown(ec);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
headless_head_destroy(to_headless_head(base)); if (to_headless_head(base))
headless_head_destroy(base);
}
free(b); free(b);
} }
+17 -5
View File
@@ -4,24 +4,36 @@ endif
config_h.set('BUILD_RDP_COMPOSITOR', '1') config_h.set('BUILD_RDP_COMPOSITOR', '1')
dep_frdp = dependency('freerdp2', version: '>= 2.2.0', required: false) dep_frdp = dependency('freerdp2', version: '>= 2.3.0', required: false)
if not dep_frdp.found() if not dep_frdp.found()
error('RDP-backend requires freerdp >= 2.2.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') error('RDP-backend requires freerdp >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif endif
dep_wpr = dependency('winpr2', version: '>= 2.2.0', required: false) dep_frdp_server = dependency('freerdp-server2', version: '>= 2.3.0', required: false)
if not dep_frdp_server.found()
error('RDP-backend requires freerdp-server2 >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif
dep_wpr = dependency('winpr2', version: '>= 2.3.0', required: false)
if not dep_wpr.found() if not dep_wpr.found()
error('RDP-backend requires winpr >= 2.2.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') error('RDP-backend requires winpr >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.')
endif endif
deps_rdp = [ deps_rdp = [
dep_libweston_private, dep_libweston_private,
dep_frdp, dep_frdp,
dep_frdp_server,
dep_wpr, dep_wpr,
] ]
srcs_rdp = [
'rdp.c',
'rdpclip.c',
'rdputil.c',
]
plugin_rdp = shared_library( plugin_rdp = shared_library(
'rdp-backend', 'rdp-backend',
'rdp.c', srcs_rdp,
include_directories: common_inc, include_directories: common_inc,
dependencies: deps_rdp, dependencies: deps_rdp,
name_prefix: '', name_prefix: '',
File diff suppressed because it is too large Load Diff
+263
View File
@@ -0,0 +1,263 @@
/*
* Copyright © 2013 Hardening <rdp.effort@gmail.com>
* Copyright © 2020 Microsoft
*
* 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.
*/
#ifndef RDP_H
#define RDP_H
#include <freerdp/version.h>
#include <freerdp/freerdp.h>
#include <freerdp/listener.h>
#include <freerdp/update.h>
#include <freerdp/input.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/locale/keyboard.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/cliprdr.h>
#include <libweston/libweston.h>
#include <libweston/backend-rdp.h>
#include <libweston/weston-log.h>
#include "backend.h"
#include "shared/helpers.h"
#include "shared/string-helpers.h"
#define MAX_FREERDP_FDS 32
#define DEFAULT_AXIS_STEP_DISTANCE 10
#define DEFAULT_PIXEL_FORMAT PIXEL_FORMAT_BGRA32
/* https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardtype
* defines a keyboard type that isn't currently defined in FreeRDP, but is
* available for RDP connections */
#ifndef KBD_TYPE_KOREAN
#define KBD_TYPE_KOREAN 8
#endif
/* WinPR's GetVirtualKeyCodeFromVirtualScanCode() can't handle hangul/hanja keys */
/* 0x1f1 and 0x1f2 keys are only exists on Korean 103 keyboard (Type 8:SubType 6) */
/* From Linux's keyboard driver at drivers/input/keyboard/atkbd.c */
#define ATKBD_RET_HANJA 0xf1
#define ATKBD_RET_HANGEUL 0xf2
struct rdp_output;
struct rdp_backend {
struct weston_backend base;
struct weston_compositor *compositor;
freerdp_listener *listener;
struct wl_event_source *listener_events[MAX_FREERDP_FDS];
struct rdp_output *output;
struct weston_log_scope *debug;
struct weston_log_scope *verbose;
struct weston_log_scope *clipboard_debug;
struct weston_log_scope *clipboard_verbose;
struct wl_list peers;
char *server_cert;
char *server_key;
char *rdp_key;
int tls_enabled;
int no_clients_resize;
int force_no_compression;
bool remotefx_codec;
int external_listener_fd;
int rdp_monitor_refresh_rate;
pid_t compositor_tid;
rdp_audio_in_setup audio_in_setup;
rdp_audio_in_teardown audio_in_teardown;
rdp_audio_out_setup audio_out_setup;
rdp_audio_out_teardown audio_out_teardown;
};
enum peer_item_flags {
RDP_PEER_ACTIVATED = (1 << 0),
RDP_PEER_OUTPUT_ENABLED = (1 << 1),
};
struct rdp_peers_item {
int flags;
freerdp_peer *peer;
struct weston_seat *seat;
struct wl_list link;
};
struct rdp_head {
struct weston_head base;
};
struct rdp_output {
struct weston_output base;
struct wl_event_source *finish_frame_timer;
pixman_image_t *shadow_surface;
};
struct rdp_peer_context {
rdpContext _p;
struct rdp_backend *rdpBackend;
struct wl_event_source *events[MAX_FREERDP_FDS + 1]; /* +1 for WTSVirtualChannelManagerGetFileDescriptor */
RFX_CONTEXT *rfx_context;
wStream *encode_stream;
RFX_RECT *rfx_rects;
NSC_CONTEXT *nsc_context;
struct rdp_peers_item item;
bool button_state[5];
int verticalAccumWheelRotationPrecise;
int verticalAccumWheelRotationDiscrete;
int horizontalAccumWheelRotationPrecise;
int horizontalAccumWheelRotationDiscrete;
HANDLE vcm;
/* list of outstanding event_source sent from FreeRDP thread to display loop.*/
int loop_task_event_source_fd;
struct wl_event_source *loop_task_event_source;
pthread_mutex_t loop_task_list_mutex;
struct wl_list loop_task_list; /* struct rdp_loop_task::link */
/* Clipboard support */
CliprdrServerContext *clipboard_server_context;
void *audio_in_private;
void *audio_out_private;
struct rdp_clipboard_data_source *clipboard_client_data_source;
struct rdp_clipboard_data_source *clipboard_inflight_client_data_source;
struct wl_listener clipboard_selection_listener;
};
typedef struct rdp_peer_context RdpPeerContext;
typedef void (*rdp_loop_task_func_t)(bool freeOnly, void *data);
struct rdp_loop_task {
struct wl_list link;
RdpPeerContext *peerCtx;
rdp_loop_task_func_t func;
};
#define rdp_debug_verbose(b, ...) \
rdp_debug_print(b->verbose, false, __VA_ARGS__)
#define rdp_debug_verbose_continue(b, ...) \
rdp_debug_print(b->verbose, true, __VA_ARGS__)
#define rdp_debug(b, ...) \
rdp_debug_print(b->debug, false, __VA_ARGS__)
#define rdp_debug_continue(b, ...) \
rdp_debug_print(b->debug, true, __VA_ARGS__)
#define rdp_debug_clipboard_verbose(b, ...) \
rdp_debug_print(b->clipboard_verbose, false, __VA_ARGS__)
#define rdp_debug_clipboard_verbose_continue(b, ...) \
rdp_debug_print(b->clipboard_verbose, true, __VA_ARGS__)
#define rdp_debug_clipboard(b, ...) \
rdp_debug_print(b->clipboard_debug, false, __VA_ARGS__)
#define rdp_debug_clipboard_continue(b, ...) \
rdp_debug_print(b->clipboard_debug, true, __VA_ARGS__)
/* rdputil.c */
void
rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...);
int
rdp_wl_array_read_fd(struct wl_array *array, int fd);
void
convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType, UINT32 KeyboardSubType, UINT32 KeyboardLayout, struct xkb_rule_names *xkbRuleNames);
void
assert_compositor_thread(struct rdp_backend *b);
void
assert_not_compositor_thread(struct rdp_backend *b);
bool
rdp_event_loop_add_fd(struct wl_event_loop *loop,
int fd, uint32_t mask,
wl_event_loop_fd_func_t func,
void *data,
struct wl_event_source **event_source);
void
rdp_dispatch_task_to_display_loop(RdpPeerContext *peerCtx,
rdp_loop_task_func_t func,
struct rdp_loop_task *task);
bool
rdp_initialize_dispatch_task_event_source(RdpPeerContext *peerCtx);
void
rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx);
/* rdpclip.c */
int
rdp_clipboard_init(freerdp_peer *client);
void
rdp_clipboard_destroy(RdpPeerContext *peerCtx);
void
rdp_head_destroy(struct weston_head *base);
static inline struct rdp_head *
to_rdp_head(struct weston_head *base)
{
if (base->backend_id != rdp_head_destroy)
return NULL;
return container_of(base, struct rdp_head, base);
}
void
rdp_output_destroy(struct weston_output *base);
static inline struct rdp_output *
to_rdp_output(struct weston_output *base)
{
if (base->destroy != rdp_output_destroy)
return NULL;
return container_of(base, struct rdp_output, base);
}
static inline struct rdp_backend *
to_rdp_backend(struct weston_compositor *base)
{
return container_of(base->backend, struct rdp_backend, base);
}
#endif
File diff suppressed because it is too large Load Diff
+262
View File
@@ -0,0 +1,262 @@
/*
* Copyright © 2020 Microsoft
*
* 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "rdp.h"
static int cached_tm_mday = -1;
void rdp_debug_print(struct weston_log_scope *log_scope, bool cont, char *fmt, ...)
{
char timestr[128];
int len_va;
char *str;
if (!log_scope || !weston_log_scope_is_enabled(log_scope))
return;
va_list ap;
va_start(ap, fmt);
if (cont) {
weston_log_scope_vprintf(log_scope, fmt, ap);
goto end;
}
weston_log_timestamp(timestr, sizeof(timestr), &cached_tm_mday);
len_va = vasprintf(&str, fmt, ap);
if (len_va >= 0) {
weston_log_scope_printf(log_scope, "%s %s",
timestr, str);
free(str);
} else {
const char *oom = "Out of memory";
weston_log_scope_printf(log_scope, "%s %s",
timestr, oom);
}
end:
va_end(ap);
}
void
assert_compositor_thread(struct rdp_backend *b)
{
assert(b->compositor_tid == gettid());
}
void
assert_not_compositor_thread(struct rdp_backend *b)
{
assert(b->compositor_tid != gettid());
}
bool
rdp_event_loop_add_fd(struct wl_event_loop *loop,
int fd, uint32_t mask,
wl_event_loop_fd_func_t func,
void *data, struct wl_event_source **event_source)
{
*event_source = wl_event_loop_add_fd(loop, fd, 0, func, data);
if (!*event_source) {
weston_log("%s: wl_event_loop_add_fd failed.\n", __func__);
return false;
}
wl_event_source_fd_update(*event_source, mask);
return true;
}
void
rdp_dispatch_task_to_display_loop(RdpPeerContext *peerCtx,
rdp_loop_task_func_t func,
struct rdp_loop_task *task)
{
/* this function is ONLY used to queue the task from FreeRDP thread,
* and the task to be processed at wayland display loop thread. */
assert_not_compositor_thread(peerCtx->rdpBackend);
task->peerCtx = peerCtx;
task->func = func;
pthread_mutex_lock(&peerCtx->loop_task_list_mutex);
/* this inserts at head */
wl_list_insert(&peerCtx->loop_task_list, &task->link);
pthread_mutex_unlock(&peerCtx->loop_task_list_mutex);
eventfd_write(peerCtx->loop_task_event_source_fd, 1);
}
static int
rdp_dispatch_task(int fd, uint32_t mask, void *arg)
{
RdpPeerContext *peerCtx = (RdpPeerContext *)arg;
struct rdp_loop_task *task, *tmp;
eventfd_t dummy;
/* this must be called back at wayland display loop thread */
assert_compositor_thread(peerCtx->rdpBackend);
eventfd_read(peerCtx->loop_task_event_source_fd, &dummy);
pthread_mutex_lock(&peerCtx->loop_task_list_mutex);
/* dequeue the first task which is at last, so use reverse. */
assert(!wl_list_empty(&peerCtx->loop_task_list));
wl_list_for_each_reverse_safe(task, tmp, &peerCtx->loop_task_list, link) {
wl_list_remove(&task->link);
break;
}
pthread_mutex_unlock(&peerCtx->loop_task_list_mutex);
/* Dispatch and task will be freed by caller. */
task->func(false, task);
return 0;
}
bool
rdp_initialize_dispatch_task_event_source(RdpPeerContext *peerCtx)
{
struct rdp_backend *b = peerCtx->rdpBackend;
struct wl_event_loop *loop;
bool ret;
if (pthread_mutex_init(&peerCtx->loop_task_list_mutex, NULL) == -1) {
weston_log("%s: pthread_mutex_init failed. %s\n", __func__, strerror(errno));
goto error_mutex;
}
assert(peerCtx->loop_task_event_source_fd == -1);
peerCtx->loop_task_event_source_fd = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC);
if (peerCtx->loop_task_event_source_fd == -1) {
weston_log("%s: eventfd(EFD_SEMAPHORE) failed. %s\n", __func__, strerror(errno));
goto error_event_source_fd;
}
assert(wl_list_empty(&peerCtx->loop_task_list));
loop = wl_display_get_event_loop(b->compositor->wl_display);
assert(peerCtx->loop_task_event_source == NULL);
ret = rdp_event_loop_add_fd(loop,
peerCtx->loop_task_event_source_fd,
WL_EVENT_READABLE, rdp_dispatch_task,
peerCtx,
&peerCtx->loop_task_event_source);
if (!ret)
goto error_event_loop_add_fd;
return true;
error_event_loop_add_fd:
close(peerCtx->loop_task_event_source_fd);
peerCtx->loop_task_event_source_fd = -1;
error_event_source_fd:
pthread_mutex_destroy(&peerCtx->loop_task_list_mutex);
error_mutex:
return false;
}
void
rdp_destroy_dispatch_task_event_source(RdpPeerContext *peerCtx)
{
struct rdp_loop_task *task, *tmp;
/* This function must be called all virtual channel thread at FreeRDP is terminated,
* that ensures no more incoming tasks. */
if (peerCtx->loop_task_event_source) {
wl_event_source_remove(peerCtx->loop_task_event_source);
peerCtx->loop_task_event_source = NULL;
}
wl_list_for_each_reverse_safe(task, tmp, &peerCtx->loop_task_list, link) {
wl_list_remove(&task->link);
/* inform caller task is not really scheduled prior to context destruction,
* inform them to clean them up. */
task->func(true /* freeOnly */, task);
}
assert(wl_list_empty(&peerCtx->loop_task_list));
if (peerCtx->loop_task_event_source_fd != -1) {
close(peerCtx->loop_task_event_source_fd);
peerCtx->loop_task_event_source_fd = -1;
}
pthread_mutex_destroy(&peerCtx->loop_task_list_mutex);
}
/* This is a little tricky - it makes sure there's always at least
* one spare byte in the array in case the caller needs to add a
* null terminator to it. We can't just null terminate the array
* here, because some callers won't want that - and some won't
* like having an odd number of bytes.
*/
int
rdp_wl_array_read_fd(struct wl_array *array, int fd)
{
int len, size;
char *data;
/* Make sure we have at least 1024 bytes of space left */
if (array->alloc - array->size < 1024) {
if (!wl_array_add(array, 1024)) {
errno = ENOMEM;
return -1;
}
array->size -= 1024;
}
data = (char *)array->data + array->size;
/* Leave one char in case the caller needs space for a
* null terminator */
size = array->alloc - array->size - 1;
do {
len = read(fd, data, size);
} while (len == -1 && errno == EINTR);
if (len == -1)
return -1;
array->size += len;
return len;
}
+78 -21
View File
@@ -233,15 +233,25 @@ struct wayland_input {
struct gl_renderer_interface *gl_renderer; struct gl_renderer_interface *gl_renderer;
static void
wayland_head_destroy(struct weston_head *base);
static inline struct wayland_head * static inline struct wayland_head *
to_wayland_head(struct weston_head *base) to_wayland_head(struct weston_head *base)
{ {
if (base->backend_id != wayland_head_destroy)
return NULL;
return container_of(base, struct wayland_head, base); return container_of(base, struct wayland_head, base);
} }
static void
wayland_output_destroy(struct weston_output *base);
static inline struct wayland_output * static inline struct wayland_output *
to_wayland_output(struct weston_output *base) to_wayland_output(struct weston_output *base)
{ {
if (base->destroy != wayland_output_destroy)
return NULL;
return container_of(base, struct wayland_output, base); return container_of(base, struct wayland_output, base);
} }
@@ -501,8 +511,11 @@ static int
wayland_output_start_repaint_loop(struct weston_output *output_base) wayland_output_start_repaint_loop(struct weston_output *output_base)
{ {
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output = to_wayland_output(output_base);
struct wayland_backend *wb = struct wayland_backend *wb;
to_wayland_backend(output->base.compositor);
assert(output);
wb = to_wayland_backend(output->base.compositor);
/* If this is the initial frame, we need to attach a buffer so that /* If this is the initial frame, we need to attach a buffer so that
* the compositor can map the surface and include it in its render * the compositor can map the surface and include it in its render
@@ -526,11 +539,14 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
#ifdef ENABLE_EGL #ifdef ENABLE_EGL
static int static int
wayland_output_repaint_gl(struct weston_output *output_base, wayland_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output = to_wayland_output(output_base);
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
output->frame_cb = wl_surface_frame(output->parent.surface); output->frame_cb = wl_surface_frame(output->parent.surface);
wl_callback_add_listener(output->frame_cb, &frame_listener, output); wl_callback_add_listener(output->frame_cb, &frame_listener, output);
@@ -638,14 +654,16 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
static int static int
wayland_output_repaint_pixman(struct weston_output *output_base, wayland_output_repaint_pixman(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output = to_wayland_output(output_base);
struct wayland_backend *b = struct wayland_backend *b;
to_wayland_backend(output->base.compositor);
struct wayland_shm_buffer *sb; struct wayland_shm_buffer *sb;
assert(output);
b = to_wayland_backend(output->base.compositor);
if (output->frame) { if (output->frame) {
if (frame_status(output->frame) & FRAME_STATUS_REPAINT) if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
wl_list_for_each(sb, &output->shm.buffers, link) wl_list_for_each(sb, &output->shm.buffers, link)
@@ -718,7 +736,11 @@ static int
wayland_output_disable(struct weston_output *base) wayland_output_disable(struct weston_output *base)
{ {
struct wayland_output *output = to_wayland_output(base); struct wayland_output *output = to_wayland_output(base);
struct wayland_backend *b = to_wayland_backend(base->compositor); struct wayland_backend *b;
assert(output);
b = to_wayland_backend(base->compositor);
if (!output->base.enabled) if (!output->base.enabled)
return 0; return 0;
@@ -752,6 +774,8 @@ wayland_output_destroy(struct weston_output *base)
{ {
struct wayland_output *output = to_wayland_output(base); struct wayland_output *output = to_wayland_output(base);
assert(output);
wayland_output_disable(&output->base); wayland_output_disable(&output->base);
weston_output_release(&output->base); weston_output_release(&output->base);
@@ -1062,7 +1086,7 @@ static int
wayland_output_switch_mode(struct weston_output *output_base, wayland_output_switch_mode(struct weston_output *output_base,
struct weston_mode *mode) struct weston_mode *mode)
{ {
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output;
struct wayland_backend *b; struct wayland_backend *b;
struct wl_surface *old_surface; struct wl_surface *old_surface;
struct weston_mode *old_mode; struct weston_mode *old_mode;
@@ -1073,6 +1097,9 @@ wayland_output_switch_mode(struct weston_output *output_base,
return -1; return -1;
} }
output = to_wayland_output(output_base);
assert(output);
if (mode == NULL) { if (mode == NULL) {
weston_log("mode is NULL.\n"); weston_log("mode is NULL.\n");
return -1; return -1;
@@ -1243,10 +1270,14 @@ static int
wayland_output_enable(struct weston_output *base) wayland_output_enable(struct weston_output *base)
{ {
struct wayland_output *output = to_wayland_output(base); struct wayland_output *output = to_wayland_output(base);
struct wayland_backend *b = to_wayland_backend(base->compositor); struct wayland_backend *b;
enum mode_status mode_status; enum mode_status mode_status;
int ret = 0; int ret = 0;
assert(output);
b = to_wayland_backend(base->compositor);
wl_list_init(&output->shm.buffers); wl_list_init(&output->shm.buffers);
wl_list_init(&output->shm.free_buffers); wl_list_init(&output->shm.free_buffers);
@@ -1326,9 +1357,16 @@ static int
wayland_output_attach_head(struct weston_output *output_base, wayland_output_attach_head(struct weston_output *output_base,
struct weston_head *head_base) struct weston_head *head_base)
{ {
struct wayland_backend *b = to_wayland_backend(output_base->compositor);
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output = to_wayland_output(output_base);
struct wayland_head *head = to_wayland_head(head_base); struct wayland_head *head = to_wayland_head(head_base);
struct wayland_backend *b;
assert(output);
if (!head)
return -1;
b = to_wayland_backend(output_base->compositor);
if (!wl_list_empty(&output->base.head_list)) if (!wl_list_empty(&output->base.head_list))
return -1; return -1;
@@ -1353,6 +1391,8 @@ wayland_output_detach_head(struct weston_output *output_base,
{ {
struct wayland_output *output = to_wayland_output(output_base); struct wayland_output *output = to_wayland_output(output_base);
assert(output);
/* Rely on the disable hook if the output was enabled. We do not /* Rely on the disable hook if the output was enabled. We do not
* support cloned heads, so detaching is guaranteed to disable the * support cloned heads, so detaching is guaranteed to disable the
* output. * output.
@@ -1411,6 +1451,9 @@ wayland_head_create(struct weston_compositor *compositor, const char *name)
return NULL; return NULL;
weston_head_init(&head->base, name); weston_head_init(&head->base, name);
head->base.backend_id = wayland_head_destroy;
weston_head_set_connection_status(&head->base, true); weston_head_set_connection_status(&head->base, true);
weston_compositor_add_head(compositor, &head->base); weston_compositor_add_head(compositor, &head->base);
@@ -1458,8 +1501,12 @@ wayland_head_create_for_parent_output(struct weston_compositor *compositor,
} }
static void static void
wayland_head_destroy(struct wayland_head *head) wayland_head_destroy(struct weston_head *base)
{ {
struct wayland_head *head = to_wayland_head(base);
assert(head);
if (head->parent_output) if (head->parent_output)
head->parent_output->head = NULL; head->parent_output->head = NULL;
@@ -1474,6 +1521,9 @@ wayland_output_set_size(struct weston_output *base, int width, int height)
struct weston_head *head; struct weston_head *head;
int output_width, output_height; int output_width, output_height;
if (!output)
return -1;
/* We can only be called once. */ /* We can only be called once. */
assert(!output->base.current_mode); assert(!output->base.current_mode);
@@ -2187,10 +2237,6 @@ input_handle_touch_up(void *data, struct wl_touch *wl_touch,
timespec_from_msec(&ts, time); timespec_from_msec(&ts, time);
input->touch_points--; input->touch_points--;
if (input->touch_points == 0) {
input->touch_focus = NULL;
input->touch_active = false;
}
if (!output) if (!output)
return; return;
@@ -2253,6 +2299,11 @@ input_handle_touch_frame(void *data, struct wl_touch *wl_touch)
return; return;
notify_touch_frame(input->touch_device); notify_touch_frame(input->touch_device);
if (input->touch_points == 0) {
input->touch_focus = NULL;
input->touch_active = false;
}
} }
static void static void
@@ -2629,7 +2680,7 @@ wayland_parent_output_destroy(struct wayland_parent_output *output)
wl_callback_destroy(output->sync_cb); wl_callback_destroy(output->sync_cb);
if (output->head) if (output->head)
wayland_head_destroy(output->head); wayland_head_destroy(&output->head->base);
wl_output_destroy(output->global); wl_output_destroy(output->global);
free(output->physical.make); free(output->physical.make);
@@ -2742,14 +2793,20 @@ wayland_destroy(struct weston_compositor *ec)
{ {
struct wayland_backend *b = to_wayland_backend(ec); struct wayland_backend *b = to_wayland_backend(ec);
struct weston_head *base, *next; struct weston_head *base, *next;
struct wayland_parent_output *output, *next_output;
struct wayland_input *input, *next_input; struct wayland_input *input, *next_input;
wl_event_source_remove(b->parent.wl_source); wl_event_source_remove(b->parent.wl_source);
weston_compositor_shutdown(ec); weston_compositor_shutdown(ec);
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
wayland_head_destroy(to_wayland_head(base)); if (to_wayland_head(base))
wayland_head_destroy(base);
}
wl_list_for_each_safe(output, next_output, &b->parent.output_list, link)
wayland_parent_output_destroy(output);
wl_list_for_each_safe(input, next_input, &b->input_list, link) wl_list_for_each_safe(input, next_input, &b->input_list, link)
wayland_input_destroy(input); wayland_input_destroy(input);
+89 -43
View File
@@ -119,6 +119,7 @@ struct x11_backend {
xcb_atom_t cardinal; xcb_atom_t cardinal;
xcb_atom_t xkb_names; xcb_atom_t xkb_names;
} atom; } atom;
xcb_generic_event_t *prev_event;
}; };
struct x11_head { struct x11_head {
@@ -151,15 +152,25 @@ struct window_delete_data {
struct gl_renderer_interface *gl_renderer; struct gl_renderer_interface *gl_renderer;
static void
x11_head_destroy(struct weston_head *base);
static inline struct x11_head * static inline struct x11_head *
to_x11_head(struct weston_head *base) to_x11_head(struct weston_head *base)
{ {
if (base->backend_id != x11_head_destroy)
return NULL;
return container_of(base, struct x11_head, base); return container_of(base, struct x11_head, base);
} }
static void
x11_output_destroy(struct weston_output *base);
static inline struct x11_output * static inline struct x11_output *
to_x11_output(struct weston_output *base) to_x11_output(struct weston_output *base)
{ {
if (base->destroy != x11_output_destroy)
return NULL;
return container_of(base, struct x11_output, base); return container_of(base, struct x11_output, base);
} }
@@ -417,11 +428,14 @@ x11_output_start_repaint_loop(struct weston_output *output)
static int static int
x11_output_repaint_gl(struct weston_output *output_base, x11_output_repaint_gl(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct x11_output *output = to_x11_output(output_base); struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec;
assert(output);
ec = output->base.compositor;
ec->renderer->repaint_output(output_base, damage); ec->renderer->repaint_output(output_base, damage);
@@ -436,8 +450,8 @@ static void
set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region) set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
{ {
struct x11_output *output = to_x11_output(output_base); struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec;
struct x11_backend *b = to_x11_backend(ec); struct x11_backend *b;
pixman_region32_t transformed_region; pixman_region32_t transformed_region;
pixman_box32_t *rects; pixman_box32_t *rects;
xcb_rectangle_t *output_rects; xcb_rectangle_t *output_rects;
@@ -445,6 +459,12 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
int nrects, i; int nrects, i;
xcb_generic_error_t *err; xcb_generic_error_t *err;
if (!output)
return;
ec = output->base.compositor;
b = to_x11_backend(ec);
pixman_region32_init(&transformed_region); pixman_region32_init(&transformed_region);
pixman_region32_copy(&transformed_region, region); pixman_region32_copy(&transformed_region, region);
pixman_region32_translate(&transformed_region, pixman_region32_translate(&transformed_region,
@@ -486,15 +506,19 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
static int static int
x11_output_repaint_shm(struct weston_output *output_base, x11_output_repaint_shm(struct weston_output *output_base,
pixman_region32_t *damage, pixman_region32_t *damage)
void *repaint_data)
{ {
struct x11_output *output = to_x11_output(output_base); struct x11_output *output = to_x11_output(output_base);
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec;
struct x11_backend *b = to_x11_backend(ec); struct x11_backend *b;
xcb_void_cookie_t cookie; xcb_void_cookie_t cookie;
xcb_generic_error_t *err; xcb_generic_error_t *err;
assert(output);
ec = output->base.compositor;
b = to_x11_backend(ec);
pixman_renderer_output_set_buffer(output_base, output->hw_surface); pixman_renderer_output_set_buffer(output_base, output->hw_surface);
ec->renderer->repaint_output(output_base, damage); ec->renderer->repaint_output(output_base, damage);
@@ -803,12 +827,13 @@ static int
x11_output_switch_mode(struct weston_output *base, struct weston_mode *mode) x11_output_switch_mode(struct weston_output *base, struct weston_mode *mode)
{ {
struct x11_backend *b; struct x11_backend *b;
struct x11_output *output; struct x11_output *output = to_x11_output(base);
static uint32_t values[2]; static uint32_t values[2];
int ret; int ret;
assert(output);
b = to_x11_backend(base->compositor); b = to_x11_backend(base->compositor);
output = to_x11_output(base);
if (mode->width == output->mode.width && if (mode->width == output->mode.width &&
mode->height == output->mode.height) mode->height == output->mode.height)
@@ -880,7 +905,11 @@ static int
x11_output_disable(struct weston_output *base) x11_output_disable(struct weston_output *base)
{ {
struct x11_output *output = to_x11_output(base); struct x11_output *output = to_x11_output(base);
struct x11_backend *backend = to_x11_backend(base->compositor); struct x11_backend *backend;
assert(output);
backend = to_x11_backend(base->compositor);
if (!output->base.enabled) if (!output->base.enabled)
return 0; return 0;
@@ -905,6 +934,8 @@ x11_output_destroy(struct weston_output *base)
{ {
struct x11_output *output = to_x11_output(base); struct x11_output *output = to_x11_output(base);
assert(output);
x11_output_disable(&output->base); x11_output_disable(&output->base);
weston_output_release(&output->base); weston_output_release(&output->base);
@@ -915,7 +946,12 @@ static int
x11_output_enable(struct weston_output *base) x11_output_enable(struct weston_output *base)
{ {
struct x11_output *output = to_x11_output(base); struct x11_output *output = to_x11_output(base);
struct x11_backend *b = to_x11_backend(base->compositor); const struct weston_mode *mode = output->base.current_mode;
struct x11_backend *b;
assert(output);
b = to_x11_backend(base->compositor);
static const char name[] = "Weston Compositor"; static const char name[] = "Weston Compositor";
static const char class[] = "weston-1\0Weston Compositor"; static const char class[] = "weston-1\0Weston Compositor";
@@ -954,8 +990,7 @@ x11_output_enable(struct weston_output *base)
output->window, output->window,
screen->root, screen->root,
0, 0, 0, 0,
output->base.current_mode->width, mode->width, mode->height,
output->base.current_mode->height,
0, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual, screen->root_visual,
@@ -1020,8 +1055,7 @@ x11_output_enable(struct weston_output *base)
.use_shadow = true, .use_shadow = true,
}; };
if (x11_output_init_shm(b, output, if (x11_output_init_shm(b, output,
output->base.current_mode->width, mode->width, mode->height) < 0) {
output->base.current_mode->height) < 0) {
weston_log("Failed to initialize SHM for the X11 output\n"); weston_log("Failed to initialize SHM for the X11 output\n");
goto err; goto err;
} }
@@ -1062,9 +1096,7 @@ x11_output_enable(struct weston_output *base)
wl_event_loop_add_timer(loop, finish_frame_handler, output); wl_event_loop_add_timer(loop, finish_frame_handler, output);
weston_log("x11 output %dx%d, window id %d\n", weston_log("x11 output %dx%d, window id %d\n",
output->base.current_mode->width, mode->width, mode->height, output->window);
output->base.current_mode->height,
output->window);
return 0; return 0;
@@ -1079,11 +1111,17 @@ static int
x11_output_set_size(struct weston_output *base, int width, int height) x11_output_set_size(struct weston_output *base, int width, int height)
{ {
struct x11_output *output = to_x11_output(base); struct x11_output *output = to_x11_output(base);
struct x11_backend *b = to_x11_backend(base->compositor); struct x11_backend *b;
struct weston_head *head; struct weston_head *head;
xcb_screen_t *scrn = b->screen; xcb_screen_t *scrn;
int output_width, output_height; int output_width, output_height;
if (!output)
return -1;
b = to_x11_backend(base->compositor);
scrn = b->screen;
/* We can only be called once. */ /* We can only be called once. */
assert(!output->base.current_mode); assert(!output->base.current_mode);
@@ -1165,6 +1203,9 @@ x11_head_create(struct weston_compositor *compositor, const char *name)
return -1; return -1;
weston_head_init(&head->base, name); weston_head_init(&head->base, name);
head->base.backend_id = x11_head_destroy;
weston_head_set_connection_status(&head->base, true); weston_head_set_connection_status(&head->base, true);
weston_compositor_add_head(compositor, &head->base); weston_compositor_add_head(compositor, &head->base);
@@ -1172,8 +1213,12 @@ x11_head_create(struct weston_compositor *compositor, const char *name)
} }
static void static void
x11_head_destroy(struct x11_head *head) x11_head_destroy(struct weston_head *base)
{ {
struct x11_head *head = to_x11_head(base);
assert(head);
weston_head_release(&head->base); weston_head_release(&head->base);
free(head); free(head);
} }
@@ -1450,7 +1495,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
{ {
struct x11_backend *b = data; struct x11_backend *b = data;
struct x11_output *output; struct x11_output *output;
xcb_generic_event_t *event, *prev; xcb_generic_event_t *event;
xcb_client_message_event_t *client_message; xcb_client_message_event_t *client_message;
xcb_enter_notify_event_t *enter_notify; xcb_enter_notify_event_t *enter_notify;
xcb_key_press_event_t *key_press, *key_release; xcb_key_press_event_t *key_press, *key_release;
@@ -1466,16 +1511,15 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
int count; int count;
struct timespec time; struct timespec time;
prev = NULL;
count = 0; count = 0;
while (x11_backend_next_event(b, &event, mask)) { while (x11_backend_next_event(b, &event, mask)) {
response_type = event->response_type & ~0x80; response_type = event->response_type & ~0x80;
switch (prev ? prev->response_type & ~0x80 : 0x80) { switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE: case XCB_KEY_RELEASE:
/* Suppress key repeat events; this is only used if we /* Suppress key repeat events; this is only used if we
* don't have XCB XKB support. */ * don't have XCB XKB support. */
key_release = (xcb_key_press_event_t *) prev; key_release = (xcb_key_press_event_t *) b->prev_event;
key_press = (xcb_key_press_event_t *) event; key_press = (xcb_key_press_event_t *) event;
if (response_type == XCB_KEY_PRESS && if (response_type == XCB_KEY_PRESS &&
key_release->time == key_press->time && key_release->time == key_press->time &&
@@ -1483,8 +1527,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* Don't deliver the held key release /* Don't deliver the held key release
* event or the new key press event. */ * event or the new key press event. */
free(event); free(event);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
continue; continue;
} else { } else {
/* Deliver the held key release now /* Deliver the held key release now
@@ -1497,8 +1541,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8, key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED, WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
} }
@@ -1522,8 +1566,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
notify_keyboard_focus_in(&b->core_seat, &b->keys, notify_keyboard_focus_in(&b->core_seat, &b->keys,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
default: default:
@@ -1548,7 +1592,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
/* If we don't have XKB, we need to use the lame /* If we don't have XKB, we need to use the lame
* autorepeat detection above. */ * autorepeat detection above. */
if (!b->has_xkb) { if (!b->has_xkb) {
prev = event; b->prev_event = event;
break; break;
} }
key_release = (xcb_key_press_event_t *) event; key_release = (xcb_key_press_event_t *) event;
@@ -1643,7 +1687,7 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED) if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
break; break;
prev = event; b->prev_event = event;
break; break;
case XCB_FOCUS_OUT: case XCB_FOCUS_OUT:
@@ -1677,13 +1721,13 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
#endif #endif
count++; count++;
if (prev != event) if (b->prev_event != event)
free (event); free(event);
} }
switch (prev ? prev->response_type & ~0x80 : 0x80) { switch (b->prev_event ? b->prev_event->response_type & ~0x80 : 0x80) {
case XCB_KEY_RELEASE: case XCB_KEY_RELEASE:
key_release = (xcb_key_press_event_t *) prev; key_release = (xcb_key_press_event_t *) b->prev_event;
update_xkb_state_from_core(b, key_release->state); update_xkb_state_from_core(b, key_release->state);
weston_compositor_get_time(&time); weston_compositor_get_time(&time);
notify_key(&b->core_seat, notify_key(&b->core_seat,
@@ -1691,8 +1735,8 @@ x11_backend_handle_event(int fd, uint32_t mask, void *data)
key_release->detail - 8, key_release->detail - 8,
WL_KEYBOARD_KEY_STATE_RELEASED, WL_KEYBOARD_KEY_STATE_RELEASED,
STATE_UPDATE_AUTOMATIC); STATE_UPDATE_AUTOMATIC);
free(prev); free(b->prev_event);
prev = NULL; b->prev_event = NULL;
break; break;
default: default:
break; break;
@@ -1792,8 +1836,10 @@ x11_destroy(struct weston_compositor *ec)
weston_compositor_shutdown(ec); /* destroys outputs, too */ weston_compositor_shutdown(ec); /* destroys outputs, too */
wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) {
x11_head_destroy(to_x11_head(base)); if (to_x11_head(base))
x11_head_destroy(base);
}
XCloseDisplay(backend->dpy); XCloseDisplay(backend->dpy);
free(backend); free(backend);
+12 -12
View File
@@ -32,6 +32,8 @@
#ifndef LIBWESTON_BACKEND_INTERNAL_H #ifndef LIBWESTON_BACKEND_INTERNAL_H
#define LIBWESTON_BACKEND_INTERNAL_H #define LIBWESTON_BACKEND_INTERNAL_H
struct weston_hdr_metadata_type1;
struct weston_backend { struct weston_backend {
void (*destroy)(struct weston_compositor *compositor); void (*destroy)(struct weston_compositor *compositor);
@@ -46,27 +48,21 @@ struct weston_backend {
* Returns an opaque pointer, which the backend may use as private * Returns an opaque pointer, which the backend may use as private
* data referring to the repaint cycle. * data referring to the repaint cycle.
*/ */
void * (*repaint_begin)(struct weston_compositor *compositor); void (*repaint_begin)(struct weston_compositor *compositor);
/** Cancel a repaint sequence /** Cancel a repaint sequence
* *
* Cancels a repaint sequence, when an error has occurred during * Cancels a repaint sequence, when an error has occurred during
* one output's repaint; see repaint_begin. * one output's repaint; see repaint_begin.
*
* @param repaint_data Data returned by repaint_begin
*/ */
void (*repaint_cancel)(struct weston_compositor *compositor, void (*repaint_cancel)(struct weston_compositor *compositor);
void *repaint_data);
/** Conclude a repaint sequence /** Conclude a repaint sequence
* *
* Called on successful completion of a repaint sequence; see * Called on successful completion of a repaint sequence; see
* repaint_begin. * repaint_begin.
*
* @param repaint_data Data returned by repaint_begin
*/ */
int (*repaint_flush)(struct weston_compositor *compositor, int (*repaint_flush)(struct weston_compositor *compositor);
void *repaint_data);
/** Allocate a new output /** Allocate a new output
* *
@@ -142,6 +138,10 @@ weston_head_set_subpixel(struct weston_head *head,
void void
weston_head_set_transform(struct weston_head *head, uint32_t transform); weston_head_set_transform(struct weston_head *head, uint32_t transform);
void
weston_head_set_supported_eotf_mask(struct weston_head *head,
uint32_t eotf_mask);
/* weston_output */ /* weston_output */
void void
@@ -154,9 +154,6 @@ weston_output_damage(struct weston_output *output);
void void
weston_output_release(struct weston_output *output); weston_output_release(struct weston_output *output);
void
weston_output_init_zoom(struct weston_output *output);
void void
weston_output_finish_frame(struct weston_output *output, weston_output_finish_frame(struct weston_output *output,
const struct timespec *stamp, const struct timespec *stamp,
@@ -178,6 +175,9 @@ void
weston_output_region_from_global(struct weston_output *output, weston_output_region_from_global(struct weston_output *output,
pixman_region32_t *region); pixman_region32_t *region);
const struct weston_hdr_metadata_type1 *
weston_output_get_hdr_metadata_type1(const struct weston_output *output);
/* weston_seat */ /* weston_seat */
void void
+2 -2
View File
@@ -310,8 +310,8 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
/* If this was a key binding and it didn't /* If this was a key binding and it didn't
* install a keyboard grab, install one now to * install a keyboard grab, install one now to
* swallow the key press. */ * swallow the key press. */
if (keyboard->grab == if (keyboard->grab == &keyboard->default_grab ||
&keyboard->default_grab) keyboard->grab == &keyboard->input_method_grab)
install_binding_grab(keyboard, install_binding_grab(keyboard,
time, time,
key, key,
+1 -1
View File
@@ -110,7 +110,7 @@ clipboard_source_data(int fd, uint32_t mask, void *data)
static void static void
clipboard_source_accept(struct weston_data_source *source, clipboard_source_accept(struct weston_data_source *source,
uint32_t time, const char *mime_type) uint32_t serial, const char *mime_type)
{ {
} }
+244 -57
View File
@@ -27,12 +27,37 @@
#include "config.h" #include "config.h"
#include <assert.h> #include <assert.h>
#include <string.h>
#include <libweston/libweston.h> #include <libweston/libweston.h>
#include "color.h" #include "color.h"
#include "color-lcms.h" #include "color-lcms.h"
#include "shared/helpers.h" #include "shared/helpers.h"
static cmsUInt32Number
cmlcms_get_render_intent(enum cmlcms_category cat,
struct weston_surface *surface,
struct weston_output *output)
{
/*
* TODO: Take into account client provided content profile,
* output profile, and the category of the wanted color
* transformation.
*/
cmsUInt32Number intent = INTENT_RELATIVE_COLORIMETRIC;
return intent;
}
static struct cmlcms_color_profile *
get_cprof_or_stock_sRGB(struct weston_color_manager_lcms *cm,
struct weston_color_profile *cprof_base)
{
if (cprof_base)
return get_cprof(cprof_base);
else
return cm->sRGB_profile;
}
static void static void
cmlcms_destroy_color_transform(struct weston_color_transform *xform_base) cmlcms_destroy_color_transform(struct weston_color_transform *xform_base)
{ {
@@ -48,47 +73,52 @@ cmlcms_get_surface_color_transform(struct weston_color_manager *cm_base,
struct weston_surface_color_transform *surf_xform) struct weston_surface_color_transform *surf_xform)
{ {
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = {
/*
* Assumes both content and output color spaces are sRGB SDR.
* This defines the blending space as optical sRGB SDR.
*/
.type = CMLCMS_TYPE_EOTF_sRGB,
};
struct cmlcms_color_transform *xform; struct cmlcms_color_transform *xform;
/* TODO: use output color profile */ /* TODO: take weston_output::eotf_mode into account */
if (output->color_profile)
return false; struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_BLEND,
.input_profile = get_cprof_or_stock_sRGB(cm, NULL /* TODO: surface->color_profile */),
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
surface, output);
xform = cmlcms_color_transform_get(cm, &param); xform = cmlcms_color_transform_get(cm, &param);
if (!xform) if (!xform)
return false; return false;
surf_xform->transform = &xform->base; surf_xform->transform = &xform->base;
surf_xform->identity_pipeline = true;
return true;
}
static bool
cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = {
/* /*
* Assumes blending space is optical sRGB SDR and * When we introduce LCMS plug-in we can precisely answer this question
* output color space is sRGB SDR. * by examining the color pipeline using precision parameters. For now
* we just compare if it is same pointer or not.
*/ */
.type = CMLCMS_TYPE_EOTF_sRGB_INV, if (xform->search_key.input_profile == xform->search_key.output_profile)
}; surf_xform->identity_pipeline = true;
else
surf_xform->identity_pipeline = false;
return true;
}
static bool
cmlcms_get_blend_to_output_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
struct cmlcms_color_transform *xform; struct cmlcms_color_transform *xform;
/* TODO: use output color profile */ /* TODO: take weston_output::eotf_mode into account */
if (output->color_profile)
return false; struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_BLEND_TO_OUTPUT,
.input_profile = NULL,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
xform = cmlcms_color_transform_get(cm, &param); xform = cmlcms_color_transform_get(cm, &param);
if (!xform) if (!xform)
@@ -99,44 +129,200 @@ cmlcms_get_output_color_transform(struct weston_color_manager *cm_base,
} }
static bool static bool
cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base, cmlcms_get_sRGB_to_output_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output, struct weston_output *output,
struct weston_color_transform **xform_out) struct weston_color_transform **xform_out)
{ {
/* Assumes output color space is sRGB SDR */ struct cmlcms_color_transform *xform;
/* TODO: use output color profile */ /* TODO: take weston_output::eotf_mode into account */
if (output->color_profile)
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_OUTPUT,
.input_profile = cm->sRGB_profile,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
/*
* Create a color transformation when output profile is not stock
* sRGB profile.
*/
if (param.output_profile != cm->sRGB_profile) {
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
return false; return false;
*xform_out = &xform->base;
/* Identity transform */ } else {
*xform_out = NULL; *xform_out = NULL; /* Identity transform */
}
return true; return true;
} }
static bool static bool
cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base, cmlcms_get_sRGB_to_blend_color_transform(struct weston_color_manager_lcms *cm,
struct weston_output *output, struct weston_output *output,
struct weston_color_transform **xform_out) struct weston_color_transform **xform_out)
{
struct cmlcms_color_transform *xform;
/* TODO: take weston_output::eotf_mode into account */
struct cmlcms_color_transform_search_param param = {
.category = CMLCMS_CATEGORY_INPUT_TO_BLEND,
.input_profile = cm->sRGB_profile,
.output_profile = get_cprof_or_stock_sRGB(cm, output->color_profile),
};
param.intent_output = cmlcms_get_render_intent(param.category,
NULL, output);
xform = cmlcms_color_transform_get(cm, &param);
if (!xform)
return false;
*xform_out = &xform->base;
return true;
}
static float
meta_clamp(float value, const char *valname, float min, float max,
struct weston_output *output)
{
float ret = value;
/* Paranoia against NaN */
if (!(ret >= min))
ret = min;
if (!(ret <= max))
ret = max;
if (ret != value) {
weston_log("output '%s' clamping %s value from %f to %f.\n",
output->name, valname, value, ret);
}
return ret;
}
static bool
cmlcms_get_hdr_meta(struct weston_output *output,
struct weston_hdr_metadata_type1 *hdr_meta)
{
const struct weston_color_characteristics *cc;
hdr_meta->group_mask = 0;
/* Only SMPTE ST 2084 mode uses HDR Static Metadata Type 1 */
if (weston_output_get_eotf_mode(output) != WESTON_EOTF_MODE_ST2084)
return true;
/* ICC profile overrides color characteristics */
if (output->color_profile) {
/*
* TODO: extract characteristics from profile?
* Get dynamic range from weston_color_characteristics?
*/
return true;
}
cc = weston_output_get_color_characteristics(output);
/* Target content chromaticity */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_PRIMARIES) {
unsigned i;
for (i = 0; i < 3; i++) {
hdr_meta->primary[i].x = meta_clamp(cc->primary[i].x,
"primary", 0.0, 1.0,
output);
hdr_meta->primary[i].y = meta_clamp(cc->primary[i].y,
"primary", 0.0, 1.0,
output);
}
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_PRIMARIES;
}
/* Target content white point */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_WHITE) {
hdr_meta->white.x = meta_clamp(cc->white.x, "white",
0.0, 1.0, output);
hdr_meta->white.y = meta_clamp(cc->white.y, "white",
0.0, 1.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_WHITE;
}
/* Target content peak and max mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXL) {
hdr_meta->maxDML = meta_clamp(cc->max_luminance, "maxDML",
1.0, 65535.0, output);
hdr_meta->maxCLL = meta_clamp(cc->max_luminance, "maxCLL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXDML;
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXCLL;
}
/* Target content min mastering luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MINL) {
hdr_meta->minDML = meta_clamp(cc->min_luminance, "minDML",
0.0001, 6.5535, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MINDML;
}
/* Target content max frame-average luminance */
if (cc->group_mask & WESTON_COLOR_CHARACTERISTICS_GROUP_MAXFALL) {
hdr_meta->maxFALL = meta_clamp(cc->maxFALL, "maxFALL",
1.0, 65535.0, output);
hdr_meta->group_mask |= WESTON_HDR_METADATA_TYPE1_GROUP_MAXFALL;
}
return true;
}
static struct weston_output_color_outcome *
cmlcms_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output)
{ {
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
struct cmlcms_color_transform_search_param param = { struct weston_output_color_outcome *co;
/* Assumes blending space is optical sRGB SDR */
.type = CMLCMS_TYPE_EOTF_sRGB,
};
struct cmlcms_color_transform *xform;
/* TODO: use output color profile */ co = zalloc(sizeof *co);
if (output->color_profile) if (!co)
return false; return NULL;
xform = cmlcms_color_transform_get(cm, &param); if (!cmlcms_get_hdr_meta(output, &co->hdr_meta))
if (!xform) goto out_fail;
return false;
*xform_out = &xform->base; /*
return true; * TODO: if output->color_profile is NULL, maybe manufacture a
* profile from weston_color_characteristics if it has enough
* information?
* Or let the frontend decide to call a "create a profile from
* characteristics" API?
*/
/* TODO: take container color space into account */
if (!cmlcms_get_blend_to_output_color_transform(cm, output,
&co->from_blend_to_output))
goto out_fail;
if (!cmlcms_get_sRGB_to_blend_color_transform(cm, output,
&co->from_sRGB_to_blend))
goto out_fail;
if (!cmlcms_get_sRGB_to_output_color_transform(cm, output,
&co->from_sRGB_to_output))
goto out_fail;
return co;
out_fail:
weston_output_color_outcome_destroy(&co);
return NULL;
} }
static void static void
@@ -165,6 +351,10 @@ cmlcms_init(struct weston_color_manager *cm_base)
cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger); cmsSetLogErrorHandlerTHR(cm->lcms_ctx, lcms_error_logger);
if (!cmlcms_create_stock_profile(cm)) {
weston_log("color-lcms: error: cmlcms_create_stock_profile failed\n");
return false;
}
weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion()); weston_log("LittleCMS %d initialized.\n", cmsGetEncodedCMMversion());
return true; return true;
@@ -175,6 +365,8 @@ cmlcms_destroy(struct weston_color_manager *cm_base)
{ {
struct weston_color_manager_lcms *cm = get_cmlcms(cm_base); struct weston_color_manager_lcms *cm = get_cmlcms(cm_base);
if (cm->sRGB_profile)
cmlcms_color_profile_destroy(cm->sRGB_profile);
assert(wl_list_empty(&cm->color_transform_list)); assert(wl_list_empty(&cm->color_transform_list));
assert(wl_list_empty(&cm->color_profile_list)); assert(wl_list_empty(&cm->color_profile_list));
@@ -199,13 +391,8 @@ weston_color_manager_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmlcms_destroy_color_profile; cm->base.destroy_color_profile = cmlcms_destroy_color_profile;
cm->base.get_color_profile_from_icc = cmlcms_get_color_profile_from_icc; cm->base.get_color_profile_from_icc = cmlcms_get_color_profile_from_icc;
cm->base.destroy_color_transform = cmlcms_destroy_color_transform; cm->base.destroy_color_transform = cmlcms_destroy_color_transform;
cm->base.get_surface_color_transform = cm->base.get_surface_color_transform = cmlcms_get_surface_color_transform;
cmlcms_get_surface_color_transform; cm->base.create_output_color_outcome = cmlcms_create_output_color_outcome;
cm->base.get_output_color_transform = cmlcms_get_output_color_transform;
cm->base.get_sRGB_to_output_color_transform =
cmlcms_get_sRGB_to_output_color_transform;
cm->base.get_sRGB_to_blend_color_transform =
cmlcms_get_sRGB_to_blend_color_transform;
wl_list_init(&cm->color_transform_list); wl_list_init(&cm->color_transform_list);
wl_list_init(&cm->color_profile_list); wl_list_init(&cm->color_profile_list);
+89 -12
View File
@@ -39,6 +39,7 @@ struct weston_color_manager_lcms {
struct wl_list color_transform_list; /* cmlcms_color_transform::link */ struct wl_list color_transform_list; /* cmlcms_color_transform::link */
struct wl_list color_profile_list; /* cmlcms_color_profile::link */ struct wl_list color_profile_list; /* cmlcms_color_profile::link */
struct cmlcms_color_profile *sRGB_profile; /* stock profile */
}; };
static inline struct weston_color_manager_lcms * static inline struct weston_color_manager_lcms *
@@ -59,6 +60,58 @@ struct cmlcms_color_profile {
cmsHPROFILE profile; cmsHPROFILE profile;
struct cmlcms_md5_sum md5sum; struct cmlcms_md5_sum md5sum;
/**
* If the profile does support being an output profile and it is used as an
* output then this field represents a light linearizing transfer function
* and it can not be null. The field is null only if the profile is not
* usable as an output profile. The field is set when cmlcms_color_profile
* is created.
*/
cmsToneCurve *output_eotf[3];
/**
* If the profile does support being an output profile and it is used as an
* output then this field represents a concatenation of inverse EOTF + VCGT,
* if the tag exists and it can not be null.
* VCGT is part of monitor calibration which means: even though we must
* apply VCGT in the compositor, we pretend that it happens inside the
* monitor. This is how the classic color management and ICC profiles work.
* The ICC profile (ignoring the VCGT tag) characterizes the output which
* is VCGT + monitor behavior. The field is null only if the profile is not
* usable as an output profile. The field is set when cmlcms_color_profile
* is created.
*/
cmsToneCurve *output_inv_eotf_vcgt[3];
/**
* VCGT tag cached from output profile, it could be null if not exist
*/
cmsToneCurve *vcgt[3];
};
/**
* Type of LCMS transforms
*/
enum cmlcms_category {
/**
* Uses combination of input profile with output profile, but
* without INV EOTF or with additional EOTF in the transform pipeline
* inputblend = input profile + output profile + output EOTF
*/
CMLCMS_CATEGORY_INPUT_TO_BLEND = 0,
/**
* Uses INV EOTF only concatenated with VCGT tag if present
* blendoutput = output inverse EOTF + VCGT
*/
CMLCMS_CATEGORY_BLEND_TO_OUTPUT,
/**
* Transform uses input profile and output profile as is
* inputoutput = input profile + output profile + VCGT
*/
CMLCMS_CATEGORY_INPUT_TO_OUTPUT,
}; };
static inline struct cmlcms_color_profile * static inline struct cmlcms_color_profile *
@@ -78,18 +131,12 @@ cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm,
void void
cmlcms_destroy_color_profile(struct weston_color_profile *cprof_base); cmlcms_destroy_color_profile(struct weston_color_profile *cprof_base);
/*
* Perhaps a placeholder, until we get actual color spaces involved and
* see how this would work better.
*/
enum cmlcms_color_transform_type {
CMLCMS_TYPE_EOTF_sRGB = 0,
CMLCMS_TYPE_EOTF_sRGB_INV,
CMLCMS_TYPE__END,
};
struct cmlcms_color_transform_search_param { struct cmlcms_color_transform_search_param {
enum cmlcms_color_transform_type type; enum cmlcms_category category;
struct cmlcms_color_profile *input_profile;
struct cmlcms_color_profile *output_profile;
cmsUInt32Number intent_output; /* selected intent from output profile */
}; };
struct cmlcms_color_transform { struct cmlcms_color_transform {
@@ -100,8 +147,15 @@ struct cmlcms_color_transform {
struct cmlcms_color_transform_search_param search_key; struct cmlcms_color_transform_search_param search_key;
/* for EOTF types */ /**
cmsToneCurve *curve; * 3D LUT color mapping part of the transformation, if needed.
* For category CMLCMS_CATEGORY_INPUT_TO_OUTPUT it includes pre-curve and
* post-curve.
* For category CMLCMS_CATEGORY_INPUT_TO_BLEND it includes pre-curve.
* For category CMLCMS_CATEGORY_BLEND_TO_OUTPUT and when identity it is
* not used
*/
cmsHTRANSFORM cmap_3dlut;
}; };
static inline struct cmlcms_color_transform * static inline struct cmlcms_color_transform *
@@ -117,4 +171,27 @@ cmlcms_color_transform_get(struct weston_color_manager_lcms *cm,
void void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform); cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform);
struct cmlcms_color_profile *
ref_cprof(struct cmlcms_color_profile *cprof);
void
unref_cprof(struct cmlcms_color_profile *cprof);
bool
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm);
void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof);
bool
retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
cmsHPROFILE hProfile,
cmsToneCurve *output_eotf[3],
cmsToneCurve *output_inv_eotf_vcgt[3],
cmsToneCurve *vcgt[3],
unsigned int num_points);
unsigned int
cmlcms_reasonable_1D_points(void);
#endif /* WESTON_COLOR_LCMS_H */ #endif /* WESTON_COLOR_LCMS_H */
+286 -1
View File
@@ -36,6 +36,223 @@
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/string-helpers.h" #include "shared/string-helpers.h"
struct xyz_arr_flt {
float v[3];
};
static double
xyz_dot_prod(const struct xyz_arr_flt a, const struct xyz_arr_flt b)
{
return (double)a.v[0] * b.v[0] +
(double)a.v[1] * b.v[1] +
(double)a.v[2] * b.v[2];
}
/**
* Graeme sketched a linearization method there:
* https://lists.freedesktop.org/archives/wayland-devel/2019-March/040171.html
*/
static bool
build_eotf_from_clut_profile(cmsContext lcms_ctx,
cmsHPROFILE profile,
cmsToneCurve *output_eotf[3],
int num_points)
{
int ch, point;
float *curve_array[3];
float *red = NULL;
cmsHPROFILE xyz_profile = NULL;
cmsHTRANSFORM transform_rgb_to_xyz = NULL;
bool ret = false;
const float div = num_points - 1;
red = malloc(sizeof(float) * num_points * 3);
if (!red)
goto release;
curve_array[0] = red;
curve_array[1] = red + num_points;
curve_array[2] = red + 2 * num_points;
xyz_profile = cmsCreateXYZProfileTHR(lcms_ctx);
if (!xyz_profile)
goto release;
transform_rgb_to_xyz = cmsCreateTransformTHR(lcms_ctx, profile,
TYPE_RGB_FLT, xyz_profile,
TYPE_XYZ_FLT,
INTENT_ABSOLUTE_COLORIMETRIC,
0);
if (!transform_rgb_to_xyz)
goto release;
for (ch = 0; ch < 3; ch++) {
struct xyz_arr_flt prim_xyz_max;
struct xyz_arr_flt prim_xyz;
double xyz_square_magnitude;
float rgb[3] = { 0.0f, 0.0f, 0.0f };
rgb[ch] = 1.0f;
cmsDoTransform(transform_rgb_to_xyz, rgb, prim_xyz_max.v, 1);
/**
* Calculate xyz square of magnitude uses single channel 100% and
* others are zero.
*/
xyz_square_magnitude = xyz_dot_prod(prim_xyz_max, prim_xyz_max);
/**
* Build rgb tone curves
*/
for (point = 0; point < num_points; point++) {
rgb[ch] = (float)point / div;
cmsDoTransform(transform_rgb_to_xyz, rgb, prim_xyz.v, 1);
curve_array[ch][point] = xyz_dot_prod(prim_xyz,
prim_xyz_max) /
xyz_square_magnitude;
}
/**
* Create LCMS object of rgb tone curves and validate whether
* monotonic
*/
output_eotf[ch] = cmsBuildTabulatedToneCurveFloat(lcms_ctx,
num_points,
curve_array[ch]);
if (!output_eotf[ch])
goto release;
if (!cmsIsToneCurveMonotonic(output_eotf[ch])) {
/**
* It is interesting to see how this profile was created.
* We assume that such a curve could not be used for linearization
* of arbitrary profile.
*/
goto release;
}
}
ret = true;
release:
if (transform_rgb_to_xyz)
cmsDeleteTransform(transform_rgb_to_xyz);
if (xyz_profile)
cmsCloseProfile(xyz_profile);
free(red);
if (ret == false)
cmsFreeToneCurveTriple(output_eotf);
return ret;
}
/**
* Concatenation of two monotonic tone curves.
* LCMS API cmsJoinToneCurve does y = Y^-1(X(t)),
* but want to have y = Y^(X(t))
*/
static cmsToneCurve *
lcmsJoinToneCurve(cmsContext context_id, const cmsToneCurve *X,
const cmsToneCurve *Y, unsigned int resulting_points)
{
cmsToneCurve *out = NULL;
float t, x;
float *res = NULL;
unsigned int i;
res = zalloc(resulting_points * sizeof(float));
if (res == NULL)
goto error;
for (i = 0; i < resulting_points; i++) {
t = (float)i / (resulting_points - 1);
x = cmsEvalToneCurveFloat(X, t);
res[i] = cmsEvalToneCurveFloat(Y, x);
}
out = cmsBuildTabulatedToneCurveFloat(context_id, resulting_points, res);
error:
if (res != NULL)
free(res);
return out;
}
/**
* Extract EOTF from matrix-shaper and cLUT profiles,
* then invert and concatenate with 'vcgt' curve if it
* is available.
*/
bool
retrieve_eotf_and_output_inv_eotf(cmsContext lcms_ctx,
cmsHPROFILE hProfile,
cmsToneCurve *output_eotf[3],
cmsToneCurve *output_inv_eotf_vcgt[3],
cmsToneCurve *vcgt[3],
unsigned int num_points)
{
cmsToneCurve *curve = NULL;
const cmsToneCurve * const *vcgt_curves;
unsigned i;
cmsTagSignature tags[] = {
cmsSigRedTRCTag, cmsSigGreenTRCTag, cmsSigBlueTRCTag
};
if (cmsIsMatrixShaper(hProfile)) {
/**
* Optimization for matrix-shaper profile
* May have 1DLUT->3x3->3x3->1DLUT, 1DLUT->3x3->1DLUT
*/
for (i = 0 ; i < 3; i++) {
curve = cmsReadTag(hProfile, tags[i]);
if (!curve)
goto fail;
output_eotf[i] = cmsDupToneCurve(curve);
if (!output_eotf[i])
goto fail;
}
} else {
/**
* Linearization of cLUT profile may have 1DLUT->3DLUT->1DLUT,
* 1DLUT->3DLUT, 3DLUT
*/
if (!build_eotf_from_clut_profile(lcms_ctx, hProfile,
output_eotf, num_points))
goto fail;
}
/**
* If the caller looking for eotf only then return early.
* It could be used for input profile when identity case: EOTF + INV_EOTF
* in pipeline only.
*/
if (output_inv_eotf_vcgt == NULL)
return true;
for (i = 0; i < 3; i++) {
curve = cmsReverseToneCurve(output_eotf[i]);
if (!curve)
goto fail;
output_inv_eotf_vcgt[i] = curve;
}
vcgt_curves = cmsReadTag(hProfile, cmsSigVcgtTag);
if (vcgt_curves && vcgt_curves[0] && vcgt_curves[1] && vcgt_curves[2]) {
for (i = 0; i < 3; i++) {
curve = lcmsJoinToneCurve(lcms_ctx,
output_inv_eotf_vcgt[i],
vcgt_curves[i], num_points);
if (!curve)
goto fail;
cmsFreeToneCurve(output_inv_eotf_vcgt[i]);
output_inv_eotf_vcgt[i] = curve;
if (vcgt)
vcgt[i] = cmsDupToneCurve(vcgt_curves[i]);
}
}
return true;
fail:
cmsFreeToneCurveTriple(output_eotf);
cmsFreeToneCurveTriple(output_inv_eotf_vcgt);
return false;
}
/* FIXME: sync with spec! */ /* FIXME: sync with spec! */
static bool static bool
validate_icc_profile(cmsHPROFILE profile, char **errmsg) validate_icc_profile(cmsHPROFILE profile, char **errmsg)
@@ -102,15 +319,37 @@ cmlcms_color_profile_create(struct weston_color_manager_lcms *cm,
return cprof; return cprof;
} }
static void void
cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof) cmlcms_color_profile_destroy(struct cmlcms_color_profile *cprof)
{ {
wl_list_remove(&cprof->link); wl_list_remove(&cprof->link);
cmsFreeToneCurveTriple(cprof->vcgt);
cmsFreeToneCurveTriple(cprof->output_eotf);
cmsFreeToneCurveTriple(cprof->output_inv_eotf_vcgt);
cmsCloseProfile(cprof->profile); cmsCloseProfile(cprof->profile);
free(cprof->base.description); free(cprof->base.description);
free(cprof); free(cprof);
} }
struct cmlcms_color_profile *
ref_cprof(struct cmlcms_color_profile *cprof)
{
if (!cprof)
return NULL;
weston_color_profile_ref(&cprof->base);
return cprof;
}
void
unref_cprof(struct cmlcms_color_profile *cprof)
{
if (!cprof)
return;
weston_color_profile_unref(&cprof->base);
}
static char * static char *
make_icc_file_description(cmsHPROFILE profile, make_icc_file_description(cmsHPROFILE profile,
const struct cmlcms_md5_sum *md5sum, const struct cmlcms_md5_sum *md5sum,
@@ -131,6 +370,52 @@ make_icc_file_description(cmsHPROFILE profile,
return desc; return desc;
} }
/**
*
* Build stock profile which available for clients unaware of color management
*/
bool
cmlcms_create_stock_profile(struct weston_color_manager_lcms *cm)
{
cmsHPROFILE profile;
struct cmlcms_md5_sum md5sum;
char *desc = NULL;
profile = cmsCreate_sRGBProfileTHR(cm->lcms_ctx);
if (!profile) {
weston_log("color-lcms: error: cmsCreate_sRGBProfileTHR failed\n");
return false;
}
if (!cmsMD5computeID(profile)) {
weston_log("Failed to compute MD5 for ICC profile\n");
goto err_close;
}
cmsGetHeaderProfileID(profile, md5sum.bytes);
desc = make_icc_file_description(profile, &md5sum, "sRGB stock");
if (!desc)
goto err_close;
cm->sRGB_profile = cmlcms_color_profile_create(cm, profile, desc, NULL);
if (!cm->sRGB_profile)
goto err_close;
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
cm->sRGB_profile->profile,
cm->sRGB_profile->output_eotf,
cm->sRGB_profile->output_inv_eotf_vcgt,
cm->sRGB_profile->vcgt,
cmlcms_reasonable_1D_points()))
goto err_close;
return true;
err_close:
free(desc);
cmsCloseProfile(profile);
return false;
}
bool bool
cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm_base, cmlcms_get_color_profile_from_icc(struct weston_color_manager *cm_base,
const void *icc_data, const void *icc_data,
+185 -55
View File
@@ -33,48 +33,98 @@
#include "color-lcms.h" #include "color-lcms.h"
#include "shared/helpers.h" #include "shared/helpers.h"
/* Arguments to cmsBuildParametricToneCurve() */ /**
struct tone_curve_def { * The method is used in linearization of an arbitrary color profile
cmsInt32Number cmstype; * when EOTF is retrieved we want to know a generic way to decide the number
cmsFloat64Number params[5]; * of points
};
/*
* LCMS uses the required number of 'params' based on 'cmstype', the parametric
* tone curve number. LCMS honors negative 'cmstype' as inverse function.
* These are LCMS built-in parametric tone curves.
*/ */
static const struct tone_curve_def predefined_eotf_curves[] = { unsigned int
[CMLCMS_TYPE_EOTF_sRGB] = { cmlcms_reasonable_1D_points(void)
.cmstype = 4, {
.params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 }, return 1024;
}, }
[CMLCMS_TYPE_EOTF_sRGB_INV] = {
.cmstype = -4, static unsigned int
.params = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 }, cmlcms_reasonable_3D_points(void)
}, {
}; return 33;
}
static void static void
cmlcms_fill_in_tone_curve(struct weston_color_transform *xform_base, fill_in_curves(cmsToneCurve *curves[3], float *values, unsigned len)
float *values, unsigned len)
{ {
struct cmlcms_color_transform *xform = get_xform(xform_base);
float *R_lut = values; float *R_lut = values;
float *G_lut = R_lut + len; float *G_lut = R_lut + len;
float *B_lut = G_lut + len; float *B_lut = G_lut + len;
unsigned i; unsigned i;
cmsFloat32Number x, y; cmsFloat32Number x;
assert(xform->curve != NULL);
assert(len > 1);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
x = (double)i / (len - 1); x = (double)i / (len - 1);
y = cmsEvalToneCurveFloat(xform->curve, x); R_lut[i] = cmsEvalToneCurveFloat(curves[0], x);
R_lut[i] = y; G_lut[i] = cmsEvalToneCurveFloat(curves[1], x);
G_lut[i] = y; B_lut[i] = cmsEvalToneCurveFloat(curves[2], x);
B_lut[i] = y; }
}
static void
cmlcms_fill_in_pre_curve(struct weston_color_transform *xform_base,
float *values, unsigned len)
{
struct cmlcms_color_transform *xform = get_xform(xform_base);
assert(xform->search_key.category == CMLCMS_CATEGORY_BLEND_TO_OUTPUT);
assert(len > 1);
fill_in_curves(xform->search_key.output_profile->output_inv_eotf_vcgt,
values, len);
}
/**
* Clamp value to [0.0, 1.0], except pass NaN through.
*
* This function is not intended for hiding NaN.
*/
static float
ensure_unorm(float v)
{
if (v <= 0.0f)
return 0.0f;
if (v > 1.0f)
return 1.0f;
return v;
}
static void
cmlcms_fill_in_3dlut(struct weston_color_transform *xform_base,
float *lut, unsigned int len)
{
struct cmlcms_color_transform *xform = get_xform(xform_base);
float rgb_in[3];
float rgb_out[3];
unsigned int index;
unsigned int value_b, value_r, value_g;
float divider = len - 1;
assert(xform->search_key.category == CMLCMS_CATEGORY_INPUT_TO_BLEND ||
xform->search_key.category == CMLCMS_CATEGORY_INPUT_TO_OUTPUT);
for (value_b = 0; value_b < len; value_b++) {
for (value_g = 0; value_g < len; value_g++) {
for (value_r = 0; value_r < len; value_r++) {
rgb_in[0] = (float)value_r / divider;
rgb_in[1] = (float)value_g / divider;
rgb_in[2] = (float)value_b / divider;
cmsDoTransform(xform->cmap_3dlut, rgb_in, rgb_out, 1);
index = 3 * (value_r + len * (value_g + len * value_b));
lut[index ] = ensure_unorm(rgb_out[0]);
lut[index + 1] = ensure_unorm(rgb_out[1]);
lut[index + 2] = ensure_unorm(rgb_out[2]);
}
}
} }
} }
@@ -82,55 +132,135 @@ void
cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform) cmlcms_color_transform_destroy(struct cmlcms_color_transform *xform)
{ {
wl_list_remove(&xform->link); wl_list_remove(&xform->link);
if (xform->curve)
cmsFreeToneCurve(xform->curve); if (xform->cmap_3dlut)
cmsDeleteTransform(xform->cmap_3dlut);
unref_cprof(xform->search_key.input_profile);
unref_cprof(xform->search_key.output_profile);
free(xform); free(xform);
} }
static bool
xform_set_cmap_3dlut(struct cmlcms_color_transform *xform,
cmsHPROFILE input_profile,
cmsHPROFILE output_profile,
cmsToneCurve *curves[3],
cmsUInt32Number intent)
{
struct weston_color_manager_lcms *cm = get_cmlcms(xform->base.cm);
cmsHPROFILE arr_prof[3] = { input_profile, output_profile, NULL };
int num_profiles = 2;
if (curves[0]) {
arr_prof[2] = cmsCreateLinearizationDeviceLinkTHR(cm->lcms_ctx,
cmsSigRgbData,
curves);
if (!arr_prof[2])
return false;
num_profiles = 3;
}
xform->cmap_3dlut = cmsCreateMultiprofileTransformTHR(cm->lcms_ctx,
arr_prof,
num_profiles,
TYPE_RGB_FLT,
TYPE_RGB_FLT,
intent,
0);
if (!xform->cmap_3dlut) {
cmsCloseProfile(arr_prof[2]);
weston_log("color-lcms error: fail cmsCreateMultiprofileTransformTHR.\n");
return false;
}
xform->base.mapping.type = WESTON_COLOR_MAPPING_TYPE_3D_LUT;
xform->base.mapping.u.lut3d.fill_in = cmlcms_fill_in_3dlut;
xform->base.mapping.u.lut3d.optimal_len =
cmlcms_reasonable_3D_points();
cmsCloseProfile(arr_prof[2]);
return true;
}
static struct cmlcms_color_transform * static struct cmlcms_color_transform *
cmlcms_color_transform_create(struct weston_color_manager_lcms *cm, cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
const struct cmlcms_color_transform_search_param *param) const struct cmlcms_color_transform_search_param *search_param)
{ {
struct cmlcms_color_profile *input_profile = search_param->input_profile;
struct cmlcms_color_profile *output_profile = search_param->output_profile;
struct cmlcms_color_transform *xform; struct cmlcms_color_transform *xform;
const struct tone_curve_def *tonedef; bool ok = false;
if (param->type < 0 || param->type >= CMLCMS_TYPE__END) {
weston_log("color-lcms error: bad color transform type in %s.\n",
__func__);
return NULL;
}
tonedef = &predefined_eotf_curves[param->type];
xform = zalloc(sizeof *xform); xform = zalloc(sizeof *xform);
if (!xform) if (!xform)
return NULL; return NULL;
xform->curve = cmsBuildParametricToneCurve(cm->lcms_ctx, weston_color_transform_init(&xform->base, &cm->base);
tonedef->cmstype, wl_list_init(&xform->link);
tonedef->params); xform->search_key = *search_param;
if (xform->curve == NULL) { xform->search_key.input_profile = ref_cprof(input_profile);
weston_log("color-lcms error: failed to build parametric tone curve.\n"); xform->search_key.output_profile = ref_cprof(output_profile);
free(xform);
return NULL; /* Ensure the linearization etc. have been extracted. */
if (!output_profile->output_eotf[0]) {
if (!retrieve_eotf_and_output_inv_eotf(cm->lcms_ctx,
output_profile->profile,
output_profile->output_eotf,
output_profile->output_inv_eotf_vcgt,
output_profile->vcgt,
cmlcms_reasonable_1D_points()))
goto error;
} }
weston_color_transform_init(&xform->base, &cm->base); switch (search_param->category) {
xform->search_key = *param; case CMLCMS_CATEGORY_INPUT_TO_BLEND:
/* Use EOTF to linearize the result. */
ok = xform_set_cmap_3dlut(xform, input_profile->profile,
output_profile->profile,
output_profile->output_eotf,
search_param->intent_output);
break;
case CMLCMS_CATEGORY_INPUT_TO_OUTPUT:
/* Apply also VCGT if it exists. */
ok = xform_set_cmap_3dlut(xform, input_profile->profile,
output_profile->profile,
output_profile->vcgt,
search_param->intent_output);
break;
case CMLCMS_CATEGORY_BLEND_TO_OUTPUT:
xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D; xform->base.pre_curve.type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D;
xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_tone_curve; xform->base.pre_curve.u.lut_3x1d.fill_in = cmlcms_fill_in_pre_curve;
xform->base.pre_curve.u.lut_3x1d.optimal_len = 256; xform->base.pre_curve.u.lut_3x1d.optimal_len =
cmlcms_reasonable_1D_points();
ok = true;
break;
}
if (!ok)
goto error;
wl_list_insert(&cm->color_transform_list, &xform->link); wl_list_insert(&cm->color_transform_list, &xform->link);
return xform; return xform;
error:
cmlcms_color_transform_destroy(xform);
weston_log("CM cmlcms_color_transform_create failed\n");
return NULL;
} }
static bool static bool
transform_matches_params(const struct cmlcms_color_transform *xform, transform_matches_params(const struct cmlcms_color_transform *xform,
const struct cmlcms_color_transform_search_param *param) const struct cmlcms_color_transform_search_param *param)
{ {
if (xform->search_key.type != param->type) if (xform->search_key.category != param->category)
return false;
if (xform->search_key.intent_output != param->intent_output ||
xform->search_key.output_profile != param->output_profile ||
xform->search_key.input_profile != param->input_profile)
return false; return false;
return true; return true;
-1
View File
@@ -2,7 +2,6 @@ if not get_option('color-management-lcms')
subdir_done() subdir_done()
endif endif
dep_lcms2 = dependency('lcms2', version: '>= 2.9', required: false)
if not dep_lcms2.found() if not dep_lcms2.found()
error('color-lcms plugin requires lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.') error('color-lcms plugin requires lcms2 which was not found. Or, you can use \'-Dcolor-management-lcms=false\'.')
endif endif
+33 -37
View File
@@ -35,6 +35,18 @@ struct weston_color_manager_noop {
struct weston_color_manager base; struct weston_color_manager base;
}; };
static bool
check_output_eotf_mode(struct weston_output *output)
{
if (output->eotf_mode == WESTON_EOTF_MODE_SDR)
return true;
weston_log("Error: color manager no-op does not support EOTF mode %s of output %s.\n",
weston_eotf_mode_to_str(output->eotf_mode),
output->name);
return false;
}
static struct weston_color_manager_noop * static struct weston_color_manager_noop *
get_cmnoop(struct weston_color_manager *cm_base) get_cmnoop(struct weston_color_manager *cm_base)
{ {
@@ -74,6 +86,9 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
/* TODO: Assert surface has no colorspace set */ /* TODO: Assert surface has no colorspace set */
assert(output->color_profile == NULL); assert(output->color_profile == NULL);
if (!check_output_eotf_mode(output))
return false;
/* Identity transform */ /* Identity transform */
surf_xform->transform = NULL; surf_xform->transform = NULL;
surf_xform->identity_pipeline = true; surf_xform->identity_pipeline = true;
@@ -81,43 +96,29 @@ cmnoop_get_surface_color_transform(struct weston_color_manager *cm_base,
return true; return true;
} }
static bool static struct weston_output_color_outcome *
cmnoop_get_output_color_transform(struct weston_color_manager *cm_base, cmnoop_create_output_color_outcome(struct weston_color_manager *cm_base,
struct weston_output *output, struct weston_output *output)
struct weston_color_transform **xform_out)
{ {
struct weston_output_color_outcome *co;
assert(output->color_profile == NULL); assert(output->color_profile == NULL);
/* Identity transform */ if (!check_output_eotf_mode(output))
*xform_out = NULL; return NULL;
return true; co = zalloc(sizeof *co);
} if (!co)
return NULL;
static bool /* Identity transform on everything */
cmnoop_get_sRGB_to_output_color_transform(struct weston_color_manager *cm_base, co->from_blend_to_output = NULL;
struct weston_output *output, co->from_sRGB_to_blend = NULL;
struct weston_color_transform **xform_out) co->from_sRGB_to_output = NULL;
{
assert(output->color_profile == NULL);
/* Identity transform */ co->hdr_meta.group_mask = 0;
*xform_out = NULL;
return true; return co;
}
static bool
cmnoop_get_sRGB_to_blend_color_transform(struct weston_color_manager *cm_base,
struct weston_output *output,
struct weston_color_transform **xform_out)
{
assert(output->color_profile == NULL);
/* Identity transform */
*xform_out = NULL;
return true;
} }
static bool static bool
@@ -153,13 +154,8 @@ weston_color_manager_noop_create(struct weston_compositor *compositor)
cm->base.destroy_color_profile = cmnoop_destroy_color_profile; cm->base.destroy_color_profile = cmnoop_destroy_color_profile;
cm->base.get_color_profile_from_icc = cmnoop_get_color_profile_from_icc; cm->base.get_color_profile_from_icc = cmnoop_get_color_profile_from_icc;
cm->base.destroy_color_transform = cmnoop_destroy_color_transform; cm->base.destroy_color_transform = cmnoop_destroy_color_transform;
cm->base.get_surface_color_transform = cm->base.get_surface_color_transform = cmnoop_get_surface_color_transform;
cmnoop_get_surface_color_transform; cm->base.create_output_color_outcome = cmnoop_create_output_color_outcome;
cm->base.get_output_color_transform = cmnoop_get_output_color_transform;
cm->base.get_sRGB_to_output_color_transform =
cmnoop_get_sRGB_to_output_color_transform;
cm->base.get_sRGB_to_blend_color_transform =
cmnoop_get_sRGB_to_blend_color_transform;
return &cm->base; return &cm->base;
} }
+52
View File
@@ -297,3 +297,55 @@ out_close:
close(fd); close(fd);
return cprof; return cprof;
} }
/** Get a string naming the EOTF mode
*
* \internal
*/
WL_EXPORT const char *
weston_eotf_mode_to_str(enum weston_eotf_mode e)
{
switch (e) {
case WESTON_EOTF_MODE_NONE: return "(none)";
case WESTON_EOTF_MODE_SDR: return "SDR";
case WESTON_EOTF_MODE_TRADITIONAL_HDR: return "traditional gamma HDR";
case WESTON_EOTF_MODE_ST2084: return "ST2084";
case WESTON_EOTF_MODE_HLG: return "HLG";
}
return "???";
}
/** A list of EOTF modes as a string
*
* \param eotf_mask Bitwise-or'd enum weston_eotf_mode values.
* \return Comma separated names of the listed EOTF modes. Must be free()'d by
* the caller.
*/
WL_EXPORT char *
weston_eotf_mask_to_str(uint32_t eotf_mask)
{
FILE *fp;
char *str = NULL;
size_t size = 0;
unsigned i;
const char *sep = "";
fp = open_memstream(&str, &size);
if (!fp)
return NULL;
for (i = 0; eotf_mask; i++) {
uint32_t bitmask = 1u << i;
if (eotf_mask & bitmask) {
fprintf(fp, "%s%s", sep,
weston_eotf_mode_to_str(bitmask));
sep = ", ";
}
eotf_mask &= ~bitmask;
}
fclose(fp);
return str;
}

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