Compare commits

..

240 Commits

Author SHA1 Message Date
Andrea Cavalli ea5e7c688e Test 2021-09-12 16:41:24 +02:00
Andrea Cavalli f5a4fe32db Test 2021-09-12 16:22:16 +02:00
Andrea Cavalli 672bba9ed0 Test 2021-09-12 16:08:21 +02:00
Andrea Cavalli d448ffcb05 Test 2021-09-12 16:05:52 +02:00
Andrea Cavalli 012d982d90 Test 2021-09-12 16:00:33 +02:00
Andrea Cavalli 6d2e5cd62e Change defaults 2021-09-12 15:57:52 +02:00
Andrea Cavalli e2d60a037c Change defaults 2021-09-12 15:44:42 +02:00
Andrea Cavalli 52687e0853 default 192DPI 2021-09-12 13:19:26 +02:00
Ryan Gonzalez 18f1ce0b6e xwayland: Clear output buffers on scale change 2021-08-23 13:21:28 -05:00
Ryan Gonzalez aa849658c5 xwayland: Allow controlling global output scale via properties
This adds a new property, _XWAYLAND_GLOBAL_OUTPUT_SCALE, to control the
global output scale from the compositor.
2021-08-23 13:21:28 -05:00
Christopher Snowhill b46a9bba29 xwayland: Fix cursor size, present scale, and present damage 2021-08-23 13:21:28 -05:00
Dario Nieuwenhuis fbc7cefc43 xwayland: Multi DPI support via global factor rescaling
To benefit from Wayland's multi DPI capabilities in XWayland a global scaling
factor is introduced, which is applied to all outputs.

The RandR size of an output is calculated by the (integer-)multiplication of
this global scaling factor with its logical size received via the xdg-output
protocol.

In other words the size of any RandR screen corresponds to the mode size of
its wl_output multiplied with the quotient of global scaling factor divided by
the compositor's internal output-dependent scaling factor.

HiDPI aware X clients can then provide Pixmaps enlarged by the global scaling
factor and the Wayland compositor is supposed to downscale these buffers on
outputs scaled by less than the global scaling factor.

A Wayland compositor needs to scale all X communication in its XWM part by the
global scaling factor, such that X windows have the correct geometry.

In summary:
* All positions in Wayland internal communication must be carried out by the
compositor in logical coordinates, i.e. in its compositor space.
* All positions in X internal communication are based on RandR sizes.
* All positions in Wayland to X communication must be multiplied by the global
scaling factor.
* All positions in X to Wayland communication must be divided by the global
scaling factor.

In order to not break compositors that do not support these transformations,
the global scaling factor is set to 1 by default, which behaves the same as
before.

[dirbaio@dirbaio.net: fix incorrect scaling in a few places]
[rymg19@gmail.com: minor style fixes]
Signed-off-by: Roman Gilg <subdiff@gmail.com>
Signed-off-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
2021-08-23 13:21:28 -05:00
Povilas Kanapickas 18d3131f9a meson: Implement developer documentation build
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-08-20 10:26:07 +00:00
Povilas Kanapickas 722da1c62c meson: Add option to disable libdrm support
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-08-20 07:11:44 +00:00
Adam Jackson 1f720dc9a3 dmx: Fix some redeclaration warnings from gcc 11
Of the form:

    ../hw/dmx/config/xdmxconfig.c:68:26: warning: redundant redeclaration of ‘dmxConfigEntry’ [-Wredundant-decls]
       68 | extern DMXConfigEntryPtr dmxConfigEntry;
          |                          ^~~~~~~~~~~~~~
2021-08-17 16:06:57 -04:00
Adam Jackson b49f0f9b32 xkb: Silence a warning from gcc 11
I get this:

    In function ‘TryCopyStr’,
        inlined from ‘CopyISOLockArgs’ at ../xkb/xkbtext.c:875:9:
    ../xkb/xkbtext.c:720:13: warning: ‘tbuf’ may be used uninitialized [-Wmaybe-uninitialized]
      720 |             strcat(to, from);
          |             ^~~~~~~~~~~~~~~~
    ../xkb/xkbtext.c: In function ‘CopyISOLockArgs’:
    <built-in>: note: by argument 1 of type ‘const char *’ to ‘__builtin_strlen’ declared here
    ../xkb/xkbtext.c:871:10: note: ‘tbuf’ declared here
      871 |     char tbuf[64];
          |          ^~~~

Just initialize tbuf so it definitely works.
2021-08-17 16:04:40 -04:00
Adam Jackson c1138d8ec8 xinput: Silence a warning from gcc 11
[45/388] Compiling C object Xi/liblibxserver_xi.a.p/xichangehierarchy.c.o
../Xi/xichangehierarchy.c:61:32: warning: argument 1 of type ‘int[256]’ with mismatched bound [-Warray-parameter=]
   61 | XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
      |                            ~~~~^~~~~~~~~~~~~~~~~
In file included from ../Xi/xichangehierarchy.c:54:
../Xi/xichangehierarchy.h:42:37: note: previously declared as ‘int[]’
   42 | void XISendDeviceHierarchyEvent(int flags[]);
      |                                 ~~~~^~~~~~~
2021-08-17 16:02:44 -04:00
Adam Jackson f3a98334e6 selinux: Stop using security_context_t
This is apparently deprecated now and is and was always just char *.
2021-08-17 16:02:39 -04:00
Simon Ser 6f63873da5 xwayland: fix xdg_output leak
The xdg_output wasn't cleaned up when destroying the xwl_output.

Signed-off-by: Simon Ser <contact@emersion.fr>
2021-08-12 07:07:26 +00:00
Demi Marie Obenour 659260a0b7 More missing version checks in SProcs
The bug in XFixes was also found in GenericEvent and Damage.
2021-08-08 12:43:01 +00:00
Roman Gilg e4dabe8d93 Remove build-only include from public header
The dix-config.h file is not installed, but dix.h is. The include makes the
compilation of external drivers fail (for example the libinput driver).

The Xserver compilation also works without the include, so just remove it.

Signed-off-by: Roman Gilg <subdiff@gmail.com>
2021-08-07 14:26:26 +02:00
Demi Marie Obenour 31fb35a7af XFixes: add version check for byteswapped clients
The version check for byteswapped clients was missing.
2021-08-06 11:12:40 -04:00
Olivier Fourdan 7eba412072 xfree86: Move xf86CVTMode() function
The xf86CVTMode() was implemented in a standalone source file because it
was being used for both the xfree86 API and the standalone cvt utility.

Now that the cvt utility is removed (as part of libxcvt) we can move the
small xf86CVTMode() function with the rest of the xf86Modes sources.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1142
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2021-08-06 11:29:29 +00:00
Olivier Fourdan f2781e9536 xfree86/cvt: Drop cvt utility
The cvt utility is now replaced by the standalone version found in
libxcvt, no need to build the one in xfree86 anymore.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1142
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2021-08-06 11:29:29 +00:00
Olivier Fourdan f788289bdc xfree86: Use libxcvt
Replace the local implementation of the VESA CVT standard timing
modelines generator with the one from libxct to avoid code duplication.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1142
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2021-08-06 11:29:29 +00:00
Olivier Fourdan 6ea2c001f9 xwayland: Use libxcvt
Xwayland is using a copy of the CVT generator found in Xorg.

Rather than duplicating the code within the xserver tree, use the
libxcvt implementation instead.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1142
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2021-08-06 11:29:29 +00:00
Olivier Fourdan a4ab57cb74 build: Add dependency on libxcvt
libxcvt is a library providing a standalone version of the X server
implementation of the VESA CVT standard timing modelines generator.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1142
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
2021-08-06 11:29:29 +00:00
Olivier Fourdan 84897891e5 ci: Install libxcvt from git
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
2021-08-06 11:29:29 +00:00
Demi Marie Obenour 5c2592cbb1 Add do-while loops to DIX macros
This ensures they will behave properly in conditionals and always
require a trailing semicolon.
2021-07-31 08:55:52 -04:00
Alex Richardson d83c84bd9d Mark the dixChangeWindowProperty() value argument as const
It is copied using memcpy() and not modified so we can add const. This
fixes a -Wincompatible-pointer-types-discards-qualifiers compiler warning
that was failing a -Werror XVnc build for me.

Signed-off-by: Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
2021-07-30 08:36:35 +00:00
Zoltán Böszörményi fb5322ce28 glamoregl: Initialize glamor on the main device
This allows e.g. an UDL device (driven by llvmpipe) to be automatically
set up with GPU acceleration via reverse PRIME.

The result is e.g.:

  # DISPLAY=:0.2 xrandr --listproviders
  Providers: number : 2
  Provider 0: id: 0xec cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 1 outputs: 1 associated providers: 1 name:modesetting
  Provider 1: id: 0x12c cap: 0xb, Source Output, Sink Output, Sink Offload crtcs: 2 outputs: 2 associated providers: 1 name:Intel

Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2021-07-30 00:27:39 +00:00
Zoltán Böszörményi f08bc32f5a xf86: Assign GPUs to screens according to configuration
If there is an explicit configuration, assign the RandR provider
of the GPUDevice to the screen it was specified for.

If there is no configuration (default case) the screen number is
still 0 so it doesn't change behaviour.

The result is e.g:

  # DISPLAY=:0.2 xrandr --listproviders
  Providers: number : 2
  Provider 0: id: 0xd2 cap: 0x2, Sink Output crtcs: 1 outputs: 1 associated providers: 0 name:modesetting
  Provider 1: id: 0xfd cap: 0xb, Source Output, Sink Output, Sink Offload crtcs: 2 outputs: 2 associated providers: 0 name:Intel

Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2021-07-30 00:27:39 +00:00
Zoltán Böszörményi cd567415cc xf86: Extract screen configuration matching into its own function
Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2021-07-30 00:27:39 +00:00
Boris-Barboris 16571b8926 Don't hardcode fps for fake screen
Currently, when main hardware screen is powered-off,
X server initializes fake screen's timer with
1 second update interval.

Streaming software like Nomachine or Vnc, as well as
desktop input automation suffers from it, since it
will forever be stuck on 1 fps until the display is
turned back on.

This commit adds command line option -fakescreenfps <int>
that allows the user to change the default fake screen
timer.

Signed-off-by: Baranin Alexander <ismailsiege@gmail.com>
2021-07-29 08:09:00 +00:00
Łukasz Spintzyk 8836b9d243 modesetting: unflip not possible when glamor is not set
This is fixing crashes of xfce when running under qemu
2021-07-22 13:24:21 +02:00
Łukasz Spintzyk d6c02ffd9c present: fallback get_crtc to return crtc belonging to screen with present extension
Since crtc can belong to secondary output that may not have present
extension enabled we should fallback to first enabled crtc or fake crtc.

Fix for issue xorg/xserver#1195
2021-07-20 08:10:46 +02:00
Michel Dänzer f6f2f203bc present: Drop flip_idler member from present_vblank_rec
It's redundant with the pixmap member of struct xwl_present_event.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:20:56 +02:00
Michel Dänzer 212cfbcf68 xwayland/present: Use present_vblank_ptr instead of xwl_present_event*
Where the latter isn't really needed.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:20:35 +02:00
Michel Dänzer fe8c7855f3 xwayland/present: Fold xwl_present_release_event into _free_event
The only difference was unhooking from the vblank.event_queue list,
which is already done by xwl_present_flip_notify_vblank in
xwl_present_msc_bump.
2021-07-09 16:20:20 +02:00
Michel Dänzer 31d2ebca77 xwayland/present: Drop target_msc member from struct xwl_present_event
Use present_vblank_rec::exec_msc instead.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:20:04 +02:00
Michel Dänzer 495ec59664 xwayland/present: Drop pending member from struct xwl_present_event
We are handling two cases here: the active flip or the pending flip.

For the pending flip (event->pending == TRUE), we called
xwl_present_release_pixmap.

For the active flip (event->pending == FALSE), we called
xwl_present_release_event. However, xwl_present_flip_notify_vblank
already unhooked event->vblank.event_queue. So this was effectively the
same as calling xwl_present_release_pixmap.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:19:30 +02:00
Michel Dänzer f73340445f xwayland/present: Drop list member from struct xwl_present_event
Use present_vblank_rec::event_queue instead.

The changes in xwl_present_execute shouldn't really be needed, since
we should never hit queue_vblank in present_execute_wait. But let's be
safe rather than sorry, plus this simplifies the code.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:18:56 +02:00
Michel Dänzer aac31d2758 xwayland/present: Drop exec_queue member from struct xwl_present_window
Doesn't serve any purpose anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:18:47 +02:00
Michel Dänzer f8c086b214 xwayland/present: Fold xwl_present_event_notify into its caller
Can just call xwl_present_execute directly.

This allows dropping the window member from struct xwl_present_window as
well.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:18:33 +02:00
Michel Dänzer c30f3d08ac xwayland/present: Use exec_queue for deferring completion events
We clear the vblank->pixmap field, so next time xwl_present_execute
falls through to present_execute_post.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:18:07 +02:00
Michel Dänzer 4503c8d9ea xwayland/present: Fold xwl_present_idle_notify into its caller
Allows simplification by avoiding indirection.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:17:55 +02:00
Michel Dänzer b2a06e0700 xwayland/present: Drop sync_flip member of struct xwl_present_window
The same information can be determined from the flip queue.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:17:44 +02:00
Michel Dänzer fc53e3c536 xwaland/present: Drop flip_pending member of struct xwl_present_window
Use the first element of the flip_queue list for the same purpose.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:17:23 +02:00
Michel Dänzer c592c66625 xwayland/present: Fold xwl_present_flip_notify into its callers
No need for them to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:17:15 +02:00
Michel Dänzer 4230176080 xwayland/present: Embed present_vblank_rec in xwl_present_event
This allows for various simplifications.

Use the pointer to the struct memory as the event ID. In contrast to
the SCMD code for Xorg (where pending DRM events cannot be cancelled),
this is safe here, because we can destroy pending Wayland callbacks. So
we can't get a callback with a stale pointer to freed memory.

Remove xwl_present_window::release_list in favour of
present_vblank_rec::window_list.

Remove xwl_present_event::xwl_present_window in favour of
present_vblank_rec::window.

xwl_present_free_event is never called for a NULL pointer anymore, no
need to check.

v2:
* Restore DestroyWindow wrapping order to make sure
  present_destroy_window doesn't call xwl_present_abort_vblank.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:15:50 +02:00
Michel Dänzer 61cc5d96ed present: Refactor present_vblank_init helper ouf of _vblank_create
Allows embedding into another struct.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:15:39 +02:00
Michel Dänzer 35f173ddb6 xwayland/present: Drop abort member of struct xwl_present_event
We can call xwl_present_free_event unconditionally from
xwl_present_abort_vblank, since the sync_callback is already destroyed
in xwl_present_cleanup.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:15:10 +02:00
Michel Dänzer 0517460301 xwayland/present: Simplify calls to Xwayland-private functions
Change parameter types to what's really needed, or just fold the
function into its only caller.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:56 +02:00
Michel Dänzer 490248ea70 xwayland/present: Rename present_wnmd_* functions to xwl_present_*
The WNMD indirection is gone.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:47 +02:00
Michel Dänzer 0c0cbbc7cb present: Remove present_wnmd_info_rec
Doesn't serve any purpose anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:38 +02:00
Michel Dänzer 561c63d0f1 xwayland/present: Merge present_wnmd_flips_stop & xwl_present_flips_stop
Just use the latter instead of the former elsewhere. No need for them
to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:28 +02:00
Michel Dänzer a67f16fde1 xwayland/present: Fold present_wnmd_get_ust_msc into its callers
Just use xwl_present_get_ust_msc directly. No need for the indirection
anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:19 +02:00
Michel Dänzer 080c1ca3f5 xwayland/present: Fold present_wnmd_queue_vblank into its callers
Just use xwl_present_queue_vblank directly. No need for the indirection
anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:14:09 +02:00
Michel Dänzer c22887bc7a xwayland/present: Fold present_wnmd_get_crtc into present_wnmd_pixmap
And use xwl_present_get_crtc directly.

No need for them to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:59 +02:00
Michel Dänzer cb35ff596e xwayland/present: Fold present_wnmd_check_flip into its callers
Mainly into xwl_present_check_flip, and call that from
present_wnmd_check_flip_window.

No need for them to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:48 +02:00
Michel Dänzer 7b78cf6b3a xwayland/present: Simplify query_capabilities
No need for the WNMD indirection anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:39 +02:00
Michel Dänzer 244403ec87 xwayland/present: Fold present_wnmd_abort_vblank into its only caller
No need for them to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:32 +02:00
Michel Dänzer f7adbc2166 xwayland/present: Drop present_wnmd_flush in favour of xwl_present_flush
No need for the indirection anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:24 +02:00
Michel Dänzer 7fd114365d xwayland/present: Fold present_wnmd_flip into present_wnmd_execute
No need for the indirection anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:15 +02:00
Michel Dänzer 2e1dcd731f xwayland/present: Fold present_wnmd_screen_init into xwl_present_init
No need for them to be separate anymore.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:13:04 +02:00
Michel Dänzer b6419359b6 present: Move present_wnmd.c contents to hw/xwayland/xwayland-present.c
This will allow eliminating indirections and making the Xwayland Present
code more efficient and easier to follow.

While this technically changes the Xorg video driver ABI, I don't know
of any drivers using the dropped present_wnmd_* symbols, and I doubt a
Xorg driver could make use of them as is anyway.

(As a bonus, Xorg no longer links any Xwayland specific Present code)

v2:
* Wrap DestroyWindow before initializing Present, so that
  present_destroy_window runs before xwl_present_cleanup. Avoids crash
  due to present_destroy_window calling xwl_present_* functions when
  xwl_present_window was already freed. (Olivier Fourdan)

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:11:22 +02:00
Michel Dänzer c35a716b02 present: Fold wnmd_init_mode_hooks into wnmd_screen_init
Preparation for moving WNMD code to hw/xwayland. No functional change
intended.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:11:11 +02:00
Michel Dänzer 10bdd87fe4 present: Move present_wnmd_screen_init to present_wnmd.c
Now all WNMD code is in present_wnmd.c.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:11:02 +02:00
Michel Dänzer b6d54b0f5d present: Dispatch clear_window_flip via present_screen_priv hook
Eliminates special cases in present_destroy_window.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:10:54 +02:00
Michel Dänzer 93666ebe37 present: Remove create_event_id hook
Each present_vblank_create caller generates and sets the ID afterwards.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:10:43 +02:00
Michel Dänzer 44f705a5b6 present: Pass capabilities to present_vblank_create by value
Preparation for moving WNMD code to hw/xwayland. No functional change
intended.

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 16:10:06 +02:00
Michel Dänzer 86e645bcfa xwayland/eglstream: Drop xwl_eglstream_set_window_pixmap
Not sure why we'd need to abandon a pending stream for a pixmap just
because it's no longer a window pixmap. Let's try not to.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 15:51:43 +02:00
Michel Dänzer ba8763c27b xwayland/eglstream: Consolidate pending_cb destruction
Into a new xwl_eglstream_destroy_pending_stream helper.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 15:50:57 +02:00
Michel Dänzer 204f10c29e xwayland: Call RRTellChanged if the RandR configuration may have changed
This makes sure RandR events are sent to interested clients as needed.
This was happening implicitly in some cases, but not in others, e.g. if
the root window size didn't change.

If this were to call RRTellChanged more often than necessary in some
cases, that should be harmless, as it only sends events if something
has actually changed since last time.

Should fix https://bugzilla.redhat.com/show_bug.cgi?id=1979892 .

v2:
* Call RRTellChanged at the very end of update_screen_size, just in
  case.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 11:48:15 +02:00
Michel Dänzer a6d178b6af randr: Bail from RRTellChanged if there's no root window yet
This can happen if RRTellChanged is called during initialization.

Continuing in that case makes no sense conceptually:

* Any event sent over the wire requires a corresponding window.
* No root window probably means there can't be any clients which could
  receive the events.

In practice, it would result in a crash down the road due to
dereferencing the NULL ScreenRec::root pointer.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-07-09 11:48:15 +02:00
Matt Turner 7e20c8b7b8 Build xz tarballs instead of bzip2
Signed-off-by: Matt Turner <mattst88@gmail.com>
2021-07-08 12:32:01 -07:00
Dave Airlie a955286869 glamor: add EXT_gpu_shader4 support
This enables a number of the GLSL 1.30 paths on GPUs that have
EXT_gpu_shader4 but don't have GLSL 1.30 exposed.

(Intel gen4/5 mainly)

Reviewed-by: Adam Jackson <ajax@redhat.com>
2021-07-07 08:42:09 +10:00
Dave Airlie a2f5b917f5 glamor: add glamor_glsl_has_ints wrapper
This should make adding gpu shader4 support cleaner

Reviewed-by: Adam Jackson <ajax@redhat.com>
2021-07-07 08:41:50 +10:00
Povilas Kanapickas b4f55712da xserver 21.0.99.1
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-07-05 21:40:55 +03:00
Povilas Kanapickas b67e514dbb meson: Fix warnings when reading back and checking feature flags
Meson does not like comparing things of different types which is a
problem when reading back values of feature flags as they may contain
either false (bool) or 1 (string).

Since there is a strong reason why we use false when the feature does
not exist, we work around this issue by always converting the returned
value to int via to_int().

Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1190
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-07-05 12:46:14 +00:00
Adam Jackson b2a0de4f07 xfixes: Allow the client to upgrade the fixes protocol version
If you say FixesQueryVersion twice we remember whatever the second
version number was. With just libXfixes this isn't an issue because the
request is hidden in extension setup, but libxcb-xfixes doesn't do that
for you, which means the second one can _lower_ the requested fixes
version, disabling requests that the client thought it had enabled.

Paper over this by allowing the version number to be raised but not
lowered. Also go ahead and delete the minor version number from the
client state since xfixes doesn't have minor versions (yet, anyway).
2021-07-01 19:18:19 +00:00
Olivier Fourdan 7d509b6f34 xwayland/eglstream: Remove stream validity
To avoid an EGL stream in the wrong state, if the window pixmap changed
before the stream was connected, we would still keep the pending stream
but mark it as invalid. Once the callback is received, the pending would
be simply discarded.

But all of this is actually to avoid a bug in egl-wayland, there should
not be any problem with Xwayland destroying an EGL stream while the
compositor is still using it.

With that bug now fixed in egl-wayland 1.1.7, we can safely drop all
that logic from Xwayland EGLstream backend.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1189
2021-06-30 09:06:37 +02:00
Olivier Fourdan 2be9f795bc xwayland/eglstream: Keep pending stream if the pixmap didn't change
If the pixmap does not actually change in set_window_pixmap(), there is
no need to invalidate the pending stream, if there's one.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-06-29 15:59:41 +02:00
orbea 2531ee0245 hw/dmx/config: Link directly with libdmxconfig.a
When building xserver with slibtool (https://dev.midipix.org/cross/slibtool)
the build will fail.

  /usr/bin/ld: cannot find -ldmxconfig

This is because xserver creates libdmxconfig.a internally and then links with
the linker flag -ldmxconfig. However according to automake documentation the
-lfoo linker flags should only be used for external dependencies and all
internal libraries should be linked with the libtool archive file (.la) or
the static archive (.a) when the former is not available.

GNU libtool is far more permissive and happens to silently obscure this issue
while slibtool fails because it instead sees '-L./.libs -ldmxconfig'.
2021-06-25 18:54:46 +00:00
Povilas Kanapickas 2f53d1cf73 config: Fix platform busid parsing when there is no ID_PATH prop
On at least Lenovo Thinkpad E585 udev does not have ID_PATH property for
the drm node (see
https://gitlab.freedesktop.org/xorg/xserver/-/issues/993). While this is
likely udev bug, this causes the device to be not recognized as
attribs->busid is NULL, which causes platform_find_pci_info to be not
called and corresponding xf86_platform_devices[i]->pdev to be NULL.

At this moment pdev being NULL will cause a crash, but this is a
different bug.

Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/993
Fixes: 0816e8fc linux: Make platform device probe less fragile
Reviewed-by: Zoltán Böszörményi <zboszor@gmail.com>
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-25 13:24:51 +03:00
Olivier Certner d4b38e1119 os: Properly report failure to link lock file
Stop assuming that a failure to link always means that the file indeed
exists. In case of other failure (e.g., permissions), the user would get an
inconsistent "Can't read lock file" message.

Signed-off-by: Olivier Certner <olce.freedesktop@certner.fr>
2021-06-25 10:18:18 +00:00
Łukasz Spintzyk d66b7ec129 xfree86: Fix out of array bound access to xf86Entities
Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-06-24 09:05:57 +02:00
Povilas Kanapickas 0d93bbfa2c xfree86: Fix potentially NULL reference to platform device's PCI device
xf86_platform_devices[i].pdev may be NULL in cases we fail to parse the
busid in config_udev_odev_setup_attribs() (see also [1], [2]) such as
when udev does not give use ID_PATH. This in turn leads to
platform_find_pci_info() being not called and pdev being NULL.

[1]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/993
[2]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1076

Reviewed-by: Zoltán Böszörményi <zboszor@gmail.com>
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-23 14:29:10 +03:00
Povilas Kanapickas 303763941f xfree86: Consistently check for reference to primaryBus pci_device
This is the only place where we don't check whether
primaryBus.id.plat->pdev is not NULL before accessing its members.

It may be NULL in cases we fail to parse the busid in
config_udev_odev_setup_attribs() (see also [1], [2]) such as when udev
does not give use ID_PATH. This in turn leads to
platform_find_pci_info() being not called and pdev being NULL in one of
the items within the xf86_platform_devices array. For this to cause a
crash we only need it to become the primaryBus device.

[1]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/993
[2]: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1076

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-23 14:29:10 +03:00
Povilas Kanapickas b9722d39cd configure.ac: Switch project version to 20.x.y style
Reviewed-by: Zoltán Böszörményi <zboszor@gmail.com>
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-23 14:23:55 +03:00
Zoltán Böszörményi ef89b6648e xfree86: Fix NULL pointer dereference crash
screenp->displays[count] (passed to configDisplay() in
configScreen()) is NULL if there is no Virtual setting
in the configuration.

Fixes: f8a6be04d0 ("xfree86: Change
displays array to pointers array to fix invalid pointer issues
after table reallocation")

Signed-off-by: Zoltán Böszörményi <zboszor@gmail.com>
2021-06-21 14:11:37 +02:00
Olivier Fourdan aad61e8e03 glx: Fix use after free in MakeCurrent
The fix from commit c468d34c7 - "glx: Set ContextTag for all contexts"
is actually incomplete, it correctly sets the context tag for direct
contexts as well, but would fail to mark the context's currentClient.

As a result, when the context is destroyed, it would be freed
immediately rather than being just scheduled for deletion, even though
it is still current for some client. leading to a use-after-free.

Make sure to also set the context's currentClient for direct contexts as
well, not just indirect ones.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Fixes: c468d34c7 - "glx: Set ContextTag for all contexts"
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1186
Reviewed-by: Adam Jackson <ajax@redhat.com>
2021-06-21 08:39:38 +02:00
Povilas Kanapickas 021b3c2f77 configure.ac: Bump inputproto dep to 2.3.99.1
This should have been part of 6cbcbc81525b131b5b94409ea870af663d5c28bb.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-16 13:01:17 +00:00
Daniel Strnad 05b3c681ea hw/xfree86: Propagate physical dimensions from DRM connector
Physical dimmension of display can be obtained not just by configuration or
DDC, but also directly from kernel via drmModeGetConnector(). Until now
xserver silently discarded these values even when no configuration nor EDID
were present and fallbacked to default DPI.
2021-06-15 13:21:11 +00:00
Łukasz Spintzyk f8a6be04d0 xfree86: Change displays array to pointers array to fix invalid pointer issues after table reallocation
There are rare cases when xf86SetDepthBpp is resizing displays array in confScreen.
As that array is shared between set of ScrnInfoRec's then realloc might invalidate chached DispPtr display values in
otheres ScrnInfoRec objects.

If we will change displays array as an array of pointers to DispRec then cached DispRec pointers in ScrnInfoRec
won't be invalid after reallocation of displays array.

Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-06-15 10:01:14 +00:00
Povilas Kanapickas 1a1bd5cf7a modesetting: Add a limit on async page flip error log frequency
In certain circumstances we will have a lot of flip errors without a
reasonable way to prevent them. In such case we reduce the number of
logged messages to at least not fill the error logs.

The details are as follows:

At least on i915 hardware support for async page flip support depends on
the used modifiers which themselves can change dynamically for a screen.
This results in the following problems:

- We can't know about whether a particular CRTC will be able to do an
async flip without hardcoding the same logic as the kernel as there's no
interface to query this information.

- There is no way to give this information to an application, because
the protocol of the present extension does not specify anything about
changing of the capabilities on runtime or the need to re-query them.

Even if the above was solved, the only benefit would be avoiding a
roundtrip to the kernel and reduced amount of error logs. The former
does not seem to be a good enough benefit compared to the amount of work
that would need to be done. The latter is solved in this commit.

Reviewed-by: Eero Tamminen <eero.t.tamminen@intel.com>
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-15 12:53:33 +03:00
Povilas Kanapickas 9992245c5f modesetting: Extract flip failure logging to a single place
Reviewed-by: Eero Tamminen <eero.t.tamminen@intel.com>
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-06-15 12:53:33 +03:00
Jose Maria Casanova Crespo 9adb13e296 glamor: Avoid using GL_QUADS on V3D
Like in 0e3f1252da ("glamor: Avoid using GL_QUADS on VC4")
this will avoid mesa to fallback doing conversion for QUADS primitives.

Signed-off-by: Jose Maria Casanova Crespo <jmcasanova@igalia.com>
Reviewed-by: Emma Anholt <emma@anholt.net>
2021-06-14 21:36:13 +02:00
Michel Dänzer 104c7c5048 xwayland/present: Move wl_buffer check into xwl_glamor_check_flip
Keeps the glamor specific code together more.

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-06-14 10:44:03 +02:00
Michel Dänzer 3641c24bd0 xwayland/eglstream: Handle xwl_pixmap_get returning NULL
In xwl_glamor_eglstream_get_wl_buffer_for_pixmap. This can likely be hit
now with an SHM pixmap via the Present flip path. There might be other
corner cases.

Fixes: f3eb1684fa "xwayland: enable MIT-SHM shared pixmaps"
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-06-14 10:43:59 +02:00
Michel Dänzer d163e0a1d5 ci: Fix UPSTREAM_REPO -> FDO_UPSTREAM_REPO
The latter is what ci-templates expect.

Fixes: ab73c16930 "ci: Update to the latest templates"
Reviewed-by: Simon Ser <contact@emersion.fr>
2021-06-11 18:25:01 +02:00
Lukasz Spintzyk 7e7c147105 modesetting: Disable reverse prime offload mode for displays running on evdi,udl
This mode for displays running on evdi/udl as side effect of failed glamor_egl_init
reverse_prime_offload_mode was initialized to FALSE

After Mesa upgrade to 21.0.0 GL_RENDERER is not llvmpipe that results in successful glamor_egl_init
and reverse_prime_offload_mode enabled.

This commit is explicitly disabling reverse_prime_offload_mode for evdi and udl drivers

Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-06-08 16:20:36 +00:00
Olivier Fourdan c468d34c72 glx: Set ContextTag for all contexts
Currently, xorgGlxMakeCurrent() would set the context tag only for
indirect GLX contexts.

However, several other places expect to find a context for the tag or
they would raise a GLXBadContextTag error, such as WaitGL() or WaitX().

Set the context tag for direct contexts as well, to avoid raising an
error and possibly killing the client.

Thanks to Erik Kurzinger <ekurzinger@nvidia.com> for spotting the issue.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2021-06-08 07:20:53 +00:00
Olivier Fourdan 6b47321bc6 dix: Add optional terminate delay
When the command line option "-terminate" is used, it could be
interesting to give it an optional grace period to let the Xserver
running for a little longer in case a new connection occurs.

This adds an optional parameter to the "-terminate" command line option
for this purpose.

v2: Use a delay in seconds instead of milliseconds
    (Martin Peres <martin.peres@mupuf.org>)
v3: Clarify man page entry, ensure terminateDelay is always >= 0,
    simplify TimerFree(). (Peter Hutterer <peter.hutterer@who-t.net>)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-06-07 17:28:05 +02:00
Olivier Fourdan e167299f60 xfixes: Add ClientDisconnectMode
With Wayland compositors now being able to start Xwayland on demand, the
next logical step is to be able to stop Xwayland when there is no more
need for it.

The Xserver itself is capable of terminating itself once all X11 clients
are gone, yet in a typical full session, there are a number of X11
clients running continuously (e.g. the Xsettings daemon, IBus, etc.).

Those always-running clients will prevent the Xserver from terminating,
because the actual number of X11 clients will never drop to 0. Worse,
the X11 window manager of a Wayland compositor also counts as an X11
client, hence also preventing Xwayland from stopping.

Some compositors such as mutter use the XRes extension to query the X11
clients connected, match their PID with the actual executable name and
compare those with a list of executables that can be ignored when
deciding to kill the Xserver.

But that's not just clumsy, it is also racy, because a new X11 client
might initiate a connection the X11 server right when the compositor is
about to kill it.

To solve this issue directly at the Xserver level, this add new entries
to the XFixes extension to let the X11 clients themselves specify the
disconnect mode they expect.

Typically, those X11 daemon clients would specify the disconnect mode
XFixesClientDisconnectFlagTerminate to let the Xserver know that they
should not be accounted for when checking the remaining clients prior
to terminate.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-06-07 17:28:05 +02:00
Erik Kurzinger b7a85e44da glx: don't create implicit GLXWindow if one already exists
If a GLXMakeCurrent request specifies an X window as its drawable,
__glXGetDrawable will implicitly create a GLXWindow for it. However,
the client may have already explicitly created a GLXWindow for that X
window. If that happens, two __glXDrawableRes resources will be added
to the window.

If the explicitly-created GLXWindow is later destroyed by the client,
DrawableGone will call FreeResourceByType on the X window, but this
will actually free the resource for the implicitly-created GLXWindow,
since that one would be at the head of the list.

Then if the X window is destroyed after that, the resource for the
explicitly-created GLXWindow will be freed. But that GLXWindow was
already destroyed above. This crashes the server when it tries to call
the destroyed GLXWindow's destructor. It also means the
implicitly-created GLXWindow would have been leaked since the
FreeResourceByType call mentioned above skips calling the destructor.

To fix this, if __glXGetDrawable is given an X window, it should check
if there is already a GLXWindow associated with it, and only create an
implicit one if there is not.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2021-06-07 14:53:13 +00:00
Jan Beich 8274dd6643 meson: provide fallback for *proto dependencies
Meson has a built-in facility to use bundled versions of dependencies
if system packages are too old. Enable for xorgproto after 8e504d8b36eb:

Run-time dependency xproto found: YES 7.0.33
Run-time dependency randrproto found: YES 1.6.0
Run-time dependency renderproto found: YES 0.11.1
Run-time dependency xextproto found: YES 7.3.0
Dependency inputproto found: NO found 2.3.2 but need: '>= 2.3.99.1'
Found CMake: /usr/local/bin/cmake (3.20.2)
Run-time dependency inputproto found: NO (tried pkgconfig and cmake)
Looking for a fallback subproject for the dependency inputproto

meson.build:73:0: ERROR: Neither a subproject directory nor a xorgproto.wrap file was found.
2021-06-01 02:44:58 +00:00
Olivier Fourdan 34a58d7714 xwayland/eglstream: Log when GL_OES_EGL_image is missing
That will dramatically affect performance, might as well log when we
cannot use GL_OES_EGL_image with the NVIDIA closed-source driver.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-31 08:24:00 +00:00
Olivier Fourdan fae58e9b03 xwayland/eglstream: Use "nvidia" for GLVND
If the EGLStream backend is able to use hardware acceleration with the
NVIDIA closed source driver, we should use the "nvidia" GLX
implementation instead of the one from Mesa to take advantage of the
NVIDIA hardware accelerated rendering.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-31 08:24:00 +00:00
Olivier Fourdan 24fc8aea1e xwayland: Add preferred GLVND vendor to xwl_screen
If Xwayland's EGLstream backend supports hardware acceleration with the
NVIDIA closed-source driver, the GLX library also needs to be one
shipped by NVIDIA, that's what GLVND is for.

Add a new member to the xwl_screen that the backend can optionally set
to the preferred GLVND vendor to use.

If not set, "mesa" is assumed.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-31 08:24:00 +00:00
Niveditha Rau 2de5ded3c6 glx: Check for byte-swapping in SetReplyHeader
Check for the need to byte-swap when attempting to display
GL apps between a big-endian server and little-endian client
or vice versa.

Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1127
2021-05-30 13:49:37 -07:00
Adam Jackson bcb1de600a glx: Fix error return code in GLXGetDrawableAttributes
This should only ever throw GLXBadDrawable, says the protocol spec.
2021-05-30 10:59:58 +00:00
Povilas Kanapickas eb6f8daca5 Xi: Work around broken libxcb that doesn't ignore unknown device classes
libxcb 14.1 and older are not forwards-compatible with new device
classes as it does not properly ignore unknown device classes. Since
breaking libxcb would break quite a lot of applications, we instead
report Gesture device class only if the client advertised support for XI
2.4.

Clients may still not work in cases when a client advertises XI 2.4
support and then a completely separate module within the client uses
broken libxcb to call XIQueryDevice.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-05-30 13:46:59 +03:00
Povilas Kanapickas 7e692633fb Xi: Implement gesture support for XIQueryDevice 2021-05-30 13:46:59 +03:00
Povilas Kanapickas 0886254f96 xfree86: Bump input minor ABI due to addition touchpad gestures
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-05-30 13:26:46 +03:00
Povilas Kanapickas 1cdc3b5d14 xfree86: Implement gesture support for test input driver 2021-05-30 13:26:45 +03:00
Povilas Kanapickas dccc0275f4 Bump XI protocol version to 2.4 2021-05-30 13:26:44 +03:00
Povilas Kanapickas 75feb13668 Xi: Include gestures among events that may freeze device 2021-05-30 13:26:43 +03:00
Povilas Kanapickas 5163fc8bc2 Implement gesture processing logic 2021-05-30 13:26:42 +03:00
Povilas Kanapickas d3c52df161 hw/xfree86: Implement public APIs to submit gesture events 2021-05-30 13:26:41 +03:00
Povilas Kanapickas 100a2ad6da dix: Implement gesture event submission code path 2021-05-30 13:26:40 +03:00
Povilas Kanapickas 7656a9c8dd dix: Implement internal gesture state handling 2021-05-30 13:26:39 +03:00
Povilas Kanapickas 0bf4123fd3 dix: Implement gesture event fixups before delivery 2021-05-30 13:26:38 +03:00
Povilas Kanapickas 227f601de3 xi: Implement conversions from internal to Xi2 gesture event structs 2021-05-30 13:26:37 +03:00
Povilas Kanapickas f3462178ca test/xi2: Verify that XI_GestureSwipeEnd is ignored when outside mask 2021-05-30 13:26:36 +03:00
Povilas Kanapickas 407a2234b3 test/xi2: Update tests for gesture event types 2021-05-30 13:26:35 +03:00
Povilas Kanapickas f83f7dbb1c xi: Bump max supported XI2 event type 2021-05-30 13:26:34 +03:00
Povilas Kanapickas 8190954639 xi: Implement selection logic for gesture event types 2021-05-30 13:26:33 +03:00
Povilas Kanapickas 080bac39c8 xi: Implement grab support for new gesture event types 2021-05-30 13:26:32 +03:00
Povilas Kanapickas b544a1fdb8 xi: Implement internal gesture event struct 2021-05-30 13:26:31 +03:00
Povilas Kanapickas 22fa31ed56 dix: Add new internal event enums for gesture events 2021-05-30 13:26:30 +03:00
Povilas Kanapickas 8e504d8b36 meson: Depend on inputproto 2.3.99.1
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-05-30 13:26:29 +03:00
Povilas Kanapickas 2acde60147 .gitlab-ci: Install xorgproto 2021.4.99.2 from git
This is required for the support of upcoming XI 2.4 protocol.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-05-30 13:26:28 +03:00
Claes Nästén 236d177550 os: include unistd.h when HAVE_PSTACK is defined
On Solaris when HAVE_PSTACK is defined unistd.h needs to be included to
avoid implicit declarations of pipe, read, execle etc.
2021-05-27 21:33:12 +00:00
Erik Kurzinger 7515c23a41 xwayland/eglstream: flush stream after eglSwapBuffers
When eglSwapBuffers inserts a new frame into a window's stream, there may be a
delay before the state of the consumer end of the stream is updated to reflect
this. If the subsequent wl_surface_attach, wl_surface_damage, wl_surface_commit
calls are received by the compositor before then, it will (typically) re-use
the previous frame acquired from the stream instead of the latest one.

This can leave the window displaying out-of-date contents, which might never be
updated thereafter.

To fix this, after calling eglSwapBuffers, xwl_glamor_eglstream_post_damage
should call eglStreamFlushNV. This call will block until it can be guaranteed
that the state of the consumer end of the stream has been updated to reflect
that a new frame is available.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1171

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2021-05-20 12:46:23 +00:00
Simon Ser f3eb1684fa xwayland: enable MIT-SHM shared pixmaps
Allow X11 clients to create shared pixmaps via the MIT-SHM
extension under Xwayland. Tested with a wlroots patch [1].

Also add a few assertions to make sure we have wl_buffers where we
need them.

[1]: https://github.com/swaywm/wlroots/pull/2875

Signed-off-by: Simon Ser <contact@emersion.fr>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-18 15:19:55 +00:00
Erik Kurzinger 3d33d885fc xwayland/eglstream: allow commits to dma-buf backed pixmaps
As of commit 098e0f52 xwl_glamor_eglstream_allow_commits will not allow commits
if the xwl_pixmap does not have an EGLSurface. This is valid for pixmaps backed
by an EGLStream, however pixmaps backed by a dma-buf for OpenGL or Vulkan
rendering will never have an EGLSurface.  Unlike EGLStream backed pixmaps,
though, glamor will render directly to the buffer that Xwayland passes to the
compositor. Hence, they don't require the intermediate copy in
xwl_glamor_eglstream_post_damage that EGLStream backed pixmaps do, so there is
no need for an EGLSurface.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-17 12:32:22 -04:00
Olivier Fourdan 012350e3db xwayland/eglstream: Set ALU to GXCopy for blitting
The EGLstream backend's post damage function uses a shader and
glDrawArrays() to copy the data from the glamor's pixmap texture prior
to do the eglSwapBuffers().

However, glDrawArrays() can be affected by the GL state, and therefore
not reliably produce the expected copy, causing the content of the
buffer to be corrupted.

Make sure to set the ALU to GXCopy prior to call glDrawArrays() to get
the expected result.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan d85bfa6ab7 xwayland/eglstream: Do not always increment pixmap refcnt on commit
Currently, the EGLstream backend would increment the pixmap refcount for
each commit, and decrease that refcount on the wl_buffer release
callback.

But that's relying on the compositor sending us a release callback for
each commit, otherwise the pixmap refcount will keep increasing and the
pixmap will be leaked.

So instead, increment the refcount on the pixmap only when we have not
received a release notification for the wl_buffer, to avoid increasing
the pixmap refcount more than once without a corresponding release
event.

This way, if the pixmap is still in use when released on the X11 side,
the EGL stream will be kept until the compositor releases it.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan b583395cd3 xwayland/eglstream: Check eglSwapBuffers()
EGLstream's post_damage() would unconditionally return success
regardless of the actual status of the eglSwapBuffers().

Yet, if eglSwapBuffers() fails, we should not post the corresponding
damage as they wouldn't match the actual content of the buffer.

Use the eglSwapBuffers() return value as the return value for
post_damage() and do not take a refrence on the pixmap if it fails.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan a457999710 xwayland/eglstream: Fix calloc/malloc
Use calloc() instead of malloc() like the rest of the code.

Also fix the arguments of calloc() calls to match the definition which
is calloc(size_t nmemb, size_t size).

This is a cleanup patch, no functional change.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan 098e0f52c0 xwayland/eglstream: Do not commit without surface
The EGL surface for the xwl_pixmap is created once the stream is ready
and valid.

If the pixmap's EGL surface fails, for whatever reason, the xwl_pixmap
will be unusable and will end up as an invalid wl_buffer.

Make sure we do not allow commits in that case and recreate the
xwl_pixmap/stream.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan bee2ebb29f xwayland/eglstream: Drop the list of pending streams
Now that the pending stream is associated with the xwl_pixmap for
EGLStream and the xwl_pixmap itself is associated to the pixmap, we have
a reliable way to get to those data from any pending stream.

As a result, the list of pending streams that we keep in the EGLStream
global structure becomes useless.

So we can drop the pending stream's xwl_pixmap and also the list of
pending streams altogether, and save us a walk though that list for each
callback.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan e19bf86c17 xwayland/eglstream: Keep a reference to the pixmap
Commit affc47452 - "xwayland: Drop the separate refcount for the
xwl_pixmap" removed the separate reference counter for the xwl_pixmap
which holds the EGLStream.

While that works fine for the common case, if the window's pixmap is
changed before the stream is ready, the older pixmap will be destroyed
and the xwl_pixmap along with it, even if the compositor is still using
the stream.

The code that was removed with commit affc47452 was taking care of that
by increasing the separate reference counter for the xwl_pixmap, but it
no longer the case.

As a result, we may end up with the EGL stream in the wrong state when
trying to use it, which will cascade down into all sort of issues.

To avoid the problem, increase the reference count on the pixmap when it
is marked as invalid in EGLStream's SetWindowPixmap().

This way, the xwl_pixmap and the EGLStream are kept until released by
the compositor, even when the pixmap changes before stream is ready.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Fixes: affc47452 xwayland: Drop the separate refcount for the xwl_pixmap
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan cb61ecc729 xwayland/eglstream: Dissociate pending stream from window
Previously, we would have pending streams associated with top level X11
windows, keeping temporary accounting for the pending streams before
they get fully initialized for the xwl_pixmap which would be associated
with X11 pixmaps.

If the window content changes before the stream is ready, the
corresponding pending stream would be marked as invalid and the pending
stream would be eventually removed once the stream becomes ready.

Since commit affc47452 - "xwayland: Drop the separate refcount for the
xwl_pixmap", we no longer keep a separate reference counter for the
xwl_pixmap, but rather tie it to the X11 pixmap lifespan. Yet, the
pending stream would still be associated with the X11 toplevel window.

Dissociate the pending streams from the X11 toplevel window, to keep it
tied only to the xwl_pixmap so that we can have:

 - pixmap <-> xwl_pixmap
 - xwl_pixmap <-> pending stream

Of course, the pending streams remain temporary and get removed as soon
as the ready callback is triggered, but the pending streams are not
linked to the X11 window anymore which can change their content, and
therefore their X11 pixmap at any time.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan cc596bcfb2 xwayland/eglstream: Add more error checking
eglCreateStreamKHR() can fail and return EGL_NO_STREAM_KHR, in which
case there is no point in trying to create a buffer from it.

Similarly, eglCreateStreamProducerSurfaceKHR() also fail and return
EGL_NO_SURFACE, which in turn will be used in eglMakeCurrent() as
draw/read surface, and therefore would mean no draw/read buffer.

In those cases, log the error, and bail out early. That won't solve the
issue but will help with investigating the root cause of issues with
EGLStream backend.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan 823f3254fa xwayland/eglstream: Small refactoring
Some functions are called "callback" whereas they are not longer
callback functions or "unref" while they no longer deal with a reference
counter anymore, which is quite confusing. Rename those functions to be
more explicit.

Also, the pending streams can be destroyed in different places, move the
common code to separate function to avoid duplicating code and help with
readability of the code.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
2021-05-11 14:08:58 +02:00
Olivier Fourdan 85244d2a20 xwayland/eglstream: Check framebuffer status
The EGLStream backend would sometime generate GL errors trying to draw
to the framebuffer, which gives an invalid buffer, which in turn would
generate a Wayland error from the compositor which is fatal to the
client.

Check the framebuffer status and bail out early if it's not complete,
to avoid getting into trouble later.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan 252cbad316 xwayland/glamor: Add return status to post_damage
If the glamor backend failed to post damage, the caller should do the
same to avoid a failure to attach the buffer to the Wayland surface.

Change the API of Xwayland's glamor backend post_damage() to return a
status so that xwl_window_post_damage() can tell whether the callee
failed.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan 3b265c59a6 glamor: Dump backtrace on GL error
Currrently, when a GL error is triggered, glamor would log the error
which may not be sufficient to trace it back to the cause of the error.

Also dump the backtrace which may give more information as to where the
error comes from.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan 25d2f4948f xwayland: Check buffer prior to attaching it
If the buffer is NULL, do not even try to attach it, and risk a Wayland
protocol error which would be fatal to us.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Olivier Fourdan 4f0889e983 xwayland/eglstream: Check buffer creation
EGLStream wl_eglstream_display_create_stream() may fail, yet Xwayland
would try to attach the buffer which may cause a fatal Wayland protocol
error raised by the compositor.

Check if the buffer creation worked, and fail gracefully otherwise (like
wayland-eglsurface does).

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1156
2021-05-11 14:08:58 +02:00
Erik Kurzinger 4f6fbd5009 xwayland-eglstream: fix X11 rendering to flipping GL / VK window
If a window is being used for direct rendering with OpenGL or Vulkan, and is
using the flipping path for presentation, it's pixmap will be set to a dma-buf
backed pixmap created by the client-side GL driver. However, this means that
xwl_glamor_eglstream_post_damage won't work since it requires that the pixmap
has an EGLSurface that it can render to, which dma-buf backed pixmaps do not.

In this case, though, xwl_glamor_eglstream_post_damage is not necessary since
glamor will have rendered directly to the pixmap, so we can simply pass it
directly to the compositor. There's no need for the intermediate copy we
normally do in that function.

Therefore, this change adds an early-return case to post_damage for dma-buf
backed pixmaps, and removes the corresponding asserts from that function and
allow_commits.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-04-30 11:08:41 -04:00
qarmin a50a0e3485 glxcmds: Fix possible out of bounds 2021-04-24 19:42:52 +00:00
Mazlan, Hazwan Arif 3ea46f9336 dri2: Sync i965_pci_ids.h from mesa iris_pci_ids.h
Copied TGL PCI ID from MESA iris_pci_ids.h
This update brings in a significant number of new platform ID's
Sync up until commit f02ae698

Signed-off-by: Mazlan, Hazwan Arif <hazwan.arif.mazlan@intel.com>
2021-04-24 19:21:41 +00:00
Jon Turney d3933a24d1 CI: Add an x86 MinGW-w64 cross build
Only cross-build for x86 MinGW-w64, as x64 MinGW-w64 will probably
require fixing LLP64 issues.

I don't know any source for pre-built cross-dependencies of the X
server, so build these from git.

Don't build with GLX enabled, so I don't have to deal with
cross-building mesa and it's dependencies, for the moment.
2021-04-24 19:43:00 +01:00
luporl 7e142cb2a8 xserver: fix RGB mask handling
On FreeBSD 13.0-CURRENT for PowerPC64 big-endian (BE), X was
crashing in some cases. For instance, when twm was started
and the background was clicked to open its menu, X crashed
with a segmentation fault, trying to dereference a null pointer
at CreatePicture().

There were 2 issues with xorg-server handling of RGB masks that
caused the pointer above to be null and thus the crash:
- wrong use of ffs() to get the RGB offsets from the masks
- overflow when shifting a 16-bit integer

This change fixes both issues. They happen when the system is BE
but has a video adapter using a little-endian (LE) ARGB32
framebuffer. In order to display the correct colors, this setup
requires a BE RGBA32 color format to be used by X, by setting
the RGB masks appropriately, that didn't work properly because of
the issues above.
2021-04-16 14:40:49 +00:00
Łukasz Spintzyk 5be3b80b8d modesetting: Remove few common functions from ms namespace
A lot of that code is the same as in xf86-amdgpu and xf86-nouveau drivers. By removing that functions from
ms namespace we can move that code to common implementation.

Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Łukasz Spintzyk c282be503e modesetting: remove unnecessary ms_covering_xf86_crtc dup of ms_covering_randr_crtc
Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Łukasz Spintzyk b923364c5e modesetting: Find crtc on secondary outputs as fallback instead of returning primary crtc
Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Łukasz Spintzyk d2dce22b67 present: fix msc offset calculation in screen mode
Instead of getting the current msc value from the window crtc,
which not exist take the last saved msc value saved in
the window_priv struct

Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Łukasz Spintzyk 908deb0895 present: Use crtc's screen present operation for syncing
Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Łukasz Spintzyk d03c0de77b modesetting: Initialize present extension despite glamor is disabled
Signed-off-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com>
2021-04-16 10:53:43 +00:00
Matthieu Herrb 7aaf54a188 Fix XChangeFeedbackControl() request underflow
CVE-2021-3472 / ZDI-CAN-1259

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative

Signed-off-by: Matthieu Herrb <matthieu@herrb.eu>
2021-04-13 14:28:13 +02:00
Peter Hutterer 66ce61983d xkb: silence a compiler warning
xkb.c: In function ‘ProcXkbSetMap’:
xkb.c:2747:5: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
 2747 |     DeviceIntPtr master = GetMaster(dev, MASTER_KEYBOARD);

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-04-09 17:37:29 +00:00
Peter Hutterer f6b8f8c071 xkb: don't require a trailing slash for the XKM output dir
Rework the function to use a single snprintf call instead of a mix of
strcpy/strcats. This now also appends a trailing slash where needed so we
don't rely on the build system to set this for us.

Also, since /tmp/ is the fallback and we never check if everything succeeded,
assert if we can't use /tmp/. This will never be triggered anyway, the only
caller to OutputDirectory() uses sizeof(PATH_MAX-sized array).

Follow-up from 6c51818a0f

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-04-09 17:37:29 +00:00
Jan Beich eceafd4a2d meson: switch getpeer* checks to autotools style
Checking for function "getpeereid" : YES
Checking for function "getpeerucred" : NO
[...]
include/meson.build:182:7: ERROR: Argument to "not" is not a boolean.

Fixes: 68c2cfadd6 ("meson: Make sure defines are either set to 1 or not defined")
2021-04-09 16:44:27 +00:00
Jan Beich 9f8421af63 meson: check pthread_setname_np like autotools
FreeBSD < 12.2 and OpenBSD only have pthread_set_name_np.
As libpthread isn't in scope use -Werror to trip the check.

Header <pthread.h> has symbol "PTHREAD_MUTEX_RECURSIVE" : YES
Checking if "pthread_setname_np(tid, name)" compiles: YES

os/inputthread.c:326:5: error: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    pthread_setname_np (pthread_self(), "InputThread");
    ^
os/inputthread.c:447:5: error: implicit declaration of function 'pthread_setname_np' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    pthread_setname_np (pthread_self(), "MainThread");
    ^

Fixes: c20e7b5e22 ("meson: Automatically detect HAVE_PTHREAD_SETNAME_NP")
2021-04-09 15:43:37 +00:00
Erik Kurzinger 38e875904b xwayland: implement pixmap_from_buffers for the eglstream backend
Provides an implementation for the pixmap_from_buffers DRI3 function for
xwayland's eglstream backend. This will be used by the NVIDIA GLX driver
to pass buffers from client applications to the server. These can then
be presented using the PRESENT extension.

To hopefully make this less error-prone, we also introduce a "type"
field for this struct to distinguish between xwl_pixmaps for the new
DRI3-created pixmaps and those for the existing glamor-created pixmaps.

Additionally, the patch enables wnmd present mode with the eglstream backend.
This involves creating a wl_buffer for the provided dma-buf before importing it
into EGL and passing this to the compositor so it can be scanned out directly
if possible.

Since both backends now support this present mode, the HAS_PRESENT_FLIP flag is
no longer needed, so it can be removed.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2021-04-09 14:00:01 +00:00
Erik Kurzinger bc99dd2127 xwayland: Add check_flip() glamor backend function
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

This exposes a new glamor backend function, check_flip, which can be
used to control whether flipping is supported for the given pixmap.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2021-04-09 14:00:01 +00:00
Erik Kurzinger 400d4d0fdd xwayland: move formats and modifiers functions to common glamor code
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

This moves the modifiers and formats functions previously only available
to the GBM backend to the common glamor code so that it can be used by
both the GBM and EGLStream backends.

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
2021-04-09 14:00:01 +00:00
Olivier Fourdan ae225417c0 xwayland: Move dmabuf interface to common glamor code
This is preliminary work for hardware accelerated rendering with the
NVIDIA driver.

The EGLStream backend can possibly also use the dmabuf interface, so
move the relevant code from the GBM specific source to the common bits.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
2021-04-09 14:00:01 +00:00
Povilas Kanapickas d231ce2d9c meson: Disable LTO for tests
`-flto=auto` together with `-Wl,-wrap` causes link errors at least in
certain compilers (e.g. GCC 10.2.0). Since this is reoccurring issue
(internet search shows similar problems with GCC 4.6 a decade ago) let's
disable LTO for tests even if it's disabled elsewhere.

Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1116
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-04-09 11:18:54 +00:00
Povilas Kanapickas 68c2cfadd6 meson: Make sure defines are either set to 1 or not defined
This will make the behavior of meson consistent with autotools. The
configuration macros are exposed to public headers so any inconsistency
is likely to break code for anyone who's not careful to use #ifdef
instead of #if.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-04-09 11:18:54 +00:00
Povilas Kanapickas faff5bbdf5 meson: Sync the name of INPUTTHREAD conf macro with autotools build
The rest of dix code uses INPUTTHREAD, so having a different name in
meson configuration was an oversight.

Fixes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/936

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-04-09 11:18:54 +00:00
Povilas Kanapickas b25795462f meson: Add missing pthread dependency for libxserver_os library
Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-04-09 11:18:54 +00:00
Povilas Kanapickas 9582ef4efc meson: Fix typo in libxserver_os dependencies for openbsd
This has not been tested, but os_deps is not used anywhere in the file,
so it's likely this was a typo.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-04-09 11:18:54 +00:00
Povilas Kanapickas 689496ed65 meson: Switch project version to 20.x.y style 2021-04-08 14:06:02 +00:00
Povilas Kanapickas 2df55813d0 meson: Drop version subpatch handling 2021-04-08 14:06:02 +00:00
Adam Jackson 5d3679104a meson.build: Keep the protocol version looking like xserver 1.20.x did
This effectively changes the versioning to be as if xserver 21.0 was
xserver 1.21.0. This should keep any client-side version checks that
know about the Xorg 7.0 -> xserver 1.0 epoch from getting confused.
2021-04-08 14:06:02 +00:00
George Matsumura 3e4e70db10 meson: Fix DragonFly BSD identifier in meson build files
This changes the operating system identifier tested against
host_machine.system() in meson build files from "dragonflybsd"
to the officially stable "dragonfly".

Signed-off-by: George Matsumura <gmmatsumura01@bvsd.org>
2021-04-08 02:23:21 +00:00
Edouard Gaulué 199f278a1b French text in Preferences Pane Review 2021-04-07 16:19:24 -07:00
Jeremy Huddleston Sequoia 65b27d82f2 xquartz: Call PseudoramiXExtensionInit() through InitOutput() just like xwin
Fixes: https://github.com/XQuartz/XQuartz/issues/140
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-04-07 16:11:59 -07:00
Pascal VITOUX 34e2a64ce0 xfree86: fix gtf support detection for EDID 1.4
According to the "VESA Enhanced EDID Standard", all GTF compliant
displays are continuous frequency.

The GTF support flags in 'Display Range Limits Descriptor' cannot be
used if the display is a non-continuous frequency multi-mode display.

Closes #1105
Signed-off-by: Pascal VITOUX <vitoux.pascal@gmail.com>
Fixes: 6a79a737 ("xfree86: add drm modes on non-GTF panels")
Reviewed-by: Aaron Ma aaron.ma@canonical.com
2021-04-06 11:25:42 +00:00
Aaron Plattner b75d0cca28 modesetting: Defer crtc gamma size upgrade to drmmode_setup_colormap
Rather than trying to create a gamma ramp array of the appropriate size in
drmmode_crtc_init when the GAMMA_LUT property should be used, just flag the crtc
as wanting to use the GAMMA_LUT property and then replace the gamma ramp later,
right before calling xf86HandleColormaps. This avoids a problem during initial
startup where xf86RandR12CreateObjects12 hard-codes a gamma ramp size of 256,
causing xf86RandR12CrtcSetGamma to read past the end of the DIX layer's RandR
gamma ramp array:

  PreInit
    drmmode_pre_init
      drmmode_crtc_init
        crtc->gamma_size = 1024

  ScreenInit
    xf86CrtcScreenInit
      xf86RandR12Init
        xf86RandR12Init12
          xf86RandR12CreateObjects12
            RRCrtcCreate
              randr_crtc->gammaSize = 0
          xf86RandR12InitGamma(pScrn, 256)
            RRCrtcGammaSetSize
              randr_crtc->gammaSize = 256
          xf86RandR12InitGamma
            xf86RandR12CrtcInitGamma
              RRCrtcGammaSet
                xf86RandR12CrtcSetGamma
                  // crtc->gamma_size is 1024 here, while randr_crtc->gammaRed
                  // is a 256-element array.
                  memcpy(crtc->gamma_red, randr_crtc->gammaRed, crtc->gamma_size * sizeof(crtc->gamma_red[0]));
    drmmode_setup_colormap
      xf86HandleColormaps
        xf86RandR12InitGamma
          RRCrtcGammaSetSize
            randr_crtc->gammaSize = 1024

Fixes: 245b9db0 - modesetting: Use GAMMA_LUT when available
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1126
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Robert Morell <rmorell@nvidia.com>
2021-04-05 14:25:33 -07:00
Jeremie Courreges-Anglas ab8f8c9841 xserver/os: safer IPv6 "kame hack" fix, only override sin6_scope_id if zero
This helps on KAME-based systems which want to get rid of this hack.
The assumption is that if sin6_scope_id is set, then the interface index
is no longer embedded in the address.

Signed-off-by: Jeremie Courreges-Anglas <jca@wxcvbn.org>
2021-04-04 21:06:35 +00:00
Povilas Kanapickas aeed57d722 xkb: Fix parsing of XkbSA_DeviceValuator action type
The xkb spec defines that the 7th element of the DeviceValuator key
action description is "valuator 2 value".

This error most likely was accidentally introduced as a copy-paste error
in edeb033f29.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-03-30 18:47:04 +00:00
Povilas Kanapickas a3931ec6f4 xfree86: Create a symlink X -> Xorg when installing using meson
This brings the behavior closer than what we currently have with
autotools-based build system.

Meson does not currently have native support for symlinks.
See https://github.com/mesonbuild/meson/issues/1602.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-03-26 09:29:25 +00:00
Povilas Kanapickas 09cd65233e xfree86: Set appropriate install_mode for suid_wrapper 2021-03-26 09:18:55 +00:00
Povilas Kanapickas 88b5e1a219 meson: Bump min meson version to 0.47 to get install_mode support 2021-03-26 09:18:55 +00:00
Povilas Kanapickas 82d2156ba7 xfree86: Fix meson overwriting suid wrapper with the wrapped executable
Meson gets confused when there are two targets of the same name within
the same directory, so we use a different intermediate name.

This is a problem with the Xorg SUID wrapper which has the same filename
as the real Xorg executable and is configured in the same meson.build
file. This commit works around this by using a different filename in
build stage and renaming only when installing.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-03-26 09:08:02 +00:00
Povilas Kanapickas ba51acb1de miext: Remove if check which is always true
In both cases we check for width > 0 just above, and the variable is not
modified between the checks, so the condition is always true.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-03-26 09:02:14 +00:00
Povilas Kanapickas 99e7ccffb3 dix: Fix URL to description of focus in/out model
The current URL points to an unrelated patch for acpid.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-03-25 23:18:14 +02:00
Simon Ser 1b7dca27eb xwayland: remove wl_log_set_handler_client workaround
This bumps the minimum Wayland version to 1.5 (released in 2014).

Signed-off-by: Simon Ser <contact@emersion.fr>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Martin Peres <martin.peres@mupuf.org>
2021-03-24 08:13:11 +01:00
Michel Dänzer 6c51818a0f meson: Make sure XKM_OUTPUT_DIR has a trailing slash
RunXkbComp passes an invalid file path to xkbcomp if there's no
trailing slash.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1146
Suggested-by: Dylan Baker <dylan.c.baker@intel.com>
2021-03-15 16:53:46 +01:00
Jan Beich 376eaadde3 meson: hide C API if Xorg is disabled (like autotools)
When building only Xwayland using Meson some files are always installed.
This causes package conflict if Xwayland is built separately from Xorg.

  include/xorg/compositeext.h
  include/xorg/damage.h
  include/xorg/damagestr.h
  include/xorg/dbestruct.h
  include/xorg/dri3.h
  include/xorg/fb.h
  include/xorg/fboverlay.h
  include/xorg/fbpict.h
  include/xorg/fbrop.h
  include/xorg/geext.h
  include/xorg/geint.h
  include/xorg/glyphstr.h
  include/xorg/mi.h
  include/xorg/micmap.h
  include/xorg/micoord.h
  include/xorg/migc.h
  include/xorg/miline.h
  include/xorg/mioverlay.h
  include/xorg/mipict.h
  include/xorg/mipointer.h
  include/xorg/mipointrst.h
  include/xorg/mistruct.h
  include/xorg/misync.h
  include/xorg/misyncfd.h
  include/xorg/misyncshm.h
  include/xorg/misyncstr.h
  include/xorg/mizerarc.h
  include/xorg/panoramiX.h
  include/xorg/panoramiXsrv.h
  include/xorg/picture.h
  include/xorg/picturestr.h
  include/xorg/present.h
  include/xorg/presentext.h
  include/xorg/randrstr.h
  include/xorg/rrtransform.h
  include/xorg/shadow.h
  include/xorg/shmint.h
  include/xorg/syncsdk.h
  include/xorg/vndserver.h
  include/xorg/wfbrename.h
  include/xorg/xace.h
  include/xorg/xacestr.h
  include/xorg/xorg-server.h
  include/xorg/xvdix.h
  include/xorg/xvmcext.h
  share/aclocal/xorg-server.m4

Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
2021-03-11 00:22:36 +00:00
Jeremy Huddleston Sequoia 4ae36f418e xquartz: Ensure the mouse pointer is shown when switching to a native macOS alert or window
Fixes: https://github.com/XQuartz/XQuartz/issues/100
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-03-08 21:03:57 -08:00
Matthieu Herrb b2d96b5cd4 Avoid sequences of malloc(0) / free() by checking the length.
This has an impact on heap fragmentation.

Signed-off-by: Matthieu Herrb <matthieu.herrb@laas.fr>
2021-03-08 20:32:54 +00:00
Jeremy Huddleston Sequoia 15a413e11d xquartz: Update meson build to remove deleted files
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-03-05 23:17:21 -08:00
Jeremy Huddleston Sequoia e59848548a xquartz: Fix appFlags build failure with macOS 10.15+ SDKs
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-03-05 23:17:21 -08:00
Olivier Fourdan 69e087caa4 xwayland: Fix path in pkg-config with autoconf
When using autoconf/automake to build Xwayland, the actual path to
Xwayland is not fully qualified and refers to the "exec_prefix".

As a result, the path provided by the generated pkg-config file is wrong
when using autoconf to build the Xserver.

Fix the xwayland.pc file to also set the variable "prefix" and
"exec_prefix" so that the path to Xwayland is fully resolved.

Add those variables to the meson build as well for good measure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Michel Dänzer <mdaenzer@redhat.com>
2021-03-05 11:11:54 +01:00
Olivier Fourdan d7391f383d xwayland: Fix LeaveNotify for relative pointer
Since commit 20c78f38, we use the relative pointer for enter/leave
events.

However, sprite_check_lost_focus() which verifies whether the pointer has
left an Xwayland surface still explicitly check for the absolute
pointer.

As a result, no LeaveNotify event is emitted anymore now when the
pointer crosses from an Xwayland surface to a Wayland native one.

Make sure to check the last slave device against get_pointer_event() as
well, not just the absolute pointer.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Martin Peres <martin.peres@mupuf.org>
Acked-by: Roman Gilg <subdiff@gmail.com>
Tested-by: Roman Gilg <subdiff@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Fixes: 20c78f38 - xwayland: use get_pointer_device() for enter/leave
                  handling too
2021-03-05 07:48:57 +01:00
Jacob Cherry a5367face1 xfree86: Fix autoconfig secondary GPU devices
The code path added by commit 69e4b8e6 (xfree86: attempt to autoconfig
gpu slave devices (v3)) assumes that it will only be run if the primary
device on the screen is the first device in xf86configptr->conf_device_lst.
While this is true most of the time, there are two specific cases where
this assumption fails.

First, if the first device in conf_device_lst is assigned to a different
seat than the running X server, it will be skipped by the previous
FIND_SUITABLE macro usage. Second, if the primary device was explicitly
assigned to the screen but auto_gpu_device is still set and no secondary
devices were explicitly listed, that device may not be the first device
in conf_device_lst.

When the first device in conf_device_lst is not the primary device
assigned to the screen, two problems emerge. First, the first device in
conf_device_lst will never be assigned to the screen as a secondary
device. Second, the primary device is additionally assigned to the
screen as a secondary device. The combination of these problems causes
certain otherwise valid configurations to be invalid. For example, if a
primary device is assigned to a screen and a secondary device is listed
in the config but not explicitly assigned to the screen, then one order
of the device sections results in a usable PRIME or Reverse PRIME setup
and the other order does not.

This commit removes the assumption that the primary device is the first
device in conf_device_lst by starting the loop from the start of
conf_device_lst and skipping the primary device when it is encountered.

Signed-off-by: Jacob Cherry <jcherry@nvidia.com>
2021-03-03 17:50:31 +00:00
Olivier Fourdan 97ed0048e4 xwayland: Delay cursor visibility update
Xwayland won't emulate XWarpPointer requests if the cursor is visible,
this is to avoid having the cursor jumping on screen and preventing
random X11 clients from controlling the pointer in Wayland, while
allowing games which use that mechanism with a hidden cursor to work in
Xwayland.

There are, however, games which tend to do it in the wrong order, i.e.
show the cursor before moving the pointer, and because Xwayland will not
allow an X11 client to move the pointer while the cursor is visible, the
requests will fail.

Add a workaround for such X11 clients, when the cursor is being shown,
keep it invisible until the cursor is actually moved. This way, X11
clients which show their cursor just before moving it would still have a
chance to succeed.

v2: Add a timeout to show the cursor for well behaved clients.
v3: Some cleanup (Michel)
v4: Do not cancel cursor delay when updating the cursor to avoid
    delaying cursor visibility indefinitely if the client keeps
    settings different cursors (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Tested-by: Jaap Buurman jaapbuurman@gmail.com
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/734
2021-03-03 15:28:27 +01:00
Jeremy Huddleston Sequoia 9d329a0fb1 xquartz: Remove a check for NSAppKitVersionNumber >= NSAppKitVersionNumber10_7
This check is always true on our supported systems.

Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-22 09:20:25 -08:00
Jeremy Huddleston Sequoia 839b49ac05 xquartz: Don't include strndup.c any more since we no longer support 10.8 and older
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-22 09:20:25 -08:00
Jeremy Huddleston Sequoia 677eb6827b xquartz: Add a launch trampoline to better integrate with modern versions of macOS
Fixes: https://github.com/XQuartz/XQuartz/issues/6
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-22 09:20:25 -08:00
Jeremy Huddleston Sequoia 25035229b7 xquartz: Don't process AppKit events if we haven't finished initializing
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-20 21:04:25 -08:00
Jeremy Huddleston Sequoia 487286d472 xquartz: Allocate each fbconfig separately
A change during the 1.20 development cycle resulted in fbconfigs being walked
and deallocated individually during __glXScreenDestroy.  This change
now avoids a use-after-free caused by that change.

==50859==ERROR: AddressSanitizer: heap-use-after-free on address 0x00010d3819c8 at pc 0x0001009d4230 bp 0x00016feca7a0 sp 0x00016feca798
READ of size 8 at 0x00010d3819c8 thread T5
    #0 0x1009d422c in __glXScreenDestroy glxscreens.c:448
    #1 0x10091cc98 in __glXAquaScreenDestroy indirect.c:510
    #2 0x1009d2734 in glxCloseScreen glxscreens.c:169
    #3 0x100740a24 in dix_main main.c:325
    #4 0x10023ed50 in server_thread quartzStartup.c:65
    #5 0x199ae7fd0 in _pthread_start+0x13c (libsystem_pthread.dylib:arm64e+0x6fd0)
    #6 0x199ae2d38 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d38)

0x00010d3819c8 is located 200 bytes inside of 12800-byte region [0x00010d381900,0x00010d384b00)
freed by thread T5 here:
    #0 0x101477ba8 in wrap_free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fba8)
    #1 0x1009d4240 in __glXScreenDestroy glxscreens.c:449
    #2 0x10091cc98 in __glXAquaScreenDestroy indirect.c:510
    #3 0x1009d2734 in glxCloseScreen glxscreens.c:169
    #4 0x100740a24 in dix_main main.c:325
    #5 0x10023ed50 in server_thread quartzStartup.c:65
    #6 0x199ae7fd0 in _pthread_start+0x13c (libsystem_pthread.dylib:arm64e+0x6fd0)
    #7 0x199ae2d38 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d38)

previously allocated by thread T5 here:
    #0 0x101477e38 in wrap_calloc+0x9c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fe38)
    #1 0x100925a40 in __glXAquaCreateVisualConfigs visualConfigs.c:116
    #2 0x10091cb24 in __glXAquaScreenProbe+0x224 (X11.bin:arm64+0x100730b24)
    #3 0x1009cd840 in xorgGlxServerInit glxext.c:528
    #4 0x10074539c in _CallCallbacks dixutils.c:743
    #5 0x100932a70 in CallCallbacks callback.h:83
    #6 0x100932478 in GlxExtensionInit vndext.c:244
    #7 0x10020a364 in InitExtensions miinitext.c:267
    #8 0x10073fe7c in dix_main main.c:197
    #9 0x10023ed50 in server_thread quartzStartup.c:65
    #10 0x199ae7fd0 in _pthread_start+0x13c (libsystem_pthread.dylib:arm64e+0x6fd0)
    #11 0x199ae2d38 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d38)

Regressed-in: 4b0a3cbab1
CC: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-20 17:29:40 -08:00
Jeremy Huddleston Sequoia 6a83fb51b7 xquartz: Fix a compiler warning about const incompatible pointer assignment
driWrap.c:541:30: error: assigning to 'GCOps *' (aka 'struct _GCOps *') from 'const GCOps *' (aka 'const struct _GCOps *') discards
      qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
        pGCPriv->originalOps = pGC->ops;
                             ^ ~~~~~~~~

Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-20 15:18:47 -08:00
Jeremy Huddleston Sequoia a3ddcdd56c xquartz: Fix build with sparkle enabled
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 23:16:32 -08:00
Jeremy Huddleston Sequoia 279bcbd9cf xquartz: Silence a compiler warning about missing internal methods on NSApplication
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:34:14 -08:00
Jeremy Huddleston Sequoia fe89c70e47 xquartz: Rewrite Window menu handling to not depend on X11App.windowsMenu.numberOfItems being correct in -awakeFromNib
Fixes: https://github.com/XQuartz/XQuartz/issues/56
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 41aed8f696 xquartz: Convert X11Controller ivars into @properties
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia c2750e1fab xquartz: Convert X11Application ivars into @properties
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia f51b97b0de xquartz: Fold quartzCommon.h into quartz.h
Everything declared in it comes from quartz.c, so match reality.

Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 4b4500c48f xquartz: Fold away some unnecessary hops to X11Controller through X11Application
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 39c0e1c0ab xquartz: Fold away array_with_strings_and_numbers and simplify with more modern Objective-C
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 87f8fe1f74 xqaurtz: Remove message_kit_thread() and use dispatch instead
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 94e4e17348 xquartz: Use objc_autoreleasePoolPush / objc_autoreleasePoolPop directly in QuartzBlockHandler
It violates @autoreleasepool best practices, and this helps collapse quartzCocoa.m into quartz.c

Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia fba421f700 xquartz: Minor code modernization -- @autoreleasepool adoption
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 318f8a4a8a xquartz: Remove some dead code for compatibility with older nibs
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 72a39dccf9 xquartz: Remove a workaround for AppKit versions older than Lion
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-18 22:32:14 -08:00
Jeremy Huddleston Sequoia 7e28750358 xquartz: Fix applications menu table background color for dark mode
Fixes: https://github.com/XQuartz/XQuartz/issues/32
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-17 16:24:08 -08:00
Jeremy Huddleston Sequoia 85beee9885 xquartz: Apply Xcode 12.4 automatic updates to nibs
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-17 16:24:06 -08:00
Jeremy Huddleston Sequoia 4e892aa6e1 xquartz: Update the about box copyright to 2021
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-17 13:38:31 -08:00
Jeremy Huddleston Sequoia c9a3b14c14 xquartz: Ensure we call into TIS on the main thread
There is a place where this code was called on the main thread.

We're using a rather nasty anti-pattern to just call a block inline rather
than synchonously calling it on the main thread if we're already on the main
thread.  This code could use a good overhaul, but I don't have time to rip
it apart right now.  This will address the immediate issue.

Fixes: https://github.com/XQuartz/XQuartz/issues/40
Fixes: https://github.com/XQuartz/XQuartz/issues/48
Signed-off-by: Jeremy Huddleston Sequoia <jeremyhu@apple.com>
2021-02-17 09:53:33 -08:00
Povilas Kanapickas af17b5c499 dix: Use correct listener to deliver touch end events
This fixes an problem left in f682e0563f
due to an incorrect cherry-pick.

We must use old listener->listener to deliver the touch event. Otherwise
grab won't let the event through and the abovementioned commit has no
effect.

Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
2021-02-17 04:29:48 +00:00
Peter Hutterer 20c78f38a0 xwayland: use get_pointer_device() for enter/leave handling too
In Weston, clicking the window decoration of an Xwayland client gives us a
wl_pointer.button event immediately followed by a wl_pointer.leave event.
The leave event does not contain any button state information, so the button
remains logically down in the DIX.

Once the pointer button is released, a wl_pointer.enter event is sent with
the current button state (zero). This needs to trigger a ButtonRelease event
but for that we need to ensure that the device is the same as the one we send
ButtonPress events through.

Fixes a regression introduced in a4095162ca.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2021-02-17 14:18:02 +10:00
Olivier Fourdan dee2bb033e dix: Guard against non-existing PtrFeedbackPtr
Trying to change the pointer control settings on a device without
PtrFeedbackPtr would be a bug and a crash in the Xserver.

Guard against that case by returning early with a BadImplementation
error, that might kill the X11 client but the Xserver would survive.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1137
2021-02-16 09:37:46 +01:00
Olivier Fourdan ab76272a7d xwayland: Add PtrFeedback to the touch device
Trying to change the acceleration/threshold on Xwayland cannot work, and
the corresponding handler xwl_pointer_control() is a no-op.

Yet, an X11 client trying to change those on the touch device may
possibly cause a crash because the touch device in Xwayland doesn't set
that.

Initialize the touch device's PtrFeedback to make sure that just cannot
happen.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1137
2021-02-16 09:37:46 +01:00
Olivier Fourdan a4095162ca xwayland: Use relative device for buttons/axis
We are using the relative pointer for motion events, but buttons and
axis events still go through the absolute pointer device.

That means additional DeviceChanged events that could be avoided if the
buttons and axis events were coming from the same device as motion
events.

Route those events to the relative pointer if available so that motion,
buttons and axis events come from the same device (most of the time).

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
2021-02-15 09:42:00 +01:00
Olivier Fourdan 1abab61dc2 xwayland: Add wheel axis to relative pointer
The relative pointer only has 2 axis, if we want to route the mouse
wheel events to that device, we need to add the axis definition, similar
to what is done for the absolute pointer.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
2021-02-15 09:42:00 +01:00
Olivier Fourdan 7181792824 xwayland: Split dispatch_pointer_motion_event
This is a cleanup patch, no functional change.

Split the function dispatch_pointer_motion_event() into three separate
simpler functions, relative motion with a warp emulator, relative motion
and absolute motion.

This makes the code a lot easier to read for me, rather than having
everything in a single function with nested if/else conditions.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
2021-02-15 09:42:00 +01:00
Olivier Fourdan c5c5322ad6 xwayland: Use relative values for raw events
Xwayland supports relative motion events from the Wayland compositor via
the relative-pointer protocol, and converts those to the absolute range
in device units for raw events.

Some X11 clients however wrongly assume relative values in the axis
values even for devices explicitly labeled as absolute. While this is a
bug in the client, such applications would work fine in plain Xorg but
not with Xwayland.

To avoid that issue, use the relative values for raw events without
conversion, so that such application continue to work in Xwayland.

Thanks Peter for figuring out the root cause.

v2: Don't duplicate relative and absolute events (Peter)
v3: Use POINTER_RAWONLY (Peter)

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
2021-02-15 09:42:00 +01:00
Olivier Fourdan ebdb2e2646 xwayland: Use a resolution of 0 for relative motion
That's what evdev/libinput drivers do.

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
2021-02-15 09:42:00 +01:00
Olivier Fourdan b5e1f13681 dix: Add POINTER_RAWONLY flag
This add a new flag POINTER_RAWONLY for GetPointerEvents() which does
pretty much the opposite of POINTER_NORAW.

Basically, this tells GetPointerEvents() that we only want the
DeviceChanged events and any raw events for this motion but no actual
motion events.

This is preliminary work for Xwayland to be able to use relative motion
events for raw events. Xwayland would use absolute events for raw
events, but some X11 clients (wrongly) assume raw events to be always
relative.

To allow such clients to work with Xwayland, it needs to switch to
relative raw events (if those are available from the Wayland
compositor).

However, Xwayland cannot use relative motion events for actual pointer
location because that would cause a drift over time, the pointer being
actually controlled by the Wayland compositor.

So Xwayland needs to be able to send only relative raw events, hence
this API.

Bump the ABI_XINPUT_VERSION minor version to reflect that API addition.

v2: Actually avoid sending motion events (Peter)
v3: Keep sending raw emulated events with RAWONLY (Peter)

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Related: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1130
2021-02-15 09:42:00 +01:00
Povilas Kanapickas 213129012b Xi: Deliver pointer emulated touch events to grabbing client
Delivery of emulated events usually happens only to the owning client.
If there are grabs, only the grabbing client may receive these events.

This logic does not work during the touch event replay in
DeactivatePointerGrab(), as the previous grab is no longer in the
listener queue of the touch, so the next owner gets whole emulated event
sequence. This may trigger implicit grabs. After replay,
DeactivatePointerGrab() will update the global grab without regard to
this new implicit grab, which leads to issues down the line.

This change is effectively the same as 35e5a76cc1 except that the change
is limited to only emulated pointer events. Otherwise, in the case of a
device grab we end up not sending any touch events to clients that
selected XI_TouchOwnership event and should get touch events before they
get ownership of touch sequence.

Fixes #7

https://bugs.freedesktop.org/show_bug.cgi?id=96536
2021-02-15 04:40:16 +00:00
Povilas Kanapickas 30e11535af Revert "Xi: Use current device active grab to deliver touch events if any"
This reverts commit 98e3db2ac4.
2021-02-15 04:40:16 +00:00
Povilas Kanapickas f682e0563f dix: Send touch end to clients that do async grab without touch events
If a XI2 client started listening to touches due to a selection and then
creates an active async grab that does not include touch events, then it
currently won't get the touch end event which will produce inconsistent
view of the pending touches.

Note that we only need to consider touch listeners and can ignore
pointer emulation. Under XI2 if a active grab replaces a passive
implicit grab and the active grab does not include the button release
event, the client won't get it either.
2021-02-08 05:21:29 +02:00
1205 changed files with 324548 additions and 1732 deletions

View File

@ -29,6 +29,7 @@ pkg-config,\
python3,\
windowsdriproto,\
xorgproto,\
libdmx-devel,\
libepoxy-devel,\
libfontenc-devel,\
libfreetype-devel,\
@ -72,7 +73,7 @@ cache:
- '%CYGWIN_ROOT%\home\%USERNAME%\.ccache'
build_script:
- SET PATH=%CYGWIN_ROOT%/bin
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Ddmx=true -Dxephyr=true -Dxnest=true -Dxvfb=true -Dxwin=true -Dxorg=true -Dhal=false -Dudev=false -Dpciaccess=false -Dint10=false build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson configure build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ninja -C build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ccache -s"'

View File

@ -8,10 +8,10 @@
# gcc/clang or other packages, which might break the build with older commits
# using the same tag.
variables:
UPSTREAM_REPO: xorg/xserver
FDO_UPSTREAM_REPO: xorg/xserver
FDO_DISTRIBUTION_VERSION: buster-slim
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_TAG: "2021-01-19-git"
FDO_DISTRIBUTION_TAG: "2021-07-09"
include:
- project: 'freedesktop/ci-templates'
@ -59,10 +59,21 @@ debian-buster:
after_script:
- ccache --show-stats
autotools:
extends: .common-build-and-test
script:
- mkdir build/
- cd build/
- ../autogen.sh --prefix=/usr CFLAGS="-fno-common"
- make -j${FDO_CI_CONCURRENT:-4} distcheck
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts make -j${FDO_CI_CONCURRENT:-4} check
- cd ..
- .gitlab-ci/manpages-check
meson:
extends: .common-build-and-test
script:
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxvfb=false -Dwerror=true $MESON_EXTRA_OPTIONS build/
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxephyr=true -Dwerror=true $MESON_EXTRA_OPTIONS build/
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ dist
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts ninja -j${FDO_CI_CONCURRENT:-4} -C build/ test
- .gitlab-ci/manpages-check
@ -72,3 +83,9 @@ meson-noglamor:
variables:
MESON_EXTRA_OPTIONS: >
-Dglamor=false
mingw-cross-build:
extends: .common-build-and-test
script:
- meson --cross-file=.gitlab-ci/cross-i686-w64-mingw32.txt -Dglx=false -Dsecure-rpc=false -Dlisten_tcp=true build/
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ install

View File

@ -0,0 +1,20 @@
[binaries]
c = 'i686-w64-mingw32-gcc'
cpp = 'i686-w64-mingw32-g++'
ar = 'i686-w64-mingw32-ar'
strip = 'i686-w64-mingw32-strip'
pkgconfig = '/usr/local/bin/i686-w64-mingw32-pkg-config'
windres = 'i686-w64-mingw32-windres'
exe_wrapper = 'wine'
[properties]
# Directory that contains 'bin', 'lib', etc for the toolchain
root = '/usr/i686-w64-mingw32'
# Directory that contains 'bin', 'lib', etc which have been cross-compiled
sys_root = '/usr/i686-w64-mingw32'
[host_machine]
system = 'windows'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

View File

@ -0,0 +1,79 @@
#!/bin/bash
set -e
set -o xtrace
HOST=$1
# Debian's cross-pkg-config wrappers are broken for MinGW targets, since
# dpkg-architecture doesn't know about MinGW target triplets.
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=930492
cat >/usr/local/bin/${HOST}-pkg-config <<EOF
#!/bin/sh
PKG_CONFIG_SYSROOT_DIR=/usr/${HOST} PKG_CONFIG_LIBDIR=/usr/${HOST}/lib/pkgconfig:/usr/share/pkgconfig pkg-config \$@
EOF
chmod +x /usr/local/bin/${HOST}-pkg-config
# when cross-compiling, some autoconf tests cannot be run:
# --enable-malloc0returnsnull
export xorg_cv_malloc0_returns_null=yes
build() {
url=$1
commit=$2
config=$3
name=$(basename ${url} .git)
if [[ $commit =~ ^[[:xdigit:]]{1,}$ ]]
then
git clone ${url} ${name}
git -C ${name} checkout ${commit}
else
git clone --depth 1 --branch ${commit:-master} --recurse-submodules -c advice.detachedHead=false ${url} ${name}
fi
pushd ${name}
NOCONFIGURE=1 ./autogen.sh || ./.bootstrap
./configure ${config} --host=${HOST} --prefix= --with-sysroot=/usr/${HOST}/
make -j$(nproc)
DESTDIR=/usr/${HOST} make install
popd
rm -rf ${OLDPWD}
}
build 'https://gitlab.freedesktop.org/pixman/pixman.git' 'pixman-0.38.4'
build 'https://gitlab.freedesktop.org/xorg/lib/pthread-stubs.git' '0.4'
# we can't use the xorgproto pkgconfig files from /usr/share/pkgconfig, because
# these would add -I/usr/include to CFLAGS, which breaks cross-compilation
build 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' 'xorgproto-2021.4.99.2' '--datadir=/lib'
build 'https://gitlab.freedesktop.org/xorg/lib/libXau.git' 'libXau-1.0.9'
build 'https://gitlab.freedesktop.org/xorg/proto/xcbproto.git' 'xcb-proto-1.14'
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb.git' 'libxcb-1.14'
build 'https://gitlab.freedesktop.org/xorg/lib/libxtrans.git' 'xtrans-1.4.0'
# the default value of keysymdefdir is taken from the includedir variable for
# xproto, which isn't adjusted by pkg-config for the sysroot
build 'https://gitlab.freedesktop.org/xorg/lib/libX11.git' 'libX11-1.6.9' "--with-keysymdefdir=/usr/${HOST}/include/X11"
build 'https://gitlab.freedesktop.org/xorg/lib/libxkbfile.git' 'libxkbfile-1.1.0'
# freetype needs an explicit --build to know it's cross-compiling
# disable png as freetype tries to use libpng-config, even when cross-compiling
build 'git://git.savannah.gnu.org/freetype/freetype2.git' 'VER-2-10-1' "--build=$(cc -dumpmachine) --with-png=no"
build 'https://gitlab.freedesktop.org/xorg//font/util.git' 'font-util-1.3.2'
build 'https://gitlab.freedesktop.org/xorg/lib/libfontenc.git' 'libfontenc-1.1.4'
build 'https://gitlab.freedesktop.org/xorg/lib/libXfont.git' 'libXfont2-2.0.3'
build 'https://gitlab.freedesktop.org/xorg/lib/libXdmcp.git' 'libXdmcp-1.1.3'
build 'https://gitlab.freedesktop.org/xorg/lib/libXfixes.git' 'libXfixes-5.0.3'
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git' '0.4.0'
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git' '0.4.0'
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git' '0.4.1'
# workaround xcb_windefs.h leaking all Windows API types into X server build
# (some of which clash which types defined by Xmd.h) XXX: This is a bit of a
# hack, as it makes this header depend on xorgproto. Maybe an upstreamable
# fix would involve a macro defined in the X server (XFree86Server?
# XCB_NO_WINAPI?), which makes xcb_windefs.h wrap things like XWinsock.h
# does???
sed -i s#winsock2#X11/Xwinsock# /usr/${HOST}/include/xcb/xcb_windefs.h

View File

@ -25,7 +25,9 @@ apt-get install -y \
build-essential \
ca-certificates \
ccache \
dpkg-dev \
flex \
gcc-mingw-w64-i686 \
git \
libaudit-dev \
libbsd-dev \
@ -87,21 +89,40 @@ apt-get install -y \
libxt-dev \
libxtst-dev \
libxv-dev \
libz-mingw-w64-dev \
mesa-common-dev \
meson \
mingw-w64-tools \
nettle-dev \
pkg-config \
python3-mako \
python3-numpy \
python3-six \
x11proto-dev \
xfonts-utils \
xkb-data \
xtrans-dev \
xutils-dev
.gitlab-ci/cross-prereqs-build.sh i686-w64-mingw32
cd /root
# xserver requires libxcvt
git clone https://gitlab.freedesktop.org/xorg/lib//libxcvt.git --depth 1 --branch=libxcvt-0.1.0
cd libxcvt
meson _build
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf libxcvt
# xserver requires xorgproto >= 2021.4.99.2 for XI 2.3.99.1
git clone https://gitlab.freedesktop.org/xorg/proto/xorgproto.git --depth 1 --branch=xorgproto-2021.4.99.2
pushd xorgproto
./autogen.sh
make -j${FDO_CI_CONCURRENT:-4} install
popd
rm -rf xorgproto
# weston 9.0 requires libwayland >= 1.18
git clone https://gitlab.freedesktop.org/wayland/wayland.git --depth 1 --branch=1.18.0
cd wayland

27
.travis.yml Normal file
View File

@ -0,0 +1,27 @@
language: c
cache:
ccache: true
directories:
- $HOME/Library/Caches/Homebrew
branches:
except:
- /appveyor.*/
os: osx
osx_image: xcode9.2
matrix:
include:
- env: TOOL=meson
- env: TOOL=autotools
install:
- brew update
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache meson
script:
- ./test/scripts/build-travis-osx.sh $TOOL
- ccache -s
before_cache:
- brew cleanup

215
Makefile.am Normal file
View File

@ -0,0 +1,215 @@
AUTOMAKE_OPTIONS=nostdinc
# Required for automake < 1.14
ACLOCAL_AMFLAGS = -I m4
if COMPOSITE
COMPOSITE_DIR=composite
endif
if GLX
GLX_DIR=glx
endif
if DBE
DBE_DIR=dbe
endif
if RECORD
RECORD_DIR=record
endif
if DRI3
DRI3_DIR=dri3
endif
if PRESENT
PRESENT_DIR=present
endif
if PSEUDORAMIX
PSEUDORAMIX_DIR=pseudoramiX
endif
if GLAMOR
GLAMOR_DIR=glamor
endif
SUBDIRS = \
doc \
man \
include \
dix \
fb \
mi \
Xext \
miext \
os \
randr \
render \
Xi \
xkb \
$(PSEUDORAMIX_DIR) \
$(DBE_DIR) \
$(RECORD_DIR) \
xfixes \
damageext \
$(COMPOSITE_DIR) \
$(GLX_DIR) \
$(PRESENT_DIR) \
$(DRI3_DIR) \
exa \
$(GLAMOR_DIR) \
config \
hw \
test
if XORG
aclocaldir = $(datadir)/aclocal
aclocal_DATA = xorg-server.m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-server.pc
endif
EXTRA_DIST = xorg-server.pc.in xorg-server.m4 autogen.sh README.md
DISTCHECK_CONFIGURE_FLAGS=\
--with-xkb-path=$(XKB_BASE_DIRECTORY) \
--with-xkb-bin-directory=$(XKB_BIN_DIRECTORY) \
--with-xkb-output='$${datadir}/X11/xkb/compiled'
.PHONY: ChangeLog INSTALL
INSTALL:
$(INSTALL_CMD)
ChangeLog:
$(CHANGELOG_CMD)
dist-hook: ChangeLog INSTALL
DIST_SUBDIRS = \
doc \
man \
include \
dix \
fb \
mi \
Xext \
miext \
os \
pseudoramiX \
randr \
render \
Xi \
xkb \
dbe \
record \
xfixes \
damageext \
composite \
glx \
exa \
glamor \
config \
dri3 \
present \
hw \
test
# gross hack
relink: all
$(AM_V_at)$(MAKE) -C hw relink
install-headers: Makefile
+find . -name Makefile | while read m; do \
if grep -q install-sdkHEADERS $$m; then \
(cd `dirname "$$m"` && make install-sdkHEADERS) \
fi \
done
distcheck-hook:
cd $(srcdir) && \
meson setup _distcheck_build && \
meson configure _distcheck_build && \
ninja -C _distcheck_build && \
rm -rf _distcheck_build && \
cd -
EXTRA_DIST += \
meson_options.txt \
include/xorg-config.h.meson.in \
include/xwin-config.h.meson.in \
hw/xfree86/loader/symbol-test.c \
composite/meson.build \
config/meson.build \
damageext/meson.build \
dbe/meson.build \
dix/meson.build \
dri3/meson.build \
exa/meson.build \
fb/meson.build \
glamor/meson.build \
glx/meson.build \
hw/dmx/config/meson.build \
hw/dmx/examples/meson.build \
hw/dmx/glxProxy/meson.build \
hw/dmx/input/meson.build \
hw/dmx/meson.build \
hw/kdrive/ephyr/meson.build \
hw/kdrive/meson.build \
hw/kdrive/src/meson.build \
hw/meson.build \
hw/vfb/meson.build \
hw/xfree86/common/meson.build \
hw/xfree86/ddc/meson.build \
hw/xfree86/dixmods/meson.build \
hw/xfree86/dri2/meson.build \
hw/xfree86/dri/meson.build \
hw/xfree86/drivers/modesetting/meson.build \
hw/xfree86/exa/meson.build \
hw/xfree86/fbdevhw/meson.build \
hw/xfree86/glamor_egl/meson.build \
hw/xfree86/i2c/meson.build \
hw/xfree86/int10/meson.build \
hw/xfree86/loader/meson.build \
hw/xfree86/meson.build \
hw/xfree86/modes/meson.build \
hw/xfree86/os-support/meson.build \
hw/xfree86/parser/meson.build \
hw/xfree86/ramdac/meson.build \
hw/xfree86/shadowfb/meson.build \
hw/xfree86/vgahw/meson.build \
hw/xfree86/x86emu/meson.build \
hw/xfree86/xkb/meson.build \
hw/xnest/meson.build \
hw/xquartz/meson.build \
hw/xwayland/meson.build \
hw/xwin/dri/meson.build \
hw/xwin/glx/meson.build \
hw/xwin/meson.build \
hw/xwin/winclipboard/meson.build \
include/meson.build \
meson.build \
miext/damage/meson.build \
miext/shadow/meson.build \
miext/sync/meson.build \
mi/meson.build \
os/meson.build \
present/meson.build \
pseudoramiX/meson.build \
randr/meson.build \
record/meson.build \
render/meson.build \
test/bigreq/meson.build \
test/bigreq/request-length.c \
test/meson.build \
test/sync/meson.build \
test/sync/sync.c \
Xext/meson.build \
xfixes/meson.build \
Xi/meson.build \
xkb/meson.build
DISTCLEANFILES = buildDateTime.h

120
Xext/Makefile.am Normal file
View File

@ -0,0 +1,120 @@
noinst_LTLIBRARIES = libXext.la libXvidmode.la libhashtable.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = xvdix.h xvmcext.h geext.h geint.h shmint.h syncsdk.h
endif
# Sources always included in libXextbuiltin.la, libXext.la
BUILTIN_SRCS = \
bigreq.c \
geext.c \
shape.c \
sleepuntil.c \
sleepuntil.h \
sync.c \
syncsdk.h \
syncsrv.h \
xcmisc.c \
xtest.c
BUILTIN_LIBS =
# Optional sources included if extension enabled by configure.ac rules
# MIT Shared Memory extension
MITSHM_SRCS = shm.c shmint.h
if MITSHM
BUILTIN_SRCS += $(MITSHM_SRCS)
endif
# XVideo extension
XV_SRCS = xvmain.c xvdisp.c xvmc.c xvdix.h xvmcext.h xvdisp.h
if XV
BUILTIN_SRCS += $(XV_SRCS)
endif
# XResource extension: lets clients get data about per-client resource usage
RES_SRCS = xres.c
if RES
BUILTIN_SRCS += $(RES_SRCS)
endif
# MIT ScreenSaver extension
SCREENSAVER_SRCS = saver.c
if SCREENSAVER
BUILTIN_SRCS += $(SCREENSAVER_SRCS)
endif
# Xinerama extension: making multiple video devices act as one virtual screen
XINERAMA_SRCS = panoramiX.c panoramiX.h panoramiXh.h panoramiXsrv.h panoramiXprocs.c panoramiXSwap.c
if XINERAMA
BUILTIN_SRCS += $(XINERAMA_SRCS)
if XORG
sdk_HEADERS += panoramiXsrv.h panoramiX.h
endif
endif
# X-ACE extension: provides hooks for building security policy extensions
# like XC-Security, X-SELinux & XTSol
XACE_SRCS = xace.c xace.h xacestr.h
if XACE
BUILTIN_SRCS += $(XACE_SRCS)
if XORG
sdk_HEADERS += xace.h xacestr.h
endif
endif
# SELinux extension: provides SELinux policy support for X objects
# requires X-ACE extension
XSELINUX_SRCS = xselinux_ext.c xselinux_hooks.c xselinux_label.c xselinux.h xselinuxint.h
if XSELINUX
BUILTIN_SRCS += $(XSELINUX_SRCS)
BUILTIN_LIBS += $(SELINUX_LIBS)
endif
# Security extension: multi-level security to protect clients from each other
XCSECURITY_SRCS = security.c securitysrv.h
if XCSECURITY
BUILTIN_SRCS += $(XCSECURITY_SRCS)
endif
# XF86 Big Font extension
BIGFONT_SRCS = xf86bigfont.c xf86bigfontsrv.h
if XF86BIGFONT
BUILTIN_SRCS += $(BIGFONT_SRCS)
endif
# DPMS extension
DPMS_SRCS = dpms.c dpmsproc.h
if DPMSExtension
BUILTIN_SRCS += $(DPMS_SRCS)
endif
# Now take all of the above, mix well, bake for 10 minutes and get libXext*.la
libXext_la_SOURCES = $(BUILTIN_SRCS)
libXext_la_LIBADD = $(BUILTIN_LIBS)
if RES
libXext_la_LIBADD += libhashtable.la
endif
# XVidMode extension
libXvidmode_la_SOURCES = vidmode.c
#Hashtable
libhashtable_la_SOURCES = hashtable.c hashtable.h
EXTRA_DIST = \
$(MITSHM_SRCS) \
$(XV_SRCS) \
$(RES_SRCS) \
$(SCREENSAVER_SRCS) \
$(XACE_SRCS) \
$(XCSECURITY_SRCS) \
$(XSELINUX_SRCS) \
$(XINERAMA_SRCS) \
$(BIGFONT_SRCS) \
$(DPMS_SRCS) \
$(GE_SRCS)

View File

@ -138,9 +138,15 @@ ProcGEDispatch(ClientPtr client)
static int _X_COLD
SProcGEDispatch(ClientPtr client)
{
GEClientInfoPtr pGEClient = GEGetClient(client);
REQUEST(xGEReq);
if (stuff->ReqType >= GENumberRequests)
if (pGEClient->major_version >= ARRAY_SIZE(version_requests))
return BadRequest;
if (stuff->ReqType > version_requests[pGEClient->major_version])
return BadRequest;
return (*SProcGEVector[stuff->ReqType]) (client);
}

View File

@ -73,3 +73,7 @@ libxserver_xext_vidmode = static_library('libxserver_xext_vidmode',
include_directories: inc,
dependencies: common_dep,
)
if build_xorg
install_data(hdrs_xext, install_dir: xorgsdkdir)
endif

View File

@ -37,8 +37,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid)
typedef struct {
security_context_t octx;
security_context_t dctx;
char *octx;
char *dctx;
CARD32 octx_len;
CARD32 dctx_len;
CARD32 id;
@ -48,10 +48,10 @@ typedef struct {
* Extension Dispatch
*/
static security_context_t
static char *
SELinuxCopyContext(char *ptr, unsigned len)
{
security_context_t copy = malloc(len + 1);
char *copy = malloc(len + 1);
if (!copy)
return NULL;
@ -84,7 +84,7 @@ static int
SELinuxSendContextReply(ClientPtr client, security_id_t sid)
{
SELinuxGetContextReply rep;
security_context_t ctx = NULL;
char *ctx = NULL;
int len = 0;
if (sid) {
@ -117,7 +117,7 @@ ProcSELinuxSetCreateContext(ClientPtr client, unsigned offset)
{
PrivateRec **privPtr = &client->devPrivates;
security_id_t *pSid;
security_context_t ctx = NULL;
char *ctx = NULL;
char *ptr;
int rc;
@ -165,7 +165,7 @@ ProcSELinuxGetCreateContext(ClientPtr client, unsigned offset)
static int
ProcSELinuxSetDeviceContext(ClientPtr client)
{
security_context_t ctx;
char *ctx;
security_id_t sid;
DeviceIntPtr dev;
SELinuxSubjectRec *subj;

View File

@ -114,7 +114,7 @@ SELinuxLabelClient(ClientPtr client)
int fd = XaceGetConnectionNumber(client);
SELinuxSubjectRec *subj;
SELinuxObjectRec *obj;
security_context_t ctx;
char *ctx;
subj = dixLookupPrivate(&client->devPrivates, subjectKey);
obj = dixLookupPrivate(&client->devPrivates, objectKey);
@ -169,7 +169,7 @@ SELinuxLabelInitial(void)
XaceScreenAccessRec srec;
SELinuxSubjectRec *subj;
SELinuxObjectRec *obj;
security_context_t ctx;
char *ctx;
void *unused;
/* Do the serverClient */
@ -773,7 +773,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
if (subj->sid) {
security_context_t ctx;
char *ctx;
int rc = avc_sid_to_context_raw(subj->sid, &ctx);
if (rc < 0)
@ -791,7 +791,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
if (obj->sid) {
security_context_t ctx;
char *ctx;
int rc = avc_sid_to_context_raw(obj->sid, &ctx);
if (rc < 0)
@ -847,7 +847,7 @@ void
SELinuxFlaskInit(void)
{
struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
security_context_t ctx;
char *ctx;
int ret = TRUE;
switch (selinuxEnforcingState) {

View File

@ -97,7 +97,7 @@ static int
SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec * obj, int map, int polymap)
{
const char *name = NameForAtom(atom);
security_context_t ctx;
char *ctx;
int rc = Success;
obj->poly = 1;
@ -255,7 +255,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
{
const char *name = LookupEventName(type);
security_id_t sid;
security_context_t ctx;
char *ctx;
type &= 127;
@ -291,7 +291,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
int
SELinuxExtensionToSID(const char *name, security_id_t * sid_rtn)
{
security_context_t ctx;
char *ctx;
/* Look in the mappings of extension names to contexts */
if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) {
@ -347,10 +347,10 @@ SELinuxTypeToClass(RESTYPE type)
return (security_class_t) (unsigned long) tmp;
}
security_context_t
char *
SELinuxDefaultClientLabel(void)
{
security_context_t ctx;
char *ctx;
if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0)
FatalError("SELinux: failed to look up remote-client context\n");

View File

@ -99,7 +99,7 @@ int
security_class_t SELinuxTypeToClass(RESTYPE type);
security_context_t SELinuxDefaultClientLabel(void);
char *SELinuxDefaultClientLabel(void);
void
SELinuxLabelInit(void);

111
Xi/Makefile.am Normal file
View File

@ -0,0 +1,111 @@
noinst_LTLIBRARIES = libXi.la libXistubs.la
AM_CFLAGS = $(DIX_CFLAGS)
libXi_la_SOURCES = \
allowev.c \
allowev.h \
chgdctl.c \
chgdctl.h \
chgfctl.c \
chgfctl.h \
chgkbd.c \
chgkbd.h \
chgkmap.c \
chgkmap.h \
chgprop.c \
chgprop.h \
chgptr.c \
chgptr.h \
closedev.c \
closedev.h \
devbell.c \
devbell.h \
exevents.c \
exglobals.h \
extinit.c \
getbmap.c \
getbmap.h \
getdctl.c \
getdctl.h \
getfctl.c \
getfctl.h \
getfocus.c \
getfocus.h \
getkmap.c \
getkmap.h \
getmmap.c \
getmmap.h \
getprop.c \
getprop.h \
getselev.c \
getselev.h \
getvers.c \
getvers.h \
grabdev.c \
grabdev.h \
grabdevb.c \
grabdevb.h \
grabdevk.c \
grabdevk.h \
gtmotion.c \
gtmotion.h \
listdev.c \
listdev.h \
opendev.c \
opendev.h \
queryst.c \
queryst.h \
selectev.c \
selectev.h \
sendexev.c \
sendexev.h \
setbmap.c \
setbmap.h \
setdval.c \
setdval.h \
setfocus.c \
setfocus.h \
setmmap.c \
setmmap.h \
setmode.c \
setmode.h \
ungrdev.c \
ungrdev.h \
ungrdevb.c \
ungrdevb.h \
ungrdevk.c \
ungrdevk.h \
xiallowev.c \
xiallowev.h \
xibarriers.c \
xibarriers.h \
xichangecursor.c \
xichangecursor.h \
xichangehierarchy.c \
xichangehierarchy.h \
xigetclientpointer.c \
xigetclientpointer.h \
xigrabdev.c \
xigrabdev.h \
xipassivegrab.h \
xipassivegrab.c \
xiproperty.c \
xiproperty.h \
xiquerydevice.c \
xiquerydevice.h \
xiquerypointer.c \
xiquerypointer.h \
xiqueryversion.c \
xiqueryversion.h \
xiselectev.c \
xiselectev.h \
xisetclientpointer.c \
xisetclientpointer.h \
xisetdevfocus.c \
xisetdevfocus.h \
xiwarppointer.c \
xiwarppointer.h
libXistubs_la_SOURCES = \
stubs.c

View File

@ -95,6 +95,7 @@ SOFTWARE.
#include "exevents.h"
#include "extnsionst.h"
#include "exglobals.h"
#include "eventstr.h"
#include "dixevents.h" /* DeliverFocusedEvent */
#include "dixgrabs.h" /* CreateGrab() */
#include "scrnintstr.h"
@ -168,6 +169,49 @@ IsTouchEvent(InternalEvent *event)
return FALSE;
}
Bool
IsGestureEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureBeginEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GestureSwipeBegin:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureEndEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchEnd:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* @return the device matching the deviceid of the device set in the event, or
* NULL if the event is not an XInput event.
@ -647,6 +691,25 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
/* Don't remove touch class if from->touch is non-existent. The to device
* may have an active touch grab, so we need to keep the touch class record
* around. */
if (from->gesture) {
if (!to->gesture) {
classes = to->unused_classes;
to->gesture = classes->gesture;
if (!to->gesture) {
if (!InitGestureClassDeviceStruct(to, from->gesture->max_touches))
FatalError("[Xi] no memory for class shift.\n");
}
else
classes->gesture = NULL;
}
to->gesture->sourceid = from->gesture->sourceid;
/* to->gesture->gesture is separate on the master, don't copy */
}
/* Don't remove gesture class if from->gesture is non-existent. The to device
* may have an active gesture grab, so we need to keep the gesture class record
* around. */
}
/**
@ -1292,21 +1355,13 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
int rc;
InputClients *iclients = NULL;
*mask = NULL;
*grab = NULL;
if (listener->type == TOUCH_LISTENER_GRAB ||
listener->type == TOUCH_LISTENER_POINTER_GRAB) {
*grab = listener->grab;
BUG_RETURN_VAL(!*grab, FALSE);
}
else if (ti->emulate_pointer && dev->deviceGrab.grab &&
!dev->deviceGrab.fromPassiveGrab) {
/* There may be an active pointer grab on the device */
*grab = dev->deviceGrab.grab;
}
if (*grab) {
*client = rClient(*grab);
*win = (*grab)->window;
*mask = (*grab)->xi2mask;
@ -1363,6 +1418,8 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
/* if owner selected, oclients is NULL */
*client = oclients ? rClient(oclients) : wClient(*win);
}
*grab = NULL;
}
return TRUE;
@ -1379,6 +1436,16 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
int nevents;
DeviceIntPtr kbd;
/* There may be a pointer grab on the device */
if (!grab) {
grab = dev->deviceGrab.grab;
if (grab) {
win = grab->window;
xi2mask = grab->xi2mask;
client = rClient(grab);
}
}
/* We don't deliver pointer events to non-owners */
if (!TouchResourceIsOwner(ti, listener->listener))
return !Success;
@ -1676,6 +1743,72 @@ ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
free(ev);
}
static BOOL
IsAnotherGestureActiveOnMaster(DeviceIntPtr dev, InternalEvent* ev)
{
GestureClassPtr g = dev->gesture;
if (g->gesture.active && g->gesture.sourceid != ev->gesture_event.sourceid) {
return TRUE;
}
return FALSE;
}
/**
* Processes and delivers a Gesture{Pinch,Swipe}{Begin,Update,End}.
*
* Due to having rather different delivery semantics (see the Xi 2.4 protocol
* spec for more information), this implements its own grab and event-selection
* delivery logic.
*/
void
ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev)
{
GestureInfoPtr gi;
DeviceIntPtr kbd;
Bool deactivateGestureGrab = FALSE;
Bool delivered = FALSE;
if (!dev->gesture)
return;
if (IsMaster(dev) && IsAnotherGestureActiveOnMaster(dev, ev))
return;
if (IsGestureBeginEvent(ev))
gi = GestureBeginGesture(dev, ev);
else
gi = GestureFindActiveByEventType(dev, ev->any.type);
if (!gi) {
/* This may happen if gesture is no longer active or was never started. */
return;
}
kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
event_set_state_gesture(kbd, &ev->gesture_event);
if (IsGestureBeginEvent(ev))
GestureSetupListener(dev, gi, ev);
if (IsGestureEndEvent(ev) &&
dev->deviceGrab.grab &&
dev->deviceGrab.fromPassiveGrab &&
GrabIsGestureGrab(dev->deviceGrab.grab))
deactivateGestureGrab = TRUE;
delivered = DeliverGestureEventToOwner(dev, gi, ev);
if (delivered && !deactivateGestureGrab &&
(IsGestureBeginEvent(ev) || IsGestureEndEvent(ev)))
FreezeThisEventIfNeededForSyncGrab(dev, ev);
if (IsGestureEndEvent(ev))
GestureEndGesture(gi);
if (deactivateGestureGrab)
(*dev->deviceGrab.DeactivateGrab) (dev);
}
/**
* Process DeviceEvents and DeviceChangedEvents.
*/
@ -1870,6 +2003,14 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
case ET_BarrierLeave:
ProcessBarrierEvent(ev, device);
break;
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ProcessGestureEvent(ev, device);
break;
default:
ProcessDeviceEvent(ev, device);
break;
@ -2074,6 +2215,111 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
}
}
/**
* Attempts to deliver a gesture event to the given client.
*/
static Bool
DeliverOneGestureEvent(ClientPtr client, DeviceIntPtr dev, GestureInfoPtr gi,
GrabPtr grab, WindowPtr win, InternalEvent *ev)
{
int err;
xEvent *xi2;
Mask filter;
Window child = DeepestSpriteWin(&gi->sprite)->drawable.id;
/* If we fail here, we're going to leave a client hanging. */
err = EventToXI2(ev, &xi2);
if (err != Success)
FatalError("[Xi] %s: XI2 conversion failed in %s"
" (%d)\n", dev->name, __func__, err);
FixUpEventFromWindow(&gi->sprite, xi2, win, child, FALSE);
filter = GetEventFilter(dev, xi2);
if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
return FALSE;
err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
free(xi2);
/* Returning the value from TryClientEvents isn't useful, since all our
* resource-gone cleanups will update the delivery list anyway. */
return TRUE;
}
/**
* Given a gesture event and a potential listener, retrieve info needed for processing the event.
*
* @param dev The device generating the gesture event.
* @param ev The gesture event to process.
* @param listener The gesture event listener that may receive the gesture event.
* @param[out] client The client that should receive the gesture event.
* @param[out] win The window to deliver the event on.
* @param[out] grab The grab to deliver the event through, if any.
* @return TRUE if an event should be delivered to the listener, FALSE
* otherwise.
*/
static Bool
RetrieveGestureDeliveryData(DeviceIntPtr dev, InternalEvent *ev, GestureListener* listener,
ClientPtr *client, WindowPtr *win, GrabPtr *grab)
{
int rc;
int evtype;
InputClients *iclients = NULL;
*grab = NULL;
if (listener->type == GESTURE_LISTENER_GRAB ||
listener->type == GESTURE_LISTENER_NONGESTURE_GRAB) {
*grab = listener->grab;
BUG_RETURN_VAL(!*grab, FALSE);
*client = rClient(*grab);
*win = (*grab)->window;
}
else {
rc = dixLookupResourceByType((void **) win, listener->listener, listener->resource_type,
serverClient, DixSendAccess);
if (rc != Success)
return FALSE;
/* note that we only will have XI2 listeners as
listener->type == GESTURE_LISTENER_REGULAR */
evtype = GetXI2Type(ev->any.type);
nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
if (xi2mask_isset(iclients->xi2mask, dev, evtype))
break;
BUG_RETURN_VAL(!iclients, FALSE);
*client = rClient(iclients);
}
return TRUE;
}
/**
* Delivers a gesture to the owner, if possible and needed. Returns whether
* an event was delivered.
*/
Bool
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
{
GrabPtr grab = NULL;
ClientPtr client;
WindowPtr win;
if (!gi->has_listener || gi->listener.type == GESTURE_LISTENER_NONGESTURE_GRAB) {
return 0;
}
if (!RetrieveGestureDeliveryData(dev, ev, &gi->listener, &client, &win, &grab))
return 0;
ev->gesture_event.deviceid = dev->id;
return DeliverOneGestureEvent(client, dev, gi, grab, win, ev);
}
int
InitProximityClassDeviceStruct(DeviceIntPtr dev)
{
@ -2379,8 +2625,8 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
/* Touch grab */
int
GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
GrabParameters *param, GrabMask *mask)
GrabTouchOrGesture(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
int type, GrabParameters *param, GrabMask *mask)
{
WindowPtr pWin;
GrabPtr grab;
@ -2398,7 +2644,7 @@ GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
return rc;
grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
mask, param, type, 0, NullWindow, NullCursor);
if (!grab)
return BadAlloc;

View File

@ -850,6 +850,74 @@ SBarrierEvent(xXIBarrierEvent * from,
swapl(&to->eventid);
}
static void
SGesturePinchEvent(xXIGesturePinchEvent* from,
xXIGesturePinchEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swapl(&to->scale);
swapl(&to->delta_angle);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
static void
SGestureSwipeEvent(xXIGestureSwipeEvent* from,
xXIGestureSwipeEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
/** Event swapping function for XI2 events. */
void _X_COLD
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
@ -901,6 +969,18 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
SBarrierEvent((xXIBarrierEvent *) from,
(xXIBarrierEvent *) to);
break;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
SGesturePinchEvent((xXIGesturePinchEvent*) from,
(xXIGesturePinchEvent*) to);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
SGestureSwipeEvent((xXIGestureSwipeEvent*) from,
(xXIGestureSwipeEvent*) to);
break;
default:
ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
break;

View File

@ -39,6 +39,6 @@
int SProcXIChangeHierarchy(ClientPtr /* client */ );
int ProcXIChangeHierarchy(ClientPtr /* client */ );
void XISendDeviceHierarchyEvent(int flags[]);
void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]);
#endif /* CHDEVHIER_H */

View File

@ -114,14 +114,18 @@ ProcXIPassiveGrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
if ((stuff->grab_type == XIGrabtypeEnter ||
stuff->grab_type == XIGrabtypeFocusIn ||
stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
stuff->grab_type == XIGrabtypeTouchBegin ||
stuff->grab_type == XIGrabtypeGesturePinchBegin ||
stuff->grab_type == XIGrabtypeGestureSwipeBegin) && stuff->detail != 0) {
client->errorValue = stuff->detail;
return BadValue;
}
@ -217,7 +221,16 @@ ProcXIPassiveGrabDevice(ClientPtr client)
status = GrabWindow(client, dev, stuff->grab_type, &param, &mask);
break;
case XIGrabtypeTouchBegin:
status = GrabTouch(client, dev, mod_dev, &param, &mask);
status = GrabTouchOrGesture(client, dev, mod_dev, XI_TouchBegin,
&param, &mask);
break;
case XIGrabtypeGesturePinchBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GesturePinchBegin, &param, &mask);
break;
case XIGrabtypeGestureSwipeBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GestureSwipeBegin, &param, &mask);
break;
}
@ -307,7 +320,9 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
@ -348,6 +363,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
case XIGrabtypeTouchBegin:
tempGrab->type = XI_TouchBegin;
break;
case XIGrabtypeGesturePinchBegin:
tempGrab->type = XI_GesturePinchBegin;
break;
case XIGrabtypeGestureSwipeBegin:
tempGrab->type = XI_GestureSwipeBegin;
break;
}
tempGrab->grabtype = XI2;
tempGrab->modifierDevice = mod_dev;

View File

@ -43,6 +43,9 @@
#include "xace.h"
#include "inpututils.h"
#include "exglobals.h"
#include "privates.h"
#include "xiquerydevice.h"
static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
@ -234,6 +237,9 @@ SizeDeviceClasses(DeviceIntPtr dev)
if (dev->touch)
len += sizeof(xXITouchInfo);
if (dev->gesture)
len += sizeof(xXIGestureInfo);
return len;
}
@ -464,6 +470,46 @@ SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
swaps(&touch->sourceid);
}
static Bool ShouldListGestureInfo(ClientPtr client)
{
/* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
* properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
* applications, we instead report Gesture device class only if the client advertised support
* for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
* and then a completely separate module within the client uses broken libxcb to call
* XIQueryDevice.
*/
XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
if (pXIClient->major_version) {
return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
}
return FALSE;
}
/**
* List gesture information
*
* @return The number of bytes written into info.
*/
static int
ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
gesture->type = XIGestureClass;
gesture->length = sizeof(xXIGestureInfo) >> 2;
gesture->sourceid = dev->gesture->sourceid;
gesture->num_touches = dev->gesture->max_touches;
return gesture->length << 2;
}
static void
SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
swaps(&gesture->type);
swaps(&gesture->length);
swaps(&gesture->sourceid);
}
int
GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
{
@ -567,6 +613,13 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
total_len += len;
}
if (dev->gesture && ShouldListGestureInfo(client)) {
(*nclasses)++;
len = ListGestureInfo(dev, (xXIGestureInfo *) any);
any += len;
total_len += len;
}
return total_len;
}
@ -598,7 +651,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
case XITouchClass:
SwapTouchInfo(dev, (xXITouchInfo *) any);
break;
case XIGestureClass:
SwapGestureInfo(dev, (xXIGestureInfo *) any);
break;
}
any += len * 4;

View File

@ -226,8 +226,41 @@ ProcXISelectEvents(ClientPtr client)
return BadValue;
}
/* Only one client per window may select for touch events on the
* same devices, including master devices.
/* All three pinch gesture events must be selected at once */
if ((BitIsOn(bits, XI_GesturePinchBegin) ||
BitIsOn(bits, XI_GesturePinchUpdate) ||
BitIsOn(bits, XI_GesturePinchEnd)) &&
(!BitIsOn(bits, XI_GesturePinchBegin) ||
!BitIsOn(bits, XI_GesturePinchUpdate) ||
!BitIsOn(bits, XI_GesturePinchEnd))) {
client->errorValue = XI_GesturePinchBegin;
return BadValue;
}
/* All three swipe gesture events must be selected at once. Note
that the XI_GestureSwipeEnd is at index 32 which is on the next
4-byte mask element */
if (evmask->mask_len == 1 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate)))
{
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
if (evmask->mask_len >= 2 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate) ||
BitIsOn(bits, XI_GestureSwipeEnd)) &&
(!BitIsOn(bits, XI_GestureSwipeBegin) ||
!BitIsOn(bits, XI_GestureSwipeUpdate) ||
!BitIsOn(bits, XI_GestureSwipeEnd))) {
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
/* Only one client per window may select for touch or gesture events
* on the same devices, including master devices.
* XXX: This breaks if a device goes from floating to attached. */
if (BitIsOn(bits, XI_TouchBegin)) {
rc = check_for_touch_selection_conflicts(client,
@ -237,6 +270,22 @@ ProcXISelectEvents(ClientPtr client)
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GesturePinchBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GesturePinchBegin);
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GestureSwipeBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GestureSwipeBegin);
if (rc != Success)
return rc;
}
}
if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],

17
autogen.sh Executable file
View File

@ -0,0 +1,17 @@
#! /bin/sh
srcdir=`dirname "$0"`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd "$srcdir"
autoreconf --force -v --install || exit 1
cd "$ORIGDIR" || exit $?
git config --local --get format.subjectPrefix ||
git config --local format.subjectPrefix "PATCH xserver"
if test -z "$NOCONFIGURE"; then
exec "$srcdir"/configure "$@"
fi

15
composite/Makefile.am Normal file
View File

@ -0,0 +1,15 @@
noinst_LTLIBRARIES = libcomposite.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = compositeext.h
endif
libcomposite_la_SOURCES = \
compalloc.c \
compext.c \
compint.h \
compinit.c \
compoverlay.c \
compwindow.c

View File

@ -15,3 +15,7 @@ libxserver_composite = static_library('libxserver_composite',
include_directories: inc,
dependencies: common_dep,
)
if build_xorg
install_data(hdrs_composite, install_dir: xorgsdkdir)
endif

38
config/10-quirks.conf Normal file
View File

@ -0,0 +1,38 @@
# Collection of quirks and blacklist/whitelists for specific devices.
# Accelerometer device, posts data through ABS_X/ABS_Y, making X unusable
# http://bugs.freedesktop.org/show_bug.cgi?id=22442
Section "InputClass"
Identifier "ThinkPad HDAPS accelerometer blacklist"
MatchProduct "ThinkPad HDAPS accelerometer data"
Option "Ignore" "on"
EndSection
# https://bugzilla.redhat.com/show_bug.cgi?id=523914
# Mouse does not move in PV Xen guest
# Explicitly tell evdev to not ignore the absolute axes.
Section "InputClass"
Identifier "Xen Virtual Pointer axis blacklist"
MatchProduct "Xen Virtual Pointer"
Option "IgnoreAbsoluteAxes" "off"
Option "IgnoreRelativeAxes" "off"
EndSection
# https://bugs.freedesktop.org/show_bug.cgi?id=55867
# Bug 55867 - Doesn't know how to tag XI_TRACKBALL
Section "InputClass"
Identifier "Tag trackballs as XI_TRACKBALL"
MatchProduct "trackball"
MatchDriver "evdev"
Option "TypeName" "TRACKBALL"
EndSection
# https://bugs.freedesktop.org/show_bug.cgi?id=62831
# Bug 62831 - Mionix Naos 5000 mouse detected incorrectly
Section "InputClass"
Identifier "Tag Mionix Naos 5000 mouse XI_MOUSE"
MatchProduct "La-VIEW Technology Naos 5000 Mouse"
MatchDriver "evdev"
Option "TypeName" "MOUSE"
EndSection

41
config/Makefile.am Normal file
View File

@ -0,0 +1,41 @@
AM_CFLAGS = $(DIX_CFLAGS)
noinst_LTLIBRARIES = libconfig.la
libconfig_la_SOURCES = config.c config-backends.h
libconfig_la_LIBADD =
if NEED_DBUS
AM_CFLAGS += $(DBUS_CFLAGS)
libconfig_la_SOURCES += dbus-core.c
libconfig_la_LIBADD += $(DBUS_LIBS)
endif
if CONFIG_UDEV
AM_CFLAGS += $(UDEV_CFLAGS)
libconfig_la_SOURCES += udev.c
libconfig_la_LIBADD += $(UDEV_LIBS)
if XORG
xorgconfddir = $(datadir)/X11/$(XF86CONFIGDIR)
xorgconfd_DATA = 10-quirks.conf
endif
else
if CONFIG_HAL
AM_CFLAGS += $(HAL_CFLAGS)
libconfig_la_SOURCES += hal.c
libconfig_la_LIBADD += $(HAL_LIBS)
else
if CONFIG_WSCONS
libconfig_la_SOURCES += wscons.c
endif # CONFIG_WSCONS
endif # !CONFIG_HAL
endif # !CONFIG_UDEV
EXTRA_DIST = x11-input.fdi fdi2iclass.py 10-quirks.conf

46
config/config-backends.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "input.h"
#include "list.h"
void remove_devices(const char *backend, const char *config_info);
BOOL device_is_duplicate(const char *config_info);
#ifdef CONFIG_UDEV
int config_udev_pre_init(void);
int config_udev_init(void);
void config_udev_fini(void);
void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
#elif defined(CONFIG_HAL)
int config_hal_init(void);
void config_hal_fini(void);
#elif defined(CONFIG_WSCONS)
int config_wscons_init(void);
void config_wscons_fini(void);
#endif

151
config/config.c Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <unistd.h>
#include "os.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "systemd-logind.h"
void
config_pre_init(void)
{
#ifdef CONFIG_UDEV
if (!config_udev_pre_init())
ErrorF("[config] failed to pre-init udev\n");
#endif
}
void
config_init(void)
{
#ifdef CONFIG_UDEV
if (!config_udev_init())
ErrorF("[config] failed to initialise udev\n");
#elif defined(CONFIG_HAL)
if (!config_hal_init())
ErrorF("[config] failed to initialise HAL\n");
#elif defined(CONFIG_WSCONS)
if (!config_wscons_init())
ErrorF("[config] failed to initialise wscons\n");
#endif
}
void
config_fini(void)
{
#if defined(CONFIG_UDEV)
config_udev_fini();
#elif defined(CONFIG_HAL)
config_hal_fini();
#elif defined(CONFIG_WSCONS)
config_wscons_fini();
#endif
}
void
config_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
#if defined(CONFIG_UDEV_KMS)
config_udev_odev_probe(probe_callback);
#endif
}
static void
remove_device(const char *backend, DeviceIntPtr dev)
{
/* this only gets called for devices that have already been added */
LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name);
/* Call PIE here so we don't try to dereference a device that's
* already been removed. */
input_lock();
ProcessInputEvents();
DeleteInputDeviceRequest(dev);
input_unlock();
}
void
remove_devices(const char *backend, const char *config_info)
{
DeviceIntPtr dev, next;
for (dev = inputInfo.devices; dev; dev = next) {
next = dev->next;
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
remove_device(backend, dev);
}
for (dev = inputInfo.off_devices; dev; dev = next) {
next = dev->next;
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
remove_device(backend, dev);
}
RemoveInputDeviceTraces(config_info);
}
BOOL
device_is_duplicate(const char *config_info)
{
DeviceIntPtr dev;
for (dev = inputInfo.devices; dev; dev = dev->next) {
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
return TRUE;
}
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
return TRUE;
}
return FALSE;
}
struct OdevAttributes *
config_odev_allocate_attributes(void)
{
struct OdevAttributes *attribs =
xnfcalloc(1, sizeof (struct OdevAttributes));
attribs->fd = -1;
return attribs;
}
void
config_odev_free_attributes(struct OdevAttributes *attribs)
{
if (attribs->fd != -1)
systemd_logind_release_fd(attribs->major, attribs->minor, attribs->fd);
free(attribs->path);
free(attribs->syspath);
free(attribs->busid);
free(attribs->driver);
free(attribs);
}

40
config/dbus-api Normal file
View File

@ -0,0 +1,40 @@
D-BUS Configuration API v2
----------------------------
The X server will register the bus name org.x.config.displayN, and the
object /org/x/config/N, where N is the display number.
Currently only hotplugging of input devices is supported.
org.x.config.input:
org.x.config.input.version:
Returns one unsigned int32, which is the API version.
org.x.config.input.add:
Takes an argument of key/value option pairs in arrays, e.g.:
[ss][ss][ss][ss]
is the signature for four options. These options will be passed
to the input driver as with any others.
Option names beginning with _ are not allowed; they are reserved
for internal use.
Returns a number of signed int32s. Positive integers are the
device IDs of new devices; negative numbers are X error codes,
as defined in X.h. BadMatch will be returned if the options
given do not match any device. BadValue is returned for a malformed
message. (Example: 8 is new device ID 8; -8 is BadMatch.)
Notably, BadAlloc is never returned: the server internally signals
to D-BUS that the attempt failed for lack of memory.
org.x.config.input.remove:
Takes one uint32 argument, which is the device ID to remove, i.e.:
u
is the signature.
Returns one signed int32 which represents an X status as defined in
X.h. See org.x.config.input.add. Error codes are negative numbers.
org.x.config.input.listDevices:
Lists the currently active devices. No argument.
Return value is sequence of [<id> <name>] [<id> <name>] ..., i.e. [us].

238
config/dbus-core.c Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright © 2006-2007 Daniel Stone
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dbus/dbus.h>
#include <sys/select.h>
#include "dix.h"
#include "os.h"
#include "dbus-core.h"
/* How often to attempt reconnecting when we get booted off the bus. */
#define RECONNECT_DELAY (10 * 1000) /* in ms */
struct dbus_core_info {
int fd;
DBusConnection *connection;
OsTimerPtr timer;
struct dbus_core_hook *hooks;
};
static struct dbus_core_info bus_info = { .fd = -1 };
static CARD32 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg);
static void
socket_handler(int fd, int ready, void *data)
{
struct dbus_core_info *info = data;
if (info->connection) {
do {
dbus_connection_read_write_dispatch(info->connection, 0);
} while (info->connection &&
dbus_connection_get_is_connected(info->connection) &&
dbus_connection_get_dispatch_status(info->connection) ==
DBUS_DISPATCH_DATA_REMAINS);
}
}
/**
* Disconnect (if we haven't already been forcefully disconnected), clean up
* after ourselves, and call all registered disconnect hooks.
*/
static void
teardown(void)
{
struct dbus_core_hook *hook;
if (bus_info.timer) {
TimerFree(bus_info.timer);
bus_info.timer = NULL;
}
/* We should really have pre-disconnect hooks and run them here, for
* completeness. But then it gets awkward, given that you can't
* guarantee that they'll be called ... */
if (bus_info.connection)
dbus_connection_unref(bus_info.connection);
if (bus_info.fd != -1)
RemoveNotifyFd(bus_info.fd);
bus_info.fd = -1;
bus_info.connection = NULL;
for (hook = bus_info.hooks; hook; hook = hook->next) {
if (hook->disconnect)
hook->disconnect(hook->data);
}
}
/**
* This is a filter, which only handles the disconnected signal, which
* doesn't go to the normal message handling function. This takes
* precedence over the message handling function, so have have to be
* careful to ignore anything we don't want to deal with here.
*/
static DBusHandlerResult
message_filter(DBusConnection * connection, DBusMessage * message, void *data)
{
/* If we get disconnected, then take everything down, and attempt to
* reconnect immediately (assuming it's just a restart). The
* connection isn't valid at this point, so throw it out immediately. */
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
DebugF("[dbus-core] disconnected from bus\n");
bus_info.connection = NULL;
teardown();
if (bus_info.timer)
TimerFree(bus_info.timer);
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
/**
* Attempt to connect to the system bus, and set a filter to deal with
* disconnection (see message_filter above).
*
* @return 1 on success, 0 on failure.
*/
static int
connect_to_bus(void)
{
DBusError error;
struct dbus_core_hook *hook;
dbus_error_init(&error);
bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if (!bus_info.connection || dbus_error_is_set(&error)) {
LogMessage(X_ERROR, "dbus-core: error connecting to system bus: %s (%s)\n",
error.name, error.message);
goto err_begin;
}
/* Thankyou. Really, thankyou. */
dbus_connection_set_exit_on_disconnect(bus_info.connection, FALSE);
if (!dbus_connection_get_unix_fd(bus_info.connection, &bus_info.fd)) {
ErrorF("[dbus-core] couldn't get fd for system bus\n");
goto err_unref;
}
if (!dbus_connection_add_filter(bus_info.connection, message_filter,
&bus_info, NULL)) {
ErrorF("[dbus-core] couldn't add filter: %s (%s)\n", error.name,
error.message);
goto err_fd;
}
dbus_error_free(&error);
SetNotifyFd(bus_info.fd, socket_handler, X_NOTIFY_READ, &bus_info);
for (hook = bus_info.hooks; hook; hook = hook->next) {
if (hook->connect)
hook->connect(bus_info.connection, hook->data);
}
return 1;
err_fd:
bus_info.fd = -1;
err_unref:
dbus_connection_unref(bus_info.connection);
bus_info.connection = NULL;
err_begin:
dbus_error_free(&error);
return 0;
}
static CARD32
reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg)
{
if (connect_to_bus()) {
TimerFree(bus_info.timer);
bus_info.timer = NULL;
return 0;
}
else {
return RECONNECT_DELAY;
}
}
int
dbus_core_add_hook(struct dbus_core_hook *hook)
{
struct dbus_core_hook **prev;
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next);
hook->next = NULL;
*prev = hook;
/* If we're already connected, call the connect hook. */
if (bus_info.connection)
hook->connect(bus_info.connection, hook->data);
return 1;
}
void
dbus_core_remove_hook(struct dbus_core_hook *hook)
{
struct dbus_core_hook **prev;
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next) {
if (*prev == hook) {
*prev = hook->next;
break;
}
}
}
int
dbus_core_init(void)
{
memset(&bus_info, 0, sizeof(bus_info));
bus_info.fd = -1;
bus_info.hooks = NULL;
if (!connect_to_bus())
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
return 1;
}
void
dbus_core_fini(void)
{
teardown();
}

202
config/fdi2iclass.py Executable file
View File

@ -0,0 +1,202 @@
#!/usr/bin/python
#
# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
# Modified from Martin Pitt's original fdi2mpi.py script:
# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
#
# (C) 2010 Dan Nicholson
# (C) 2009 Canonical Ltd.
# Author: Dan Nicholson <dbn.lists@gmail.com>
# Author: Martin Pitt <martin.pitt@ubuntu.com>
#
# 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
# fur- nished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice 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,
# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import sys, xml.dom.minidom
# dict converting <match> tags to Match* entries
match_table = {
'info.product': 'MatchProduct',
'input.product': 'MatchProduct',
'info.vendor': 'MatchVendor',
'input.vendor': 'MatchVendor',
'info.device': 'MatchDevicePath',
'linux.device_file': 'MatchDevicePath',
'/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
'@info.parent:pnp.id': 'MatchPnPID',
}
# dict converting info.capabilities list to Match* entries
cap_match_table = {
'input.keys': 'MatchIsKeyboard',
'input.keyboard': 'MatchIsKeyboard',
'input.keypad': 'MatchIsKeyboard',
'input.mouse': 'MatchIsPointer',
'input.joystick': 'MatchIsJoystick',
'input.tablet': 'MatchIsTablet',
'input.touchpad': 'MatchIsTouchpad',
'input.touchscreen': 'MatchIsTouchscreen',
}
def device_glob(path):
'''Convert a contains device path to a glob entry'''
if path[0] != '/':
path = '*' + path
return path + '*'
def parse_match(node):
'''Parse a <match> tag to a tuple with InputClass values'''
match = None
value = None
booltype = False
# see what type of key we have
if node.attributes.has_key('key'):
key = node.attributes['key'].nodeValue
if key in match_table:
match = match_table[key]
elif key == 'info.capabilities':
booltype = True
# bail out now if it's unrecognized
if not match and not booltype:
return (match, value)
if node.attributes.has_key('string'):
value = node.attributes['string'].nodeValue
elif node.attributes.has_key('contains'):
value = node.attributes['contains'].nodeValue
if match == 'MatchDevicePath':
value = device_glob(value)
elif booltype and value in cap_match_table:
match = cap_match_table[value]
value = 'yes'
elif node.attributes.has_key('string_outof'):
value = node.attributes['string_outof'].nodeValue.replace(';','|')
elif node.attributes.has_key('contains_outof'):
all_values = node.attributes['contains_outof'].nodeValue.split(';')
for v in all_values:
if match == 'MatchDevicePath':
v = device_glob(v)
elif match == 'MatchPnPID' and len(v) < 7:
v += '*'
if value:
value += '|' + v
else:
value = v
return (match, value)
def parse_options(node):
'''Parse the x11_* options and return InputClass entries'''
driver = ''
ignore = False
options = []
for n in node.childNodes:
if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
continue
tag = n.tagName
key = n.attributes['key'].nodeValue
value = ''
if n.hasChildNodes():
content_node = n.childNodes[0]
assert content_node.nodeType == xml.dom.Node.TEXT_NODE
value = content_node.nodeValue
if tag == 'match':
continue
assert tag in ('addset', 'merge', 'append', 'remove')
if tag == 'remove' and key == 'input.x11_driver':
ignore = True
elif key == 'input.x11_driver':
driver = value
elif key.startswith('input.x11_options.'):
option = key.split('.', 2)[2]
options.append((option, value))
return (driver, ignore, options)
def is_match_node(node):
'''Check if a node is a <match> element'''
return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
node.tagName == 'match'
def parse_all_matches(node):
'''Parse a x11 match tag and any parents that don't supply their
own options'''
matches = []
while True:
(key, value) = parse_match(node)
if key and value:
matches.append((key, value))
# walk up to a parent match node
node = node.parentNode
if node == None or not is_match_node(node):
break
# leave if there other options at this level
children = set([n.tagName for n in node.childNodes
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
if children & set(['addset', 'merge', 'append']):
break
return matches
# stupid counter to give "unique" rule names
num_sections = 1
def print_section(matches, driver, ignore, options):
'''Print a valid InputClass section to stdout'''
global num_sections
print 'Section "InputClass"'
print '\tIdentifier "Converted Class %d"' % num_sections
num_sections += 1
for m, v in matches:
print '\t%s "%s"' % (m, v)
if driver:
print '\tDriver "%s"' % driver
if ignore:
print '\tOption "Ignore" "yes"'
for o, v in options:
print '\tOption "%s" "%s"' % (o, v)
print 'EndSection'
def parse_fdi(fdi):
'''Parse x11 matches from fdi'''
# find all <match> leaf nodes
num = 0
for match_node in fdi.getElementsByTagName('match'):
children = set([n.tagName for n in match_node.childNodes
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
# see if there are any options at this level
(driver, ignore, options) = parse_options(match_node)
if not driver and not ignore and not options:
continue
matches = parse_all_matches(match_node)
if num > 0:
print
print_section(matches, driver, ignore, options)
num += 1
for f in sys.argv[1:]:
parse_fdi(xml.dom.minidom.parse(f))

675
config/hal.c Normal file
View File

@ -0,0 +1,675 @@
/*
* Copyright © 2007 Daniel Stone
* Copyright © 2007 Red Hat, Inc.
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dbus/dbus.h>
#include <hal/libhal.h>
#include <string.h>
#include <sys/select.h>
#include "dbus-core.h"
#include "input.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "os.h"
#define LIBHAL_PROP_KEY "input.x11_options."
#define LIBHAL_XKB_PROP_KEY "input.xkb."
struct config_hal_info {
DBusConnection *system_bus;
LibHalContext *hal_ctx;
};
/* Used for special handling of xkb options. */
struct xkb_options {
char *layout;
char *model;
char *rules;
char *variant;
char *options;
};
static void
device_removed(LibHalContext * ctx, const char *udi)
{
char *value;
if (asprintf(&value, "hal:%s", udi) == -1)
return;
remove_devices("hal", value);
free(value);
}
static char *
get_prop_string(LibHalContext * hal_ctx, const char *udi, const char *name)
{
char *prop, *ret;
prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL);
LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n",
name, udi, prop ? prop : "(null)");
if (prop) {
ret = strdup(prop);
libhal_free_string(prop);
}
else {
return NULL;
}
return ret;
}
static char *
get_prop_string_array(LibHalContext * hal_ctx, const char *udi,
const char *prop)
{
char **props, *ret, *str;
int i, len = 0;
props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL);
if (props) {
for (i = 0; props[i]; i++)
len += strlen(props[i]);
ret = calloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */
if (!ret) {
libhal_free_string_array(props);
return NULL;
}
str = ret;
for (i = 0; props[i]; i++) {
strcpy(str, props[i]);
str += strlen(props[i]);
*str++ = ',';
}
*(str - 1) = '\0';
libhal_free_string_array(props);
}
else {
return NULL;
}
return ret;
}
static void
device_added(LibHalContext * hal_ctx, const char *udi)
{
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
char *hal_tags, *parent;
InputOption *input_options = NULL;
InputAttributes attrs = { 0 };
DeviceIntPtr dev = NULL;
DBusError error;
struct xkb_options xkb_opts = { 0 };
int rc;
LibHalPropertySet *set = NULL;
LibHalPropertySetIterator set_iter;
char *psi_key = NULL, *tmp_val;
dbus_error_init(&error);
driver = get_prop_string(hal_ctx, udi, "input.x11_driver");
if (!driver) {
/* verbose, don't tell the user unless they _want_ to see it */
LogMessageVerb(X_INFO, 7,
"config/hal: no driver specified for device %s\n", udi);
goto unwind;
}
path = get_prop_string(hal_ctx, udi, "input.device");
if (!path) {
LogMessage(X_WARNING,
"config/hal: no driver or path specified for %s\n", udi);
goto unwind;
}
attrs.device = strdup(path);
name = get_prop_string(hal_ctx, udi, "info.product");
if (!name)
name = strdup("(unnamed)");
else
attrs.product = strdup(name);
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
attrs.tags = xstrtokenize(hal_tags, ",");
free(hal_tags);
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL))
attrs.flags |= ATTR_POINTER;
if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL))
attrs.flags |= ATTR_JOYSTICK;
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL))
attrs.flags |= ATTR_TABLET;
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet_pad", NULL))
attrs.flags |= ATTR_TABLET_PAD;
if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL))
attrs.flags |= ATTR_TOUCHPAD;
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
attrs.flags |= ATTR_TOUCHSCREEN;
parent = get_prop_string(hal_ctx, udi, "info.parent");
if (parent) {
int usb_vendor, usb_product;
char *old_parent;
/* construct USB ID in lowercase - "0000:ffff" */
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
"usb.vendor_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.vendor_id on %s "
"returned %04x\n", parent, usb_vendor);
usb_product = libhal_device_get_property_int(hal_ctx, parent,
"usb.product_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.product_id on %s "
"returned %04x\n", parent, usb_product);
if (usb_vendor && usb_product)
if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_product)
== -1)
attrs.usb_id = NULL;
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
old_parent = parent;
while (!attrs.pnp_id &&
(parent = get_prop_string(hal_ctx, parent, "info.parent"))) {
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
free(old_parent);
old_parent = parent;
}
free(old_parent);
}
input_options = input_option_new(NULL, "_source", "server/hal");
if (!input_options) {
LogMessage(X_ERROR,
"config/hal: couldn't allocate first key/value pair\n");
goto unwind;
}
/* most drivers use device.. not path. evdev uses both however, but the
* path version isn't documented apparently. support both for now. */
input_options = input_option_new(input_options, "path", path);
input_options = input_option_new(input_options, "device", path);
input_options = input_option_new(input_options, "driver", driver);
input_options = input_option_new(input_options, "name", name);
if (asprintf(&config_info, "hal:%s", udi) == -1) {
config_info = NULL;
LogMessage(X_ERROR, "config/hal: couldn't allocate name\n");
goto unwind;
}
/* Check for duplicate devices */
if (device_is_duplicate(config_info)) {
LogMessage(X_WARNING,
"config/hal: device %s already added. Ignoring.\n", name);
goto unwind;
}
/* ok, grab options from hal.. iterate through all properties
* and lets see if any of them are options that we can add */
set = libhal_device_get_all_properties(hal_ctx, udi, &error);
if (!set) {
LogMessage(X_ERROR,
"config/hal: couldn't get property list for %s: %s (%s)\n",
udi, error.name, error.message);
goto unwind;
}
libhal_psi_init(&set_iter, set);
while (libhal_psi_has_more(&set_iter)) {
/* we are looking for supported keys.. extract and add to options */
psi_key = libhal_psi_get_key(&set_iter);
if (psi_key) {
/* normal options first (input.x11_options.<propname>) */
if (!strncasecmp
(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY) - 1)) {
char *tmp;
/* only support strings for all values */
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
if (tmp_val) {
/* xkb needs special handling. HAL specs include
* input.xkb.xyz options, but the x11-input.fdi specifies
* input.x11_options.Xkbxyz options. By default, we use
* the former, unless the specific X11 ones are specified.
* Since we can't predict the order in which the keys
* arrive, we need to store them.
*/
if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) {
if (!strcasecmp(&tmp[3], "layout")) {
free(xkb_opts.layout);
xkb_opts.layout = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "model")) {
free(xkb_opts.model);
xkb_opts.model = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "rules")) {
free(xkb_opts.rules);
xkb_opts.rules = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "variant")) {
free(xkb_opts.variant);
xkb_opts.variant = strdup(tmp_val);
}
else if (!strcasecmp(&tmp[3], "options")) {
free(xkb_opts.options);
xkb_opts.options = strdup(tmp_val);
}
}
else {
/* all others */
input_options =
input_option_new(input_options,
psi_key + sizeof(LIBHAL_PROP_KEY) -
1, tmp_val);
free(tmp_val);
}
}
else {
/* server 1.4 had xkb_options as strlist. */
if ((tmp = strcasestr(psi_key, "xkb")) &&
(strlen(tmp) >= 4) &&
(!strcasecmp(&tmp[3], "options")) &&
(tmp_val =
get_prop_string_array(hal_ctx, udi, psi_key))) {
free(xkb_opts.options);
xkb_opts.options = strdup(tmp_val);
}
}
}
else if (!strncasecmp
(psi_key, LIBHAL_XKB_PROP_KEY,
sizeof(LIBHAL_XKB_PROP_KEY) - 1)) {
char *tmp;
/* only support strings for all values */
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
if (!strcasecmp(tmp, "layout")) {
if (!xkb_opts.layout)
xkb_opts.layout = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "rules")) {
if (!xkb_opts.rules)
xkb_opts.rules = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "variant")) {
if (!xkb_opts.variant)
xkb_opts.variant = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "model")) {
if (!xkb_opts.model)
xkb_opts.model = strdup(tmp_val);
}
else if (!strcasecmp(tmp, "options")) {
if (!xkb_opts.options)
xkb_opts.options = strdup(tmp_val);
}
free(tmp_val);
}
else {
/* server 1.4 had xkb options as strlist */
tmp_val = get_prop_string_array(hal_ctx, udi, psi_key);
if (tmp_val &&
strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
if (!strcasecmp(tmp, ".options") && (!xkb_opts.options))
xkb_opts.options = strdup(tmp_val);
}
free(tmp_val);
}
}
}
/* psi_key doesn't need to be freed */
libhal_psi_next(&set_iter);
}
/* Now add xkb options */
if (xkb_opts.layout)
input_options =
input_option_new(input_options, "xkb_layout", xkb_opts.layout);
if (xkb_opts.rules)
input_options =
input_option_new(input_options, "xkb_rules", xkb_opts.rules);
if (xkb_opts.variant)
input_options =
input_option_new(input_options, "xkb_variant", xkb_opts.variant);
if (xkb_opts.model)
input_options =
input_option_new(input_options, "xkb_model", xkb_opts.model);
if (xkb_opts.options)
input_options =
input_option_new(input_options, "xkb_options", xkb_opts.options);
input_options = input_option_new(input_options, "config_info", config_info);
/* this isn't an error, but how else do you output something that the user can see? */
LogMessage(X_INFO, "config/hal: Adding input device %s\n", name);
if ((rc = NewInputDeviceRequest(input_options, &attrs, &dev)) != Success) {
LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n",
rc);
dev = NULL;
goto unwind;
}
unwind:
if (set)
libhal_free_property_set(set);
free(path);
free(driver);
free(name);
free(config_info);
input_option_free_list(&input_options);
free(attrs.product);
free(attrs.vendor);
free(attrs.device);
free(attrs.pnp_id);
free(attrs.usb_id);
if (attrs.tags) {
char **tag = attrs.tags;
while (*tag) {
free(*tag);
tag++;
}
free(attrs.tags);
}
free(xkb_opts.layout);
free(xkb_opts.rules);
free(xkb_opts.model);
free(xkb_opts.variant);
free(xkb_opts.options);
dbus_error_free(&error);
return;
}
static void
disconnect_hook(void *data)
{
DBusError error;
struct config_hal_info *info = data;
if (info->hal_ctx) {
if (dbus_connection_get_is_connected(info->system_bus)) {
dbus_error_init(&error);
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
LogMessage(X_WARNING,
"config/hal: disconnect_hook couldn't shut down context: %s (%s)\n",
error.name, error.message);
dbus_error_free(&error);
}
libhal_ctx_free(info->hal_ctx);
}
info->hal_ctx = NULL;
info->system_bus = NULL;
}
static BOOL
connect_and_register(DBusConnection * connection, struct config_hal_info *info)
{
DBusError error;
char **devices;
int num_devices, i;
if (info->hal_ctx)
return TRUE; /* already registered, pretend we did something */
info->system_bus = connection;
dbus_error_init(&error);
info->hal_ctx = libhal_ctx_new();
if (!info->hal_ctx) {
LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n");
goto out_err;
}
if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) {
LogMessage(X_ERROR,
"config/hal: couldn't associate HAL context with bus\n");
goto out_err;
}
if (!libhal_ctx_init(info->hal_ctx, &error)) {
LogMessage(X_ERROR,
"config/hal: couldn't initialise context: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_err;
}
if (!libhal_device_property_watch_all(info->hal_ctx, &error)) {
LogMessage(X_ERROR,
"config/hal: couldn't watch all properties: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_ctx;
}
libhal_ctx_set_device_added(info->hal_ctx, device_added);
libhal_ctx_set_device_removed(info->hal_ctx, device_removed);
devices = libhal_find_device_by_capability(info->hal_ctx, "input",
&num_devices, &error);
/* FIXME: Get default devices if error is set. */
if (dbus_error_is_set(&error)) {
LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
goto out_ctx;
}
for (i = 0; i < num_devices; i++)
device_added(info->hal_ctx, devices[i]);
libhal_free_string_array(devices);
dbus_error_free(&error);
return TRUE;
out_ctx:
dbus_error_free(&error);
if (!libhal_ctx_shutdown(info->hal_ctx, &error)) {
LogMessage(X_WARNING,
"config/hal: couldn't shut down context: %s (%s)\n",
error.name ? error.name : "unknown error",
error.message ? error.message : "null");
dbus_error_free(&error);
}
out_err:
dbus_error_free(&error);
if (info->hal_ctx) {
libhal_ctx_free(info->hal_ctx);
}
info->hal_ctx = NULL;
info->system_bus = NULL;
return FALSE;
}
/**
* Handle NewOwnerChanged signals to deal with HAL startup at X server runtime.
*
* NewOwnerChanged is send once when HAL shuts down, and once again when it
* comes back up. Message has three arguments, first is the name
* (org.freedesktop.Hal), the second one is the old owner, third one is new
* owner.
*/
static DBusHandlerResult
ownerchanged_handler(DBusConnection * connection, DBusMessage * message,
void *data)
{
int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (dbus_message_is_signal(message,
"org.freedesktop.DBus", "NameOwnerChanged")) {
DBusError error;
char *name, *old_owner, *new_owner;
dbus_error_init(&error);
dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
if (dbus_error_is_set(&error)) {
ErrorF
("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n",
error.name, error.message);
}
else if (name && strcmp(name, "org.freedesktop.Hal") == 0) {
if (!old_owner || !strlen(old_owner)) {
DebugF("[config/hal] HAL startup detected.\n");
if (connect_and_register
(connection, (struct config_hal_info *) data))
dbus_connection_unregister_object_path(connection,
"/org/freedesktop/DBus");
else
ErrorF("[config/hal] Failed to connect to HAL bus.\n");
}
ret = DBUS_HANDLER_RESULT_HANDLED;
}
dbus_error_free(&error);
}
return ret;
}
/**
* Register a handler for the NameOwnerChanged signal.
*/
static BOOL
listen_for_startup(DBusConnection * connection, void *data)
{
DBusObjectPathVTable vtable = {.message_function = ownerchanged_handler, };
DBusError error;
const char MATCH_RULE[] = "sender='org.freedesktop.DBus',"
"interface='org.freedesktop.DBus',"
"type='signal',"
"path='/org/freedesktop/DBus'," "member='NameOwnerChanged'";
int rc = FALSE;
dbus_error_init(&error);
dbus_bus_add_match(connection, MATCH_RULE, &error);
if (!dbus_error_is_set(&error)) {
if (dbus_connection_register_object_path(connection,
"/org/freedesktop/DBus",
&vtable, data))
rc = TRUE;
else
ErrorF("[config/hal] cannot register object path.\n");
}
else {
ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name,
error.message);
ErrorF("[config/hal] cannot detect a HAL startup.\n");
}
dbus_error_free(&error);
return rc;
}
static void
connect_hook(DBusConnection * connection, void *data)
{
struct config_hal_info *info = data;
if (listen_for_startup(connection, data) &&
connect_and_register(connection, info))
dbus_connection_unregister_object_path(connection,
"/org/freedesktop/DBus");
return;
}
static struct config_hal_info hal_info;
static struct dbus_core_hook hook = {
.connect = connect_hook,
.disconnect = disconnect_hook,
.data = &hal_info,
};
int
config_hal_init(void)
{
memset(&hal_info, 0, sizeof(hal_info));
hal_info.system_bus = NULL;
hal_info.hal_ctx = NULL;
if (!dbus_core_add_hook(&hook)) {
LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n");
return 0;
}
/* verbose message */
LogMessageVerb(X_INFO, 7, "config/hal: initialized\n");
return 1;
}
void
config_hal_fini(void)
{
dbus_core_remove_hook(&hook);
}

35
config/meson.build Normal file
View File

@ -0,0 +1,35 @@
srcs_config = [
'config.c',
]
config_dep = [common_dep]
if build_dbus
srcs_config += 'dbus-core.c'
config_dep += dbus_dep
endif
if build_hal
srcs_config += 'hal.c'
config_dep += hal_dep
endif
if build_udev
srcs_config += 'udev.c'
config_dep += udev_dep
endif
if host_machine.system() == 'openbsd'
srcs_config += 'wscons.c'
endif
if build_xorg
install_data('10-quirks.conf',
install_dir: join_paths(get_option('datadir'), 'X11/xorg.conf.d'))
endif
libxserver_config = static_library('libxserver_config',
srcs_config,
include_directories: inc,
dependencies: config_dep,
)

610
config/udev.c Normal file
View File

@ -0,0 +1,610 @@
/*
* Copyright © 2009 Julien Cristau
*
* 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.
*
* Author: Julien Cristau <jcristau@debian.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <libudev.h>
#include <ctype.h>
#include <unistd.h>
#include "input.h"
#include "inputstr.h"
#include "hotplug.h"
#include "config-backends.h"
#include "os.h"
#include "globals.h"
#include "systemd-logind.h"
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#define UDEV_XKB_PROP_KEY "xkb"
#define LOG_PROPERTY(path, prop, val) \
LogMessageVerb(X_INFO, 10, \
"config/udev: getting property %s on %s " \
"returned \"%s\"\n", \
(prop), (path), (val) ? (val) : "(null)")
#define LOG_SYSATTR(path, attr, val) \
LogMessageVerb(X_INFO, 10, \
"config/udev: getting attribute %s on %s " \
"returned \"%s\"\n", \
(attr), (path), (val) ? (val) : "(null)")
static struct udev_monitor *udev_monitor;
#ifdef CONFIG_UDEV_KMS
static void
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
int major, int minor,
config_odev_probe_proc_ptr probe_callback);
#endif
static char itoa_buf[16];
static const char *itoa(int i)
{
snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
return itoa_buf;
}
static Bool
check_seat(struct udev_device *udev_device)
{
const char *dev_seat;
dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
if (!dev_seat)
dev_seat = "seat0";
if (SeatId && strcmp(dev_seat, SeatId))
return FALSE;
if (!SeatId && strcmp(dev_seat, "seat0"))
return FALSE;
return TRUE;
}
static void
device_added(struct udev_device *udev_device)
{
const char *path, *name = NULL;
char *config_info = NULL;
const char *syspath;
const char *tags_prop;
const char *key, *value, *tmp;
#ifdef CONFIG_UDEV_KMS
const char *subsys = NULL;
#endif
InputOption *input_options;
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
struct udev_list_entry *set, *entry;
struct udev_device *parent;
int rc;
dev_t devnum;
path = udev_device_get_devnode(udev_device);
syspath = udev_device_get_syspath(udev_device);
if (!path || !syspath)
return;
if (!check_seat(udev_device))
return;
devnum = udev_device_get_devnum(udev_device);
#ifdef CONFIG_UDEV_KMS
subsys = udev_device_get_subsystem(udev_device);
if (subsys && !strcmp(subsys, "drm")) {
const char *sysname = udev_device_get_sysname(udev_device);
if (strncmp(sysname, "card", 4) != 0)
return;
/* Check for devices already added through xf86platformProbe() */
if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
return;
LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
minor(devnum), NewGPUDeviceRequest);
return;
}
#endif
value = udev_device_get_property_value(udev_device, "ID_INPUT");
if (!value || !strcmp(value, "0")) {
LogMessageVerb(X_INFO, 10,
"config/udev: ignoring device %s without "
"property ID_INPUT set\n", path);
return;
}
input_options = input_option_new(NULL, "_source", "server/udev");
if (!input_options)
return;
parent = udev_device_get_parent(udev_device);
if (parent) {
const char *ppath = udev_device_get_devnode(parent);
const char *product = udev_device_get_property_value(parent, "PRODUCT");
const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
unsigned int usb_vendor, usb_model;
name = udev_device_get_sysattr_value(parent, "name");
LOG_SYSATTR(ppath, "name", name);
if (!name) {
name = udev_device_get_property_value(parent, "NAME");
LOG_PROPERTY(ppath, "NAME", name);
}
/* construct USB ID in lowercase hex - "0000:ffff" */
if (product &&
sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
char *usb_id;
if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
== -1)
usb_id = NULL;
else
LOG_PROPERTY(ppath, "PRODUCT", product);
attrs.usb_id = usb_id;
}
while (!pnp_id && (parent = udev_device_get_parent(parent))) {
pnp_id = udev_device_get_sysattr_value(parent, "id");
if (!pnp_id)
continue;
attrs.pnp_id = strdup(pnp_id);
ppath = udev_device_get_devnode(parent);
LOG_SYSATTR(ppath, "id", pnp_id);
}
}
if (!name)
name = "(unnamed)";
else
attrs.product = strdup(name);
input_options = input_option_new(input_options, "name", name);
input_options = input_option_new(input_options, "path", path);
input_options = input_option_new(input_options, "device", path);
input_options = input_option_new(input_options, "major", itoa(major(devnum)));
input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
if (path)
attrs.device = strdup(path);
tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
attrs.tags = xstrtokenize(tags_prop, ",");
if (asprintf(&config_info, "udev:%s", syspath) == -1) {
config_info = NULL;
goto unwind;
}
if (device_is_duplicate(config_info)) {
LogMessage(X_WARNING, "config/udev: device %s already added. "
"Ignoring.\n", name);
goto unwind;
}
set = udev_device_get_properties_list_entry(udev_device);
udev_list_entry_foreach(entry, set) {
key = udev_list_entry_get_name(entry);
if (!key)
continue;
value = udev_list_entry_get_value(entry);
if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
LOG_PROPERTY(path, key, value);
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
if (!strcasecmp(tmp, "rules"))
input_options =
input_option_new(input_options, "xkb_rules", value);
else if (!strcasecmp(tmp, "layout"))
input_options =
input_option_new(input_options, "xkb_layout", value);
else if (!strcasecmp(tmp, "variant"))
input_options =
input_option_new(input_options, "xkb_variant", value);
else if (!strcasecmp(tmp, "model"))
input_options =
input_option_new(input_options, "xkb_model", value);
else if (!strcasecmp(tmp, "options"))
input_options =
input_option_new(input_options, "xkb_options", value);
}
else if (!strcmp(key, "ID_VENDOR")) {
LOG_PROPERTY(path, key, value);
attrs.vendor = strdup(value);
} else if (!strncmp(key, "ID_INPUT_", 9)) {
const struct pfmap {
const char *property;
unsigned int flag;
} map[] = {
{ "ID_INPUT_KEY", ATTR_KEY },
{ "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
{ "ID_INPUT_MOUSE", ATTR_POINTER },
{ "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
{ "ID_INPUT_TABLET", ATTR_TABLET },
{ "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
{ "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
{ "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
{ NULL, 0 },
};
/* Anything but the literal string "0" is considered a
* boolean true. The empty string isn't a thing with udev
* properties anyway */
if (value && strcmp(value, "0")) {
const struct pfmap *m = map;
while (m->property != NULL) {
if (!strcmp(m->property, key)) {
LOG_PROPERTY(path, key, value);
attrs.flags |= m->flag;
}
m++;
}
}
}
}
input_options = input_option_new(input_options, "config_info", config_info);
/* Default setting needed for non-seat0 seats */
if (ServerIsNotSeat0())
input_options = input_option_new(input_options, "GrabDevice", "on");
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
name, path);
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
unwind:
free(config_info);
input_option_free_list(&input_options);
free(attrs.usb_id);
free(attrs.pnp_id);
free(attrs.product);
free(attrs.device);
free(attrs.vendor);
if (attrs.tags) {
char **tag = attrs.tags;
while (*tag) {
free(*tag);
tag++;
}
free(attrs.tags);
}
return;
}
static void
device_removed(struct udev_device *device)
{
char *value;
const char *syspath = udev_device_get_syspath(device);
#ifdef CONFIG_UDEV_KMS
const char *subsys = udev_device_get_subsystem(device);
if (subsys && !strcmp(subsys, "drm")) {
const char *sysname = udev_device_get_sysname(device);
const char *path = udev_device_get_devnode(device);
dev_t devnum = udev_device_get_devnum(device);
if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
return;
LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
syspath, path);
config_udev_odev_setup_attribs(device, path, syspath, major(devnum),
minor(devnum), DeleteGPUDeviceRequest);
/* Retry vtenter after a drm node removal */
systemd_logind_vtenter();
return;
}
#endif
if (asprintf(&value, "udev:%s", syspath) == -1)
return;
remove_devices("udev", value);
free(value);
}
static void
socket_handler(int fd, int ready, void *data)
{
struct udev_device *udev_device;
const char *action;
input_lock();
udev_device = udev_monitor_receive_device(udev_monitor);
if (!udev_device) {
input_unlock();
return;
}
action = udev_device_get_action(udev_device);
if (action) {
if (!strcmp(action, "add")) {
device_removed(udev_device);
device_added(udev_device);
} else if (!strcmp(action, "change")) {
/* ignore change for the drm devices */
const char *subsys = udev_device_get_subsystem(udev_device);
if (subsys && strcmp(subsys, "drm")) {
device_removed(udev_device);
device_added(udev_device);
}
}
else if (!strcmp(action, "remove"))
device_removed(udev_device);
}
udev_device_unref(udev_device);
input_unlock();
}
int
config_udev_pre_init(void)
{
struct udev *udev;
udev = udev_new();
if (!udev)
return 0;
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
if (!udev_monitor)
return 0;
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
NULL);
/* For Wacom serial devices */
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
#ifdef CONFIG_UDEV_KMS
/* For output GPU devices */
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
#endif
#ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
#endif
if (udev_monitor_enable_receiving(udev_monitor)) {
ErrorF("config/udev: failed to bind the udev monitor\n");
return 0;
}
return 1;
}
int
config_udev_init(void)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *device;
udev = udev_monitor_get_udev(udev_monitor);
enumerate = udev_enumerate_new(udev);
if (!enumerate)
return 0;
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_add_match_subsystem(enumerate, "tty");
#ifdef CONFIG_UDEV_KMS
udev_enumerate_add_match_subsystem(enumerate, "drm");
#endif
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_enumerate_add_match_tag(enumerate, SeatId);
#endif
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(device, devices) {
const char *syspath = udev_list_entry_get_name(device);
struct udev_device *udev_device =
udev_device_new_from_syspath(udev, syspath);
/* Device might be gone by the time we try to open it */
if (!udev_device)
continue;
device_added(udev_device);
udev_device_unref(udev_device);
}
udev_enumerate_unref(enumerate);
SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
return 1;
}
void
config_udev_fini(void)
{
struct udev *udev;
if (!udev_monitor)
return;
udev = udev_monitor_get_udev(udev_monitor);
RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
udev_monitor_unref(udev_monitor);
udev_monitor = NULL;
udev_unref(udev);
}
#ifdef CONFIG_UDEV_KMS
/* Find the last occurrence of the needle in haystack */
static char *strrstr(const char *haystack, const char *needle)
{
char *prev, *last, *tmp;
prev = strstr(haystack, needle);
if (!prev)
return NULL;
last = prev;
tmp = prev + 1;
while (tmp) {
last = strstr(tmp, needle);
if (!last)
return prev;
else {
prev = last;
tmp = prev + 1;
}
}
return last;
}
/* For certain devices udev does not create ID_PATH entry (which is presumably a bug
* in udev). We work around that by implementing a minimal ID_PATH calculator
* ourselves along the same logic that udev uses. This works only for the case of
* a PCI device being directly connected to a PCI bus, but it will cover most end
* users with e.g. a new laptop which only has beta hardware driver support.
* See https://gitlab.freedesktop.org/xorg/xserver/-/issues/993 */
static char*
config_udev_get_fallback_bus_id(struct udev_device *udev_device)
{
const char *sysname;
char *busid;
udev_device = udev_device_get_parent(udev_device);
if (udev_device == NULL)
return NULL;
if (strcmp(udev_device_get_subsystem(udev_device), "pci") != 0)
return NULL;
sysname = udev_device_get_sysname(udev_device);
busid = XNFalloc(strlen(sysname) + 5);
busid[0] = '\0';
strcat(busid, "pci:");
strcat(busid, sysname);
return busid;
}
static void
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
int major, int minor,
config_odev_probe_proc_ptr probe_callback)
{
struct OdevAttributes *attribs = config_odev_allocate_attributes();
const char *value, *str;
attribs->path = XNFstrdup(path);
attribs->syspath = XNFstrdup(syspath);
attribs->major = major;
attribs->minor = minor;
value = udev_device_get_property_value(udev_device, "ID_PATH");
if (value && (str = strrstr(value, "pci-"))) {
value = str;
if ((str = strstr(value, "usb-")))
value = str;
attribs->busid = XNFstrdup(value);
attribs->busid[3] = ':';
}
if (!value)
attribs->busid = config_udev_get_fallback_bus_id(udev_device);
/* ownership of attribs is passed to probe layer */
probe_callback(attribs);
}
void
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *device;
udev = udev_monitor_get_udev(udev_monitor);
enumerate = udev_enumerate_new(udev);
if (!enumerate)
return;
udev_enumerate_add_match_subsystem(enumerate, "drm");
udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
if (ServerIsNotSeat0())
udev_enumerate_add_match_tag(enumerate, SeatId);
#endif
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(device, devices) {
const char *syspath = udev_list_entry_get_name(device);
struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
const char *path = udev_device_get_devnode(udev_device);
const char *sysname = udev_device_get_sysname(udev_device);
dev_t devnum = udev_device_get_devnum(udev_device);
const char *subsys = udev_device_get_subsystem(udev_device);
if (!path || !syspath || !subsys)
goto no_probe;
else if (strcmp(subsys, "drm") != 0)
goto no_probe;
else if (strncmp(sysname, "card", 4) != 0)
goto no_probe;
else if (!check_seat(udev_device))
goto no_probe;
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
minor(devnum), probe_callback);
no_probe:
udev_device_unref(udev_device);
}
udev_enumerate_unref(enumerate);
return;
}
#endif

262
config/wscons.c Normal file
View File

@ -0,0 +1,262 @@
/*
* Copyright (c) 2011 Matthieu Herrb
*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsksymdef.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "input.h"
#include "inputstr.h"
#include "os.h"
#include "config-backends.h"
#define WSCONS_KBD_DEVICE "/dev/wskbd"
#define WSCONS_MOUSE_PREFIX "/dev/wsmouse"
#define KB_OVRENC \
{ KB_UK, "gb" }, \
{ KB_SV, "se" }, \
{ KB_SG, "ch" }, \
{ KB_SF, "ch" }, \
{ KB_LA, "latam" }, \
{ KB_CF, "ca" }
struct nameint {
int val;
char *name;
} kbdenc[] = {
KB_OVRENC,
KB_ENCTAB,
{0}
};
struct nameint kbdvar[] = {
{KB_NODEAD | KB_SG, "de_nodeadkeys"},
{KB_NODEAD | KB_SF, "fr_nodeadkeys"},
{KB_SF, "fr"},
{KB_DVORAK | KB_CF, "fr-dvorak"},
{KB_DVORAK | KB_FR, "bepo"},
{KB_DVORAK, "dvorak"},
{KB_CF, "fr-legacy"},
{KB_NODEAD, "nodeadkeys"},
{0}
};
struct nameint kbdopt[] = {
{KB_SWAPCTRLCAPS, "ctrl:swapcaps"},
{0}
};
struct nameint kbdmodel[] = {
{WSKBD_TYPE_ZAURUS, "zaurus"},
{0}
};
static void
wscons_add_keyboard(void)
{
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
InputOption *input_options = NULL;
char *config_info = NULL;
int fd, i, rc;
unsigned int type;
kbd_t wsenc = 0;
/* Find keyboard configuration */
fd = open(WSCONS_KBD_DEVICE, O_RDWR | O_NONBLOCK | O_EXCL);
if (fd == -1) {
LogMessage(X_ERROR, "wskbd: open %s: %s\n",
WSCONS_KBD_DEVICE, strerror(errno));
return;
}
if (ioctl(fd, WSKBDIO_GETENCODING, &wsenc) == -1) {
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GETENCODING) "
"failed: %s\n", strerror(errno));
close(fd);
return;
}
if (ioctl(fd, WSKBDIO_GTYPE, &type) == -1) {
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GTYPE) "
"failed: %s\n", strerror(errno));
close(fd);
return;
}
close(fd);
input_options = input_option_new(input_options, "_source", "server/wscons");
if (input_options == NULL)
return;
LogMessage(X_INFO, "config/wscons: checking input device %s\n",
WSCONS_KBD_DEVICE);
input_options = input_option_new(input_options, "name", WSCONS_KBD_DEVICE);
input_options = input_option_new(input_options, "driver", "kbd");
config_info = Xprintf("wscons:%s", WSCONS_KBD_DEVICE);
if (!config_info)
goto unwind;
if (KB_ENCODING(wsenc) == KB_USER) {
/* Ignore wscons "user" layout */
LogMessageVerb(X_INFO, 3, "wskbd: ignoring \"user\" layout\n");
goto kbd_config_done;
}
for (i = 0; kbdenc[i].val; i++)
if (KB_ENCODING(wsenc) == kbdenc[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using layout %s\n",
kbdenc[i].name);
input_options = input_option_new(input_options,
"xkb_layout", kbdenc[i].name);
break;
}
for (i = 0; kbdvar[i].val; i++)
if (wsenc == kbdvar[i].val || KB_VARIANT(wsenc) == kbdvar[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using variant %s\n",
kbdvar[i].name);
input_options = input_option_new(input_options,
"xkb_variant", kbdvar[i].name);
break;
}
for (i = 0; kbdopt[i].val; i++)
if (KB_VARIANT(wsenc) == kbdopt[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using option %s\n",
kbdopt[i].name);
input_options = input_option_new(input_options,
"xkb_options", kbdopt[i].name);
break;
}
for (i = 0; kbdmodel[i].val; i++)
if (type == kbdmodel[i].val) {
LogMessageVerb(X_INFO, 3, "wskbd: using model %s\n",
kbdmodel[i].name);
input_options = input_option_new(input_options,
"xkb_model", kbdmodel[i].name);
break;
}
kbd_config_done:
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
for (; dev; dev = dev->next) {
free(dev->config_info);
dev->config_info = strdup(config_info);
}
unwind:
input_option_free_list(&input_options);
}
static void
wscons_add_pointer(const char *path, const char *driver, int flags)
{
InputAttributes attrs = { };
DeviceIntPtr dev = NULL;
InputOption *input_options = NULL;
char *config_info = NULL;
int rc;
config_info = Xprintf("wscons:%s", path);
if (!config_info)
return;
input_options = input_option_new(input_options, "_source", "server/wscons");
if (input_options == NULL)
return;
input_options = input_option_new(input_options, "name", strdup(path));
input_options = input_option_new(input_options, "driver", strdup(driver));
input_options = input_option_new(input_options, "device", strdup(path));
LogMessage(X_INFO, "config/wscons: checking input device %s\n", path);
attrs.flags |= flags;
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
if (rc != Success)
goto unwind;
for (; dev; dev = dev->next) {
free(dev->config_info);
dev->config_info = strdup(config_info);
}
unwind:
input_option_free_list(&input_options);
}
static void
wscons_add_pointers(void)
{
char devname[256];
int fd, i, wsmouse_type;
/* Check pointing devices */
for (i = 0; i < 4; i++) {
snprintf(devname, sizeof(devname), "%s%d", WSCONS_MOUSE_PREFIX, i);
LogMessageVerb(X_INFO, 10, "wsmouse: checking %s\n", devname);
fd = open_device(devnamem O_RDWR | O_NONBLOCK | O_EXCL);
if (fd == -1) {
LogMessageVerb(X_WARNING, 10, "%s: %s\n", devname, strerror(errno));
continue;
}
if (ioctl(fd, WSMOUSEIO_GTYPE, &wsmouse_type) != 0) {
LogMessageVerb(X_WARNING, 10,
"%s: WSMOUSEIO_GTYPE failed\n", devname);
close(fd);
continue;
}
close(fd);
switch (wsmouse_type) {
case WSMOUSE_TYPE_SYNAPTICS:
wscons_add_pointer(devname, "synaptics", ATTR_TOUCHPAD);
break;
case WSMOUSE_TYPE_TPANEL:
wscons_add_pointer(devname, "ws", ATTR_TOUCHSCREEN);
break;
default:
break;
}
}
/* Add a default entry catching all other mux elements as "mouse" */
wscons_add_pointer(WSCONS_MOUSE_PREFIX, "mouse", ATTR_POINTER);
}
int
config_wscons_init(void)
{
wscons_add_keyboard();
wscons_add_pointers();
return 1;
}
void
config_wscons_fini(void)
{
/* Not much to do ? */
}

93
config/x11-input.fdi Normal file
View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<deviceinfo version="0.2">
<device>
<!-- The way this works:
Match against some input device (see the HAL specification for more
information), and then merge in keys, which you can use to specify
the configuration similar to the way you would in xorg.conf. You will
need to restart HAL after making changes. If you are having issues,
starting X with the -logverbose 7 flag may yield useful information.
Keys Supported:
Key "input.x11_driver" (string)
This specifies the driver to use. You MUST specify this option,
or a driver will not be loaded and the rest will be ignored by
Xorg
Key "input.x11_options.<option name>" (string)
This allows you to specify arbitrary options to pass to the driver.
Anything you would normally specify in xorg.conf goes here. So, for
option "Mode" in xorg.conf, you would specify the key name of
"input.x11_options.Mode".
Do not specify "input.x11_options.Device" since "input.device"
will be used automatically.
You MUST specify all options as strings, otherwise the server will
ignore them.
Legacy Keys
"input.xkb.rules"
"input.xkb.model"
"input.xkb.layout"
"input.xkb.variant"
"input.xkb.options"
These keys are deprecated. Use these instead:
"input.x11_options.XkbRules"
"input.x11_options.XkbModel"
"input.x11_options.XkbLayout"
"input.x11_options.XkbVariant"
"input.x11_options.XkbOptions"
See the evdev documentation for more information.
FIXME: Support tablets too.
TODO: I think its fixed, can't test
-->
<match key="info.capabilities" contains="input.mouse">
<merge key="input.x11_driver" type="string">mouse</merge>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="Linux">
<merge key="input.x11_driver" type="string">evdev</merge>
</match>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="SunOS">
<match key="input.device" contains="usb">
<merge key="input.x11_options.StreamsModule" type="string">usbms</merge>
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
</match>
</match>
</match>
<match key="info.capabilities" contains="input.keys">
<merge key="input.x11_options.XkbRules" type="string">base</merge>
<!-- If we're using Linux, we use evdev by default (falling back to
kbd otherwise). -->
<merge key="input.x11_driver" type="string">kbd</merge>
<merge key="input.x11_options.XkbModel" type="string">pc105</merge>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="Linux">
<merge key="input.x11_driver" type="string">evdev</merge>
<merge key="input.x11_options.XkbModel" type="string">evdev</merge>
</match>
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
string="SunOS">
<match key="input.device" contains="usb">
<merge key="input.x11_options.StreamsModule" type="string">usbkbm</merge>
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
</match>
</match>
<merge key="input.x11_options.XkbLayout" type="string">us</merge>
<merge key="input.x11_options.XkbVariant" type="string" />
</match>
</device>
</deviceinfo>

2529
configure.ac Normal file

File diff suppressed because it is too large Load Diff

7
damageext/Makefile.am Normal file
View File

@ -0,0 +1,7 @@
noinst_LTLIBRARIES = libdamageext.la
AM_CFLAGS = $(DIX_CFLAGS)
libdamageext_la_SOURCES = \
damageext.c \
damageextint.h

View File

@ -561,7 +561,11 @@ static int _X_COLD
SProcDamageDispatch(ClientPtr client)
{
REQUEST(xDamageReq);
if (stuff->damageReqType >= XDamageNumberRequests)
DamageClientPtr pDamageClient = GetDamageClient(client);
if (pDamageClient->major_version >= ARRAY_SIZE(version_requests))
return BadRequest;
if (stuff->damageReqType > version_requests[pDamageClient->major_version])
return BadRequest;
return (*SProcDamageVector[stuff->damageReqType]) (client);
}

12
dbe/Makefile.am Normal file
View File

@ -0,0 +1,12 @@
noinst_LTLIBRARIES = libdbe.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = dbestruct.h
endif
libdbe_la_SOURCES = \
dbe.c \
midbe.c \
midbe.h

View File

@ -12,3 +12,7 @@ libxserver_dbe = static_library('libxserver_dbe',
include_directories: inc,
dependencies: common_dep,
)
if build_xorg
install_data(hdrs_dbe, install_dir: xorgsdkdir)
endif

62
dix/Makefile.am Normal file
View File

@ -0,0 +1,62 @@
noinst_LTLIBRARIES = libdix.la libmain.la
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CFLAGS = $(DIX_CFLAGS)
libmain_la_SOURCES = \
stubmain.c
libdix_la_SOURCES = \
atom.c \
colormap.c \
cursor.c \
devices.c \
dispatch.c \
dispatch.h \
dixfonts.c \
main.c \
dixutils.c \
enterleave.c \
enterleave.h \
events.c \
eventconvert.c \
extension.c \
gc.c \
getevents.c \
gestures.c \
globals.c \
glyphcurs.c \
grabs.c \
initatoms.c \
inpututils.c \
pixmap.c \
privates.c \
property.c \
ptrveloc.c \
region.c \
registry.c \
resource.c \
selection.c \
swaprep.c \
swapreq.c \
tables.c \
touch.c \
window.c
EXTRA_DIST = buildatoms BuiltInAtoms
# Install list of protocol names
miscconfigdir = $(SERVER_MISC_CONFIG_PATH)
dist_miscconfig_DATA = protocol.txt
if SPECIAL_DTRACE_OBJECTS
# Generate dtrace object code for probes in libdix
dtrace-dix.o: $(top_srcdir)/include/Xserver.d libdix.la
$(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/include/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
noinst_PROGRAMS = dix.O
dix_O_SOURCES =
dix.O: dtrace-dix.o libdix.la
$(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
endif

View File

@ -458,6 +458,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
return FALSE;
TouchEndPhysicallyActiveTouches(dev);
GestureEndActiveGestures(dev);
ReleaseButtonsAndKeys(dev);
SyncRemoveDeviceIdleTime(dev->idle_counter);
dev->idle_counter = NULL;
@ -1670,6 +1671,32 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
return FALSE;
}
/**
* Sets up gesture capabilities on @device.
*
* @max_touches The maximum number of simultaneous touches, or 0 for unlimited.
*/
Bool
InitGestureClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches)
{
GestureClassPtr g;
BUG_RETURN_VAL(device == NULL, FALSE);
BUG_RETURN_VAL(device->gesture != NULL, FALSE);
g = calloc(1, sizeof(*g));
if (!g)
return FALSE;
g->sourceid = device->id;
g->max_touches = max_touches;
GestureInitGestureInfo(&g->gesture);
device->gesture = g;
return TRUE;
}
/*
* Check if the given buffer contains elements between low (inclusive) and
* high (inclusive) only.

View File

@ -128,6 +128,7 @@ int ProcInitialConnection();
#include "inputstr.h"
#include "xkbsrv.h"
#include "client.h"
#include "xfixesint.h"
#ifdef XSERVER_DTRACE
#include "registry.h"
@ -164,6 +165,7 @@ static int nextFreeClientID; /* always MIN free client ID */
static int nClients; /* number of authorized clients */
CallbackListPtr ClientStateCallback;
OsTimerPtr dispatchExceptionTimer;
/* dispatchException & isItTimeToYield must be declared volatile since they
* are modified by signal handlers - otherwise optimizer may assume it doesn't
@ -399,6 +401,58 @@ SmartScheduleClient(void)
return best;
}
static CARD32
DispatchExceptionCallback(OsTimerPtr timer, CARD32 time, void *arg)
{
dispatchException |= dispatchExceptionAtReset;
/* Don't re-arm the timer */
return 0;
}
static void
CancelDispatchExceptionTimer(void)
{
TimerFree(dispatchExceptionTimer);
dispatchExceptionTimer = NULL;
}
static void
SetDispatchExceptionTimer(void)
{
/* The timer delay is only for terminate, not reset */
if (!(dispatchExceptionAtReset & DE_TERMINATE)) {
dispatchException |= dispatchExceptionAtReset;
return;
}
CancelDispatchExceptionTimer();
if (terminateDelay == 0)
dispatchException |= dispatchExceptionAtReset;
else
dispatchExceptionTimer = TimerSet(dispatchExceptionTimer,
0, terminateDelay * 1000 /* msec */,
&DispatchExceptionCallback,
NULL);
}
static Bool
ShouldDisconnectRemainingClients(void)
{
int i;
for (i = 1; i < currentMaxClients; i++) {
if (clients[i]) {
if (!XFixesShouldDisconnectClient(clients[i]))
return FALSE;
}
}
/* All remaining clients can be safely ignored */
return TRUE;
}
void
EnableLimitedSchedulingLatency(void)
{
@ -3419,6 +3473,7 @@ ProcNoOperation(ClientPtr client)
*********************/
char dispatchExceptionAtReset = DE_RESET;
int terminateDelay = 0;
void
CloseDownClient(ClientPtr client)
@ -3475,7 +3530,7 @@ CloseDownClient(ClientPtr client)
if (really_close_down) {
if (client->clientState == ClientStateRunning && nClients == 0)
dispatchException |= dispatchExceptionAtReset;
SetDispatchExceptionTimer();
client->clientState = ClientStateGone;
if (ClientStateCallback) {
@ -3487,6 +3542,7 @@ CloseDownClient(ClientPtr client)
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
}
TouchListenerGone(client->clientAsMask);
GestureListenerGone(client->clientAsMask);
FreeClientResources(client);
/* Disable client ID tracking. This must be done after
* ClientStateCallback. */
@ -3503,6 +3559,9 @@ CloseDownClient(ClientPtr client)
while (!clients[currentMaxClients - 1])
currentMaxClients--;
}
if (ShouldDisconnectRemainingClients())
SetDispatchExceptionTimer();
}
static void
@ -3704,6 +3763,7 @@ SendConnSetup(ClientPtr client, const char *reason)
clientinfo.setup = (xConnSetup *) lConnectionInfo;
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
}
CancelDispatchExceptionTimer();
return Success;
}

View File

@ -56,7 +56,7 @@
*
* For a full description of the focus in/out model from a window's
* perspective, see
* http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
* https://lists.freedesktop.org/archives/xorg/2008-December/041684.html
*
* Additional notes:
* - The core protocol spec says that "In a LeaveNotify event, if a child of the

View File

@ -59,6 +59,8 @@ static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
static int eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi);
static int eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi);
/* Do not use, read comments below */
BOOL EventIsKeyRepeat(xEvent *event);
@ -163,6 +165,12 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ret = BadMatch;
break;
default:
@ -221,6 +229,12 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
*count = 0;
*xi = NULL;
return BadMatch;
@ -285,6 +299,14 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
case ET_BarrierHit:
case ET_BarrierLeave:
return eventToBarrierEvent(&ev->barrier_event, xi);
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return eventToGesturePinchEvent(&ev->gesture_event, xi);
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return eventToGestureSwipeEvent(&ev->gesture_event, xi);
default:
break;
}
@ -816,6 +838,88 @@ eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
return Success;
}
int
eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGesturePinchEvent);
xXIGesturePinchEvent *xpe;
*xi = calloc(1, len);
xpe = (xXIGesturePinchEvent *) * xi;
xpe->type = GenericEvent;
xpe->extension = IReqCode;
xpe->evtype = GetXI2Type(ev->type);
xpe->time = ev->time;
xpe->length = bytes_to_int32(len - sizeof(xEvent));
xpe->detail = ev->num_touches;
xpe->root = ev->root;
xpe->deviceid = ev->deviceid;
xpe->sourceid = ev->sourceid;
xpe->root_x = double_to_fp1616(ev->root_x);
xpe->root_y = double_to_fp1616(ev->root_y);
xpe->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGesturePinchEventCancelled : 0;
xpe->delta_x = double_to_fp1616(ev->delta_x);
xpe->delta_y = double_to_fp1616(ev->delta_y);
xpe->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xpe->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xpe->scale = double_to_fp1616(ev->scale);
xpe->delta_angle = double_to_fp1616(ev->delta_angle);
xpe->mods.base_mods = ev->mods.base;
xpe->mods.latched_mods = ev->mods.latched;
xpe->mods.locked_mods = ev->mods.locked;
xpe->mods.effective_mods = ev->mods.effective;
xpe->group.base_group = ev->group.base;
xpe->group.latched_group = ev->group.latched;
xpe->group.locked_group = ev->group.locked;
xpe->group.effective_group = ev->group.effective;
return Success;
}
int
eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGestureSwipeEvent);
xXIGestureSwipeEvent *xde;
*xi = calloc(1, len);
xde = (xXIGestureSwipeEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
xde->evtype = GetXI2Type(ev->type);
xde->time = ev->time;
xde->length = bytes_to_int32(len - sizeof(xEvent));
xde->detail = ev->num_touches;
xde->root = ev->root;
xde->deviceid = ev->deviceid;
xde->sourceid = ev->sourceid;
xde->root_x = double_to_fp1616(ev->root_x);
xde->root_y = double_to_fp1616(ev->root_y);
xde->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGestureSwipeEventCancelled : 0;
xde->delta_x = double_to_fp1616(ev->delta_x);
xde->delta_y = double_to_fp1616(ev->delta_y);
xde->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xde->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xde->mods.base_mods = ev->mods.base;
xde->mods.latched_mods = ev->mods.latched;
xde->mods.locked_mods = ev->mods.locked;
xde->mods.effective_mods = ev->mods.effective;
xde->group.base_group = ev->group.base;
xde->group.latched_group = ev->group.latched;
xde->group.locked_group = ev->group.locked;
xde->group.effective_group = ev->group.effective;
return Success;
}
/**
* Return the corresponding core type for the given event or 0 if no core
* equivalent exists.
@ -969,8 +1073,68 @@ GetXI2Type(enum EventType type)
case ET_BarrierLeave:
xi2type = XI_BarrierLeave;
break;
case ET_GesturePinchBegin:
xi2type = XI_GesturePinchBegin;
break;
case ET_GesturePinchUpdate:
xi2type = XI_GesturePinchUpdate;
break;
case ET_GesturePinchEnd:
xi2type = XI_GesturePinchEnd;
break;
case ET_GestureSwipeBegin:
xi2type = XI_GestureSwipeBegin;
break;
case ET_GestureSwipeUpdate:
xi2type = XI_GestureSwipeUpdate;
break;
case ET_GestureSwipeEnd:
xi2type = XI_GestureSwipeEnd;
break;
default:
break;
}
return xi2type;
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}Begin.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToBegin(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchBegin;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeBegin;
default:
return 0;
}
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}End.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToEnd(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchEnd;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeEnd;
default:
return 0;
}
}

View File

@ -1328,6 +1328,15 @@ ComputeFreezes(void)
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
}
else if (IsGestureEvent(event)) {
GestureInfoPtr gi =
GestureFindActiveByEventType(replayDev, event->any.type);
if (gi) {
GestureEmitGestureEndToOwner(replayDev, gi);
GestureEndGesture(gi);
}
ProcessGestureEvent(event, replayDev);
}
else {
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
event->device_event.root_x,
@ -1480,16 +1489,28 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
if (ti->active &&
CLIENT_BITS(listener->listener) == grab->resource) {
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) {
if (listener->type == TOUCH_LISTENER_REGULAR &&
listener->state != TOUCH_LISTENER_AWAITING_BEGIN &&
listener->state != TOUCH_LISTENER_HAS_END) {
/* if the listener already got any events relating to the touch, we must send
a touch end because the grab overrides the previous listener and won't
itself send any touch events.
*/
TouchEmitTouchEnd(mouse, ti, 0, listener->listener);
}
listener->type = TOUCH_LISTENER_POINTER_GRAB;
} else {
listener->type = TOUCH_LISTENER_GRAB;
}
listener->listener = grab->resource;
listener->level = grab->grabtype;
listener->state = TOUCH_LISTENER_IS_OWNER;
listener->window = grab->window;
listener->state = TOUCH_LISTENER_IS_OWNER;
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
listener->type = TOUCH_LISTENER_POINTER_GRAB;
else
listener->type = TOUCH_LISTENER_GRAB;
if (listener->grab)
FreeGrab(listener->grab);
listener->grab = AllocGrab(grab);
@ -1497,6 +1518,46 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
}
}
/**
* Update gesture records when an explicit grab is activated. Any gestures owned
* by the grabbing client are updated so the listener state reflects the new
* grab.
*/
static void
UpdateGesturesForGrab(DeviceIntPtr mouse)
{
if (!mouse->gesture || mouse->deviceGrab.fromPassiveGrab)
return;
GestureInfoPtr gi = &mouse->gesture->gesture;
GestureListener *listener = &gi->listener;
GrabPtr grab = mouse->deviceGrab.grab;
if (gi->active && CLIENT_BITS(listener->listener) == grab->resource) {
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, GetXI2Type(gi->type))) {
if (listener->type == GESTURE_LISTENER_REGULAR) {
/* if the listener already got any events relating to the gesture, we must send
a gesture end because the grab overrides the previous listener and won't
itself send any gesture events.
*/
GestureEmitGestureEndToOwner(mouse, gi);
}
listener->type = GESTURE_LISTENER_NONGESTURE_GRAB;
} else {
listener->type = GESTURE_LISTENER_GRAB;
}
listener->listener = grab->resource;
listener->window = grab->window;
if (listener->grab)
FreeGrab(listener->grab);
listener->grab = AllocGrab(grab);
}
}
/**
* Activate a pointer grab on the given device. A pointer grab will cause all
* core pointer events of this device to be delivered to the grabbing client only.
@ -1547,6 +1608,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
PostNewCursor(mouse);
UpdateTouchesForGrab(mouse);
UpdateGesturesForGrab(mouse);
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
(Bool) grab->keyboardMode);
if (oldgrab)
@ -1602,6 +1664,16 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
if (dev->deviceGrab.sync.other == grab)
dev->deviceGrab.sync.other = NullGrab;
}
/* in case of explicit gesture grab, send end event to the grab client */
if (!wasPassive && mouse->gesture) {
GestureInfoPtr gi = &mouse->gesture->gesture;
if (gi->active && GestureResourceIsOwner(gi, grab_resource)) {
GestureEmitGestureEndToOwner(mouse, gi);
GestureEndGesture(gi);
}
}
DoEnterLeaveEvents(mouse, mouse->id, grab->window,
mouse->spriteInfo->sprite->win, NotifyUngrab);
if (grab->confineTo)
@ -2533,6 +2605,44 @@ FixUpXI2DeviceEventFromWindow(SpritePtr pSprite, int evtype,
(pSprite->hot.pScreen == pWin->drawable.pScreen);
}
static void
FixUpXI2PinchEventFromWindow(SpritePtr pSprite, xXIGesturePinchEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
static void
FixUpXI2SwipeEventFromWindow(SpritePtr pSprite, xXIGestureSwipeEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
/**
* Adjust event fields to comply with the window properties.
*
@ -2566,6 +2676,18 @@ FixUpEventFromWindow(SpritePtr pSprite,
case XI_BarrierHit:
case XI_BarrierLeave:
return;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
FixUpXI2PinchEventFromWindow(pSprite,
(xXIGesturePinchEvent*) xE, pWin, child);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
FixUpXI2SwipeEventFromWindow(pSprite,
(xXIGestureSwipeEvent*) xE, pWin, child);
break;
default:
FixUpXI2DeviceEventFromWindow(pSprite, evtype,
(xXIDeviceEvent*) xE, pWin, child);

362
dix/gestures.c Normal file
View File

@ -0,0 +1,362 @@
/*
* Copyright © 2011 Collabra Ltd.
* Copyright © 2011 Red Hat, Inc.
* Copyright © 2020 Povilas Kanapickas <povilas@radix.lt>
*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "inputstr.h"
#include "scrnintstr.h"
#include "dixgrabs.h"
#include "eventstr.h"
#include "exevents.h"
#include "exglobals.h"
#include "inpututils.h"
#include "eventconvert.h"
#include "windowstr.h"
#include "mi.h"
#define GESTURE_HISTORY_SIZE 100
Bool
GestureInitGestureInfo(GestureInfoPtr gi)
{
memset(gi, 0, sizeof(*gi));
gi->sprite.spriteTrace = calloc(32, sizeof(*gi->sprite.spriteTrace));
if (!gi->sprite.spriteTrace) {
return FALSE;
}
gi->sprite.spriteTraceSize = 32;
gi->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
gi->sprite.hot.pScreen = screenInfo.screens[0];
gi->sprite.hotPhys.pScreen = screenInfo.screens[0];
return TRUE;
}
/**
* Given an event type returns the associated gesture event info.
*/
GestureInfoPtr
GestureFindActiveByEventType(DeviceIntPtr dev, int type)
{
GestureClassPtr g = dev->gesture;
enum EventType type_to_expect = GestureTypeToBegin(type);
if (!g || type_to_expect == 0 || !g->gesture.active ||
g->gesture.type != type_to_expect) {
return NULL;
}
return &g->gesture;
}
/**
* Sets up gesture info for a new gesture. Returns NULL on failure.
*/
GestureInfoPtr
GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev)
{
GestureClassPtr g = dev->gesture;
enum EventType gesture_type = GestureTypeToBegin(ev->any.type);
/* Note that we ignore begin events when an existing gesture is active */
if (!g || gesture_type == 0 || g->gesture.active)
return NULL;
g->gesture.type = gesture_type;
if (!GestureBuildSprite(dev, &g->gesture))
return NULL;
g->gesture.active = TRUE;
g->gesture.num_touches = ev->gesture_event.num_touches;
g->gesture.sourceid = ev->gesture_event.sourceid;
g->gesture.has_listener = FALSE;
return &g->gesture;
}
/**
* Releases a gesture: this must only be called after all events
* related to that gesture have been sent and finalised.
*/
void
GestureEndGesture(GestureInfoPtr gi)
{
if (gi->has_listener) {
if (gi->listener.grab) {
FreeGrab(gi->listener.grab);
gi->listener.grab = NULL;
}
gi->listener.listener = 0;
gi->has_listener = FALSE;
}
gi->active = FALSE;
gi->num_touches = 0;
gi->sprite.spriteTraceGood = 0;
}
/**
* Ensure a window trace is present in gi->sprite, constructing one for
* Gesture{Pinch,Swipe}Begin events.
*/
Bool
GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi)
{
SpritePtr sprite = &gi->sprite;
if (!sourcedev->spriteInfo->sprite)
return FALSE;
if (!CopySprite(sourcedev->spriteInfo->sprite, sprite))
return FALSE;
if (sprite->spriteTraceGood <= 0)
return FALSE;
return TRUE;
}
/**
* @returns TRUE if the specified grab or selection is the current owner of
* the gesture sequence.
*/
Bool
GestureResourceIsOwner(GestureInfoPtr gi, XID resource)
{
return (gi->listener.listener == resource);
}
void
GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
enum GestureListenerType type, WindowPtr window, const GrabPtr grab)
{
GrabPtr g = NULL;
BUG_RETURN(gi->has_listener);
/* We need a copy of the grab, not the grab itself since that may be deleted by
* a UngrabButton request and leaves us with a dangling pointer */
if (grab)
g = AllocGrab(grab);
gi->listener.listener = resource;
gi->listener.resource_type = resource_type;
gi->listener.type = type;
gi->listener.window = window;
gi->listener.grab = g;
gi->has_listener = TRUE;
}
static void
GestureAddGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, GrabPtr grab)
{
enum GestureListenerType type;
/* FIXME: owner_events */
if (grab->grabtype == XI2) {
if (xi2mask_isset(grab->xi2mask, dev, XI_GesturePinchBegin) ||
xi2mask_isset(grab->xi2mask, dev, XI_GestureSwipeBegin)) {
type = GESTURE_LISTENER_GRAB;
} else
type = GESTURE_LISTENER_NONGESTURE_GRAB;
}
else if (grab->grabtype == XI || grab->grabtype == CORE) {
type = GESTURE_LISTENER_NONGESTURE_GRAB;
}
else {
BUG_RETURN_MSG(1, "Unsupported grab type\n");
}
/* grab listeners are always RT_NONE since we keep the grab pointer */
GestureAddListener(gi, grab->resource, RT_NONE, type, grab->window, grab);
}
/**
* Add one listener if there is a grab on the given window.
*/
static void
GestureAddPassiveGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
{
Bool activate = FALSE;
Bool check_core = FALSE;
GrabPtr grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core,
activate);
if (!grab)
return;
/* We'll deliver later in gesture-specific code */
ActivateGrabNoDelivery(dev, grab, ev, ev);
GestureAddGrabListener(dev, gi, grab);
}
static void
GestureAddRegularListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
{
InputClients *iclients = NULL;
OtherInputMasks *inputMasks = NULL;
uint16_t evtype = GetXI2Type(ev->any.type);
int mask;
mask = EventIsDeliverable(dev, ev->any.type, win);
if (!mask)
return;
inputMasks = wOtherInputMasks(win);
if (mask & EVENT_XI2_MASK) {
nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
continue;
GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT,
GESTURE_LISTENER_REGULAR, win, NULL);
return;
}
}
}
void
GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
{
int i;
SpritePtr sprite = &gi->sprite;
WindowPtr win;
/* Any current grab will consume all gesture events */
if (dev->deviceGrab.grab) {
GestureAddGrabListener(dev, gi, dev->deviceGrab.grab);
return;
}
/* Find passive grab that would be activated by this event, if any. If we're handling
* ReplayDevice then the search starts from the descendant of the grab window, otherwise
* the search starts at the root window. The search ends at deepest child window. */
i = 0;
if (syncEvents.playingEvents) {
while (i < dev->spriteInfo->sprite->spriteTraceGood) {
if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin)
break;
}
}
for (; i < sprite->spriteTraceGood; i++) {
win = sprite->spriteTrace[i];
GestureAddPassiveGrabListener(dev, gi, win, ev);
if (gi->has_listener)
return;
}
/* Find the first client with an applicable event selection,
* going from deepest child window back up to the root window. */
for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
win = sprite->spriteTrace[i];
GestureAddRegularListener(dev, gi, win, ev);
if (gi->has_listener)
return;
}
}
/* As gesture grabs don't turn into active grabs with their own resources, we
* need to walk all the gestures and remove this grab from listener */
void
GestureListenerGone(XID resource)
{
GestureInfoPtr gi;
DeviceIntPtr dev;
InternalEvent *events = InitEventList(GetMaximumEventsNum());
if (!events)
FatalError("GestureListenerGone: couldn't allocate events\n");
for (dev = inputInfo.devices; dev; dev = dev->next) {
if (!dev->gesture)
continue;
gi = &dev->gesture->gesture;
if (!gi->active)
continue;
if (CLIENT_BITS(gi->listener.listener) == resource)
GestureEndGesture(gi);
}
FreeEventList(events, GetMaximumEventsNum());
}
/**
* End physically active gestures for a device.
*/
void
GestureEndActiveGestures(DeviceIntPtr dev)
{
GestureClassPtr g = dev->gesture;
InternalEvent *eventlist;
if (!g)
return;
eventlist = InitEventList(GetMaximumEventsNum());
input_lock();
mieqProcessInputEvents();
if (g->gesture.active) {
int j;
int type = GetXI2Type(GestureTypeToEnd(g->gesture.type));
int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches,
0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
for (j = 0; j < nevents; j++)
mieqProcessDeviceEvent(dev, eventlist + j, NULL);
}
input_unlock();
FreeEventList(eventlist, GetMaximumEventsNum());
}
/**
* Generate and deliver a Gesture{Pinch,Swipe}End event to the owner.
*
* @param dev The device to deliver the event for.
* @param gi The gesture record to deliver the event for.
*/
void
GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi)
{
InternalEvent event;
/* We're not processing a gesture end for a frozen device */
if (dev->deviceGrab.sync.frozen)
return;
DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis());
InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type),
0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
DeliverGestureEventToOwner(dev, gi, &event);
}

View File

@ -2099,3 +2099,139 @@ PostSyntheticMotion(DeviceIntPtr pDev,
/* FIXME: MD/SD considerations? */
(*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
}
void
InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
int type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
GestureEvent *event = &ievent->gesture_event;
double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
init_gesture_event(event, dev, ms);
screenx = dev->spriteInfo->sprite->hotPhys.x;
screeny = dev->spriteInfo->sprite->hotPhys.y;
event->type = type;
event->root = scr->root->drawable.id;
event->root_x = screenx - scr->x;
event->root_y = screeny - scr->y;
event->num_touches = num_touches;
event->flags = flags;
event->delta_x = delta_x;
event->delta_y = delta_y;
event->delta_unaccel_x = delta_unaccel_x;
event->delta_unaccel_y = delta_unaccel_y;
event->scale = scale;
event->delta_angle = delta_angle;
}
/**
* Get events for a pinch or swipe gesture.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*
* @param[out] events The list of events generated
* @param dev The device to generate the events for
* @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End}
* @prama num_touches The number of touches in the gesture
* @param flags Event flags
* @param delta_x,delta_y accelerated relative motion delta
* @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
* @param scale (valid only to pinch events) absolute scale of a pinch gesture
* @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and
* the current pinch event.
*/
int
GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
uint16_t type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
GestureClassPtr g = dev->gesture;
CARD32 ms = GetTimeInMillis();
enum EventType evtype;
int num_events = 0;
uint32_t evflags = 0;
if (!dev->enabled || !g)
return 0;
if (!IsMaster(dev))
events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT,
&num_events);
switch (type) {
case XI_GesturePinchBegin:
evtype = ET_GesturePinchBegin;
break;
case XI_GesturePinchUpdate:
evtype = ET_GesturePinchUpdate;
break;
case XI_GesturePinchEnd:
evtype = ET_GesturePinchEnd;
if (flags & XIGesturePinchEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
case XI_GestureSwipeBegin:
evtype = ET_GestureSwipeBegin;
break;
case XI_GestureSwipeUpdate:
evtype = ET_GestureSwipeUpdate;
break;
case XI_GestureSwipeEnd:
evtype = ET_GestureSwipeEnd;
if (flags & XIGestureSwipeEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
default:
return 0;
}
InitGestureEvent(events, dev, ms, evtype, num_touches, evflags,
delta_x, delta_y, delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
num_events++;
return num_events;
}
void
QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y,
double scale, double delta_angle)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
queueEventList(dev, InputEventList, nevents);
}
void
QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
0.0, 0.0);
queueEventList(dev, InputEventList, nevents);
}

View File

@ -716,3 +716,10 @@ GrabIsKeyboardGrab(GrabPtr grab)
return (grab->type == KeyPress ||
grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
}
Bool
GrabIsGestureGrab(GrabPtr grab)
{
return (grab->type == XI_GesturePinchBegin ||
grab->type == XI_GestureSwipeBegin);
}

View File

@ -746,6 +746,21 @@ init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms,
event->source_type = source_type;
}
/**
* Initializes the given gesture event to zero (or default values),
* for the given device.
*/
void
init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms)
{
memset(event, 0, sizeof(GestureEvent));
event->header = ET_Internal;
event->length = sizeof(GestureEvent);
event->time = ms;
event->deviceid = dev->id;
event->sourceid = dev->id;
}
int
event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd)
{
@ -794,6 +809,24 @@ event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
}
}
void
event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event)
{
if (kbd && kbd->key) {
XkbStatePtr state= &kbd->key->xkbInfo->state;
event->mods.base = state->base_mods;
event->mods.latched = state->latched_mods;
event->mods.locked = state->locked_mods;
event->mods.effective = state->mods;
event->group.base = state->base_group;
event->group.latched = state->latched_group;
event->group.locked = state->locked_group;
event->group.effective = state->group;
}
}
/**
* Return the event filter mask for the given device and the given core or
* XI1 protocol type.

View File

@ -99,6 +99,7 @@ Equipment Corporation.
#include <X11/fonts/libxfont2.h>
#include "opaque.h"
#include "servermd.h"
#include "hotplug.h"
#include "dixfont.h"
#include "extnsionst.h"
#include "privates.h"

View File

@ -12,6 +12,7 @@ srcs_dix = [
'eventconvert.c',
'extension.c',
'gc.c',
'gestures.c',
'getevents.c',
'globals.c',
'glyphcurs.c',

View File

@ -253,7 +253,7 @@ ProcChangeProperty(ClientPtr client)
int
dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
Atom type, int format, int mode, unsigned long len,
void *value, Bool sendevent)
const void *value, Bool sendevent)
{
PropertyPtr pProp;
PropertyRec savedProp;

15
doc/Makefile.am Normal file
View File

@ -0,0 +1,15 @@
SUBDIRS = dtrace
if ENABLE_DEVEL_DOCS
if HAVE_XMLTO
# Main DocBook/XML files (DOCTYPE book)
docbook = Xserver-spec.xml Xinput.xml
# Generate DocBook/XML output formats with or without stylesheets
include $(top_srcdir)/devbook.am
endif HAVE_XMLTO
endif ENABLE_DEVEL_DOCS
EXTRA_DIST = smartsched filter-xmlto.sh

15
doc/dtrace/Makefile.am Normal file
View File

@ -0,0 +1,15 @@
if ENABLE_DOCS
if XSERVER_DTRACE
# Main DocBook/XML files (DOCTYPE book)
docbook = Xserver-DTrace.xml
# The location where the DocBook/XML files and their generated formats are installed
shelfdir = $(docdir)
# Generate DocBook/XML output formats with or without stylesheets
include $(top_srcdir)/docbook.am
endif XSERVER_DTRACE
endif ENABLE_DOCS

64
doc/dtrace/meson.build Normal file
View File

@ -0,0 +1,64 @@
if build_docs
basename = 'Xserver-DTrace'
input_xml = basename + '.xml'
custom_target(
basename + '.html',
output: basename + '.html',
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.html.xml'),
'--stringparam', 'current.docid=' + basename,
'-o', meson.current_build_dir(),
'xhtml-nochunks', '@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
if build_docs_pdf
foreach format : ['ps', 'pdf']
output_fn = basename + '.' + format
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.pdf.xml'),
'--stringparam', 'current.docid=' + basename,
'-o', meson.current_build_dir(),
'--with-fop', format, '@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
endforeach
endif
foreach format_data : [['html', 'xorg-xhtml.xsl'], ['pdf', 'xorg-fo.xsl']]
format = format_data[0]
stylesheet = format_data[1]
output_fn = basename + '.' + format + '.db'
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xsltproc] + docs_xslt_search_flags + [
'--stringparam', 'targets.filename', output_fn,
'--stringparam', 'collect.xref.targets', 'only',
'--stringparam', 'olink.base.uri', basename + '.' + format,
'--nonet',
'--output', join_paths(meson.current_build_dir(), output_fn),
'--xinclude', join_paths(doc_stylesheet_srcdir, stylesheet),
'@INPUT0@'],
build_by_default: true,
install: true,
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
)
endforeach
endif

39
doc/meson.build Normal file
View File

@ -0,0 +1,39 @@
if build_docs_devel
foreach basename : ['Xserver-spec', 'Xinput']
input_xml = basename + '.xml'
custom_target(
basename + '.html',
output: basename + '.html',
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
'-o', meson.current_build_dir(),
'xhtml-nochunks', '@INPUT0@'],
build_by_default: true,
install: false,
)
if build_docs_pdf
foreach format : ['ps', 'pdf']
output_fn = basename + '.' + format
custom_target(
output_fn,
output: output_fn,
input: [input_xml],
command: [xmlto] + docs_xmlto_search_flags + [
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
'-o', meson.current_build_dir(),
'--with-fop', format, '@INPUT0@'],
build_by_default: true,
install: false,
)
endforeach
endif
endforeach
endif
subdir('dtrace')

13
dri3/Makefile.am Normal file
View File

@ -0,0 +1,13 @@
noinst_LTLIBRARIES = libdri3.la
AM_CFLAGS = \
@DIX_CFLAGS@ \
@LIBDRM_CFLAGS@
libdri3_la_SOURCES = \
dri3.h \
dri3_priv.h \
dri3.c \
dri3_request.c \
dri3_screen.c
sdk_HEADERS = dri3.h

View File

@ -16,3 +16,7 @@ if build_dri3
dependencies: [ common_dep, libdrm_dep ],
)
endif
if build_xorg
install_data(hdrs_dri3, install_dir: xorgsdkdir)
endif

24
exa/Makefile.am Normal file
View File

@ -0,0 +1,24 @@
noinst_LTLIBRARIES = libexa.la
if XORG
sdk_HEADERS = exa.h
endif
AM_CPPFLAGS = $(XORG_INCS)
AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS)
libexa_la_SOURCES = \
exa.c \
exa.h \
exa_classic.c \
exa_migration_classic.c \
exa_driver.c \
exa_mixed.c \
exa_migration_mixed.c \
exa_accel.c \
exa_glyphs.c \
exa_offscreen.c \
exa_render.c \
exa_priv.h \
exa_unaccel.c

1144
exa/exa.c Normal file

File diff suppressed because it is too large Load Diff

820
exa/exa.h Normal file
View File

@ -0,0 +1,820 @@
/*
*
* Copyright (C) 2000 Keith Packard
* 2004 Eric Anholt
* 2005 Zack Rusin
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of copyright holders not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Copyright holders make no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/** @file
* This is the header containing the public API of EXA for exa drivers.
*/
#ifndef EXA_H
#define EXA_H
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "gcstruct.h"
#include "picturestr.h"
#include "fb.h"
#define EXA_VERSION_MAJOR 2
#define EXA_VERSION_MINOR 6
#define EXA_VERSION_RELEASE 0
typedef struct _ExaOffscreenArea ExaOffscreenArea;
typedef void (*ExaOffscreenSaveProc) (ScreenPtr pScreen,
ExaOffscreenArea * area);
typedef enum _ExaOffscreenState {
ExaOffscreenAvail,
ExaOffscreenRemovable,
ExaOffscreenLocked
} ExaOffscreenState;
struct _ExaOffscreenArea {
int base_offset; /* allocation base */
int offset; /* aligned offset */
int size; /* total allocation size */
unsigned last_use;
void *privData;
ExaOffscreenSaveProc save;
ExaOffscreenState state;
ExaOffscreenArea *next;
unsigned eviction_cost;
ExaOffscreenArea *prev; /* Double-linked list for defragmentation */
int align; /* required alignment */
};
/**
* The ExaDriver structure is allocated through exaDriverAlloc(), and then
* fllled in by drivers.
*/
typedef struct _ExaDriver {
/**
* exa_major and exa_minor should be set by the driver to the version of
* EXA which the driver was compiled for (or configures itself at runtime
* to support). This allows EXA to extend the structure for new features
* without breaking ABI for drivers compiled against older versions.
*/
int exa_major, exa_minor;
/**
* memoryBase is the address of the beginning of framebuffer memory.
* The visible screen should be within memoryBase to memoryBase +
* memorySize.
*/
CARD8 *memoryBase;
/**
* offScreenBase is the offset from memoryBase of the beginning of the area
* to be managed by EXA's linear offscreen memory manager.
*
* In XFree86 DDX drivers, this is probably:
* (pScrn->displayWidth * cpp * pScrn->virtualY)
*/
unsigned long offScreenBase;
/**
* memorySize is the length (in bytes) of framebuffer memory beginning
* from memoryBase.
*
* The offscreen memory manager will manage the area beginning at
* (memoryBase + offScreenBase), with a length of (memorySize -
* offScreenBase)
*
* In XFree86 DDX drivers, this is probably (pScrn->videoRam * 1024)
*/
unsigned long memorySize;
/**
* pixmapOffsetAlign is the byte alignment necessary for pixmap offsets
* within framebuffer.
*
* Hardware typically has a required alignment of offsets, which may or may
* not be a power of two. EXA will ensure that pixmaps managed by the
* offscreen memory manager meet this alignment requirement.
*/
int pixmapOffsetAlign;
/**
* pixmapPitchAlign is the byte alignment necessary for pixmap pitches
* within the framebuffer.
*
* Hardware typically has a required alignment of pitches for acceleration.
* For 3D hardware, Composite acceleration often requires that source and
* mask pixmaps (textures) have a power-of-two pitch, which can be demanded
* using EXA_OFFSCREEN_ALIGN_POT. These pitch requirements only apply to
* pixmaps managed by the offscreen memory manager. Thus, it is up to the
* driver to ensure that the visible screen has an appropriate pitch for
* acceleration.
*/
int pixmapPitchAlign;
/**
* The flags field is bitfield of boolean values controlling EXA's behavior.
*
* The flags include EXA_OFFSCREEN_PIXMAPS, EXA_OFFSCREEN_ALIGN_POT, and
* EXA_TWO_BITBLT_DIRECTIONS.
*/
int flags;
/** @{ */
/**
* maxX controls the X coordinate limitation for rendering from the card.
* The driver should never receive a request for rendering beyond maxX
* in the X direction from the origin of a pixmap.
*/
int maxX;
/**
* maxY controls the Y coordinate limitation for rendering from the card.
* The driver should never receive a request for rendering beyond maxY
* in the Y direction from the origin of a pixmap.
*/
int maxY;
/** @} */
/* private */
ExaOffscreenArea *offScreenAreas;
Bool needsSync;
int lastMarker;
/** @name Solid
* @{
*/
/**
* PrepareSolid() sets up the driver for doing a solid fill.
* @param pPixmap Destination pixmap
* @param alu raster operation
* @param planemask write mask for the fill
* @param fg "foreground" color for the fill
*
* This call should set up the driver for doing a series of solid fills
* through the Solid() call. The alu raster op is one of the GX*
* graphics functions listed in X.h, and typically maps to a similar
* single-byte "ROP" setting in all hardware. The planemask controls
* which bits of the destination should be affected, and will only represent
* the bits up to the depth of pPixmap. The fg is the pixel value of the
* foreground color referred to in ROP descriptions.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareSolid() call is required of all drivers, but it may fail for any
* reason. Failure results in a fallback to software rendering.
*/
Bool (*PrepareSolid) (PixmapPtr pPixmap,
int alu, Pixel planemask, Pixel fg);
/**
* Solid() performs a solid fill set up in the last PrepareSolid() call.
*
* @param pPixmap destination pixmap
* @param x1 left coordinate
* @param y1 top coordinate
* @param x2 right coordinate
* @param y2 bottom coordinate
*
* Performs the fill set up by the last PrepareSolid() call, covering the
* area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
* in the coordinate space of the destination pixmap, so the driver will
* need to set up the hardware's offset and pitch for the destination
* coordinates according to the pixmap's offset and pitch within
* framebuffer. This likely means using exaGetPixmapOffset() and
* exaGetPixmapPitch().
*
* This call is required if PrepareSolid() ever succeeds.
*/
void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
/**
* DoneSolid() finishes a set of solid fills.
*
* @param pPixmap destination pixmap.
*
* The DoneSolid() call is called at the end of a series of consecutive
* Solid() calls following a successful PrepareSolid(). This allows drivers
* to finish up emitting drawing commands that were buffered, or clean up
* state from PrepareSolid().
*
* This call is required if PrepareSolid() ever succeeds.
*/
void (*DoneSolid) (PixmapPtr pPixmap);
/** @} */
/** @name Copy
* @{
*/
/**
* PrepareCopy() sets up the driver for doing a copy within video
* memory.
*
* @param pSrcPixmap source pixmap
* @param pDstPixmap destination pixmap
* @param dx X copy direction
* @param dy Y copy direction
* @param alu raster operation
* @param planemask write mask for the fill
*
* This call should set up the driver for doing a series of copies from the
* the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
* hardware should do the copy from the left to the right, and dy will be
* positive if the copy should be done from the top to the bottom. This
* is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
* If your hardware can only support blits that are (left to right, top to
* bottom) or (right to left, bottom to top), then you should set
* #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to
* ones that meet those requirements. The alu raster op is one of the GX*
* graphics functions listed in X.h, and typically maps to a similar
* single-byte "ROP" setting in all hardware. The planemask controls which
* bits of the destination should be affected, and will only represent the
* bits up to the depth of pPixmap.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareCopy() call is required of all drivers, but it may fail for any
* reason. Failure results in a fallback to software rendering.
*/
Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
PixmapPtr pDstPixmap,
int dx, int dy, int alu, Pixel planemask);
/**
* Copy() performs a copy set up in the last PrepareCopy call.
*
* @param pDstPixmap destination pixmap
* @param srcX source X coordinate
* @param srcY source Y coordinate
* @param dstX destination X coordinate
* @param dstY destination Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied.
*
* Performs the copy set up by the last PrepareCopy() call, copying the
* rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
* pixmap to the same-sized rectangle at (dstX, dstY) in the destination
* pixmap. Those rectangles may overlap in memory, if
* pSrcPixmap == pDstPixmap. Note that this call does not receive the
* pSrcPixmap as an argument -- if it's needed in this function, it should
* be stored in the driver private during PrepareCopy(). As with Solid(),
* the coordinates are in the coordinate space of each pixmap, so the driver
* will need to set up source and destination pitches and offsets from those
* pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch().
*
* This call is required if PrepareCopy ever succeeds.
*/
void (*Copy) (PixmapPtr pDstPixmap,
int srcX,
int srcY, int dstX, int dstY, int width, int height);
/**
* DoneCopy() finishes a set of copies.
*
* @param pPixmap destination pixmap.
*
* The DoneCopy() call is called at the end of a series of consecutive
* Copy() calls following a successful PrepareCopy(). This allows drivers
* to finish up emitting drawing commands that were buffered, or clean up
* state from PrepareCopy().
*
* This call is required if PrepareCopy() ever succeeds.
*/
void (*DoneCopy) (PixmapPtr pDstPixmap);
/** @} */
/** @name Composite
* @{
*/
/**
* CheckComposite() checks to see if a composite operation could be
* accelerated.
*
* @param op Render operation
* @param pSrcPicture source Picture
* @param pMaskPicture mask picture
* @param pDstPicture destination Picture
*
* The CheckComposite() call checks if the driver could handle acceleration
* of op with the given source, mask, and destination pictures. This allows
* drivers to check source and destination formats, supported operations,
* transformations, and component alpha state, and send operations it can't
* support to software rendering early on. This avoids costly pixmap
* migration to the wrong places when the driver can't accelerate
* operations. Note that because migration hasn't happened, the driver
* can't know during CheckComposite() what the offsets and pitches of the
* pixmaps are going to be.
*
* See PrepareComposite() for more details on likely issues that drivers
* will have in accelerating Composite operations.
*
* The CheckComposite() call is recommended if PrepareComposite() is
* implemented, but is not required.
*/
Bool (*CheckComposite) (int op,
PicturePtr pSrcPicture,
PicturePtr pMaskPicture, PicturePtr pDstPicture);
/**
* PrepareComposite() sets up the driver for doing a Composite operation
* described in the Render extension protocol spec.
*
* @param op Render operation
* @param pSrcPicture source Picture
* @param pMaskPicture mask picture
* @param pDstPicture destination Picture
* @param pSrc source pixmap
* @param pMask mask pixmap
* @param pDst destination pixmap
*
* This call should set up the driver for doing a series of Composite
* operations, as described in the Render protocol spec, with the given
* pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
* pDst are the pixmaps containing the pixel data, and should be used for
* setting the offset and pitch used for the coordinate spaces for each of
* the Pictures.
*
* Notes on interpreting Picture structures:
* - The Picture structures will always have a valid pDrawable.
* - The Picture structures will never have alphaMap set.
* - The mask Picture (and therefore pMask) may be NULL, in which case the
* operation is simply src OP dst instead of src IN mask OP dst, and
* mask coordinates should be ignored.
* - pMarkPicture may have componentAlpha set, which greatly changes
* the behavior of the Composite operation. componentAlpha has no effect
* when set on pSrcPicture or pDstPicture.
* - The source and mask Pictures may have a transformation set
* (Picture->transform != NULL), which means that the source coordinates
* should be transformed by that transformation, resulting in scaling,
* rotation, etc. The PictureTransformPoint() call can transform
* coordinates for you. Transforms have no effect on Pictures when used
* as a destination.
* - The source and mask pictures may have a filter set. PictFilterNearest
* and PictFilterBilinear are defined in the Render protocol, but others
* may be encountered, and must be handled correctly (usually by
* PrepareComposite failing, and falling back to software). Filters have
* no effect on Pictures when used as a destination.
* - The source and mask Pictures may have repeating set, which must be
* respected. Many chipsets will be unable to support repeating on
* pixmaps that have a width or height that is not a power of two.
*
* If your hardware can't support source pictures (textures) with
* non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT.
*
* Note that many drivers will need to store some of the data in the driver
* private record, for sending to the hardware with each drawing command.
*
* The PrepareComposite() call is not required. However, it is highly
* recommended for performance of antialiased font rendering and performance
* of cairo applications. Failure results in a fallback to software
* rendering.
*/
Bool (*PrepareComposite) (int op,
PicturePtr pSrcPicture,
PicturePtr pMaskPicture,
PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
/**
* Composite() performs a Composite operation set up in the last
* PrepareComposite() call.
*
* @param pDstPixmap destination pixmap
* @param srcX source X coordinate
* @param srcY source Y coordinate
* @param maskX source X coordinate
* @param maskY source Y coordinate
* @param dstX destination X coordinate
* @param dstY destination Y coordinate
* @param width destination rectangle width
* @param height destination rectangle height
*
* Performs the Composite operation set up by the last PrepareComposite()
* call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
* in the destination Pixmap. Note that if a transformation was set on
* the source or mask Pictures, the source rectangles may not be the same
* size as the destination rectangles and filtering. Getting the coordinate
* transformation right at the subpixel level can be tricky, and rendercheck
* can test this for you.
*
* This call is required if PrepareComposite() ever succeeds.
*/
void (*Composite) (PixmapPtr pDst,
int srcX,
int srcY,
int maskX,
int maskY, int dstX, int dstY, int width, int height);
/**
* DoneComposite() finishes a set of Composite operations.
*
* @param pPixmap destination pixmap.
*
* The DoneComposite() call is called at the end of a series of consecutive
* Composite() calls following a successful PrepareComposite(). This allows
* drivers to finish up emitting drawing commands that were buffered, or
* clean up state from PrepareComposite().
*
* This call is required if PrepareComposite() ever succeeds.
*/
void (*DoneComposite) (PixmapPtr pDst);
/** @} */
/**
* UploadToScreen() loads a rectangle of data from src into pDst.
*
* @param pDst destination pixmap
* @param x destination X coordinate.
* @param y destination Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied
* @param src pointer to the beginning of the source data
* @param src_pitch pitch (in bytes) of the lines of source data.
*
* UploadToScreen() copies data in system memory beginning at src (with
* pitch src_pitch) into the destination pixmap from (x, y) to
* (x + width, y + height). This is typically done with hostdata uploads,
* where the CPU sets up a blit command on the hardware with instructions
* that the blit data will be fed through some sort of aperture on the card.
*
* If UploadToScreen() is performed asynchronously, it is up to the driver
* to call exaMarkSync(). This is in contrast to most other acceleration
* calls in EXA.
*
* UploadToScreen() can aid in pixmap migration, but is most important for
* the performance of exaGlyphs() (antialiased font drawing) by allowing
* pipelining of data uploads, avoiding a sync of the card after each glyph.
*
* @return TRUE if the driver successfully uploaded the data. FALSE
* indicates that EXA should fall back to doing the upload in software.
*
* UploadToScreen() is not required, but is recommended if Composite
* acceleration is supported.
*/
Bool (*UploadToScreen) (PixmapPtr pDst,
int x,
int y, int w, int h, char *src, int src_pitch);
/**
* UploadToScratch() is no longer used and will be removed next time the EXA
* major version needs to be bumped.
*/
Bool (*UploadToScratch) (PixmapPtr pSrc, PixmapPtr pDst);
/**
* DownloadFromScreen() loads a rectangle of data from pSrc into dst
*
* @param pSrc source pixmap
* @param x source X coordinate.
* @param y source Y coordinate
* @param width width of the rectangle to be copied
* @param height height of the rectangle to be copied
* @param dst pointer to the beginning of the destination data
* @param dst_pitch pitch (in bytes) of the lines of destination data.
*
* DownloadFromScreen() copies data from offscreen memory in pSrc from
* (x, y) to (x + width, y + height), to system memory starting at
* dst (with pitch dst_pitch). This would usually be done
* using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
* and then synchronously reading from AGP. Because the implementation
* might be synchronous, EXA leaves it up to the driver to call
* exaMarkSync() if DownloadFromScreen() was asynchronous. This is in
* contrast to most other acceleration calls in EXA.
*
* DownloadFromScreen() can aid in the largest bottleneck in pixmap
* migration, which is the read from framebuffer when evicting pixmaps from
* framebuffer memory. Thus, it is highly recommended, even though
* implementations are typically complicated.
*
* @return TRUE if the driver successfully downloaded the data. FALSE
* indicates that EXA should fall back to doing the download in software.
*
* DownloadFromScreen() is not required, but is highly recommended.
*/
Bool (*DownloadFromScreen) (PixmapPtr pSrc,
int x, int y,
int w, int h, char *dst, int dst_pitch);
/**
* MarkSync() requests that the driver mark a synchronization point,
* returning an driver-defined integer marker which could be requested for
* synchronization to later in WaitMarker(). This might be used in the
* future to avoid waiting for full hardware stalls before accessing pixmap
* data with the CPU, but is not important in the current incarnation of
* EXA.
*
* Note that drivers should call exaMarkSync() when they have done some
* acceleration, rather than their own MarkSync() handler, as otherwise EXA
* will be unaware of the driver's acceleration and not sync to it during
* fallbacks.
*
* MarkSync() is optional.
*/
int (*MarkSync) (ScreenPtr pScreen);
/**
* WaitMarker() waits for all rendering before the given marker to have
* completed. If the driver does not implement MarkSync(), marker is
* meaningless, and all rendering by the hardware should be completed before
* WaitMarker() returns.
*
* Note that drivers should call exaWaitSync() to wait for all acceleration
* to finish, as otherwise EXA will be unaware of the driver having
* synchronized, resulting in excessive WaitMarker() calls.
*
* WaitMarker() is required of all drivers.
*/
void (*WaitMarker) (ScreenPtr pScreen, int marker);
/** @{ */
/**
* PrepareAccess() is called before CPU access to an offscreen pixmap.
*
* @param pPix the pixmap being accessed
* @param index the index of the pixmap being accessed.
*
* PrepareAccess() will be called before CPU access to an offscreen pixmap.
* This can be used to set up hardware surfaces for byteswapping or
* untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
* making CPU access use a different aperture.
*
* The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC,
* #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or
* #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps
* will have PrepareAccess() called on them per operation, drivers can have
* a small, statically-allocated space to maintain state for PrepareAccess()
* and FinishAccess() in. Note that PrepareAccess() is only called once per
* pixmap and operation, regardless of whether the pixmap is used as a
* destination and/or source, and the index may not reflect the usage.
*
* PrepareAccess() may fail. An example might be the case of hardware that
* can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
* fails, EXA will migrate the pixmap to system memory.
* DownloadFromScreen() must be implemented and must not fail if a driver
* wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
* pPix is the visible screen, because the visible screen can not be
* migrated.
*
* @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
* drawing.
* @return FALSE if PrepareAccess() is unsuccessful and EXA should use
* DownloadFromScreen() to migate the pixmap out.
*/
Bool (*PrepareAccess) (PixmapPtr pPix, int index);
/**
* FinishAccess() is called after CPU access to an offscreen pixmap.
*
* @param pPix the pixmap being accessed
* @param index the index of the pixmap being accessed.
*
* FinishAccess() will be called after finishing CPU access of an offscreen
* pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
* called if PrepareAccess() failed and the pixmap was migrated out.
*/
void (*FinishAccess) (PixmapPtr pPix, int index);
/**
* PixmapIsOffscreen() is an optional driver replacement to
* exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour
* of exaPixmapHasGpuCopy().
*
* @param pPix the pixmap
* @return TRUE if the given drawable is in framebuffer memory.
*
* exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
* memory, meaning that acceleration could probably be done to it, and that it
* will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
* with the CPU.
*
*
*/
Bool (*PixmapIsOffscreen) (PixmapPtr pPix);
/** @name PrepareAccess() and FinishAccess() indices
* @{
*/
/**
* EXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
* read from.
*/
#define EXA_PREPARE_DEST 0
/**
* EXA_PREPARE_SRC is the index for a pixmap that may be read from
*/
#define EXA_PREPARE_SRC 1
/**
* EXA_PREPARE_SRC is the index for a second pixmap that may be read
* from.
*/
#define EXA_PREPARE_MASK 2
/**
* EXA_PREPARE_AUX* are additional indices for other purposes, e.g.
* separate alpha maps with Composite operations.
*/
#define EXA_PREPARE_AUX_DEST 3
#define EXA_PREPARE_AUX_SRC 4
#define EXA_PREPARE_AUX_MASK 5
#define EXA_NUM_PREPARE_INDICES 6
/** @} */
/**
* maxPitchPixels controls the pitch limitation for rendering from
* the card.
* The driver should never receive a request for rendering a pixmap
* that has a pitch (in pixels) beyond maxPitchPixels.
*
* Setting this field is optional -- if your hardware doesn't have
* a pitch limitation in pixels, don't set this. If neither this value
* nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
* If set, it must not be smaller than maxX.
*
* @sa maxPitchBytes
*/
int maxPitchPixels;
/**
* maxPitchBytes controls the pitch limitation for rendering from
* the card.
* The driver should never receive a request for rendering a pixmap
* that has a pitch (in bytes) beyond maxPitchBytes.
*
* Setting this field is optional -- if your hardware doesn't have
* a pitch limitation in bytes, don't set this.
* If set, it must not be smaller than maxX * 4.
* There's no default value for maxPitchBytes.
*
* @sa maxPitchPixels
*/
int maxPitchBytes;
/* Hooks to allow driver to its own pixmap memory management */
void *(*CreatePixmap) (ScreenPtr pScreen, int size, int align);
void (*DestroyPixmap) (ScreenPtr pScreen, void *driverPriv);
/**
* Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is
* not offscreen, which will never be accelerated and Prepare/FinishAccess won't
* be called.
*/
Bool (*ModifyPixmapHeader) (PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
/* hooks for drivers with tiling support:
* driver MUST fill out new_fb_pitch with valid pitch of pixmap
*/
void *(*CreatePixmap2) (ScreenPtr pScreen, int width, int height,
int depth, int usage_hint, int bitsPerPixel,
int *new_fb_pitch);
/** @} */
Bool (*SharePixmapBacking)(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
Bool (*SetSharedPixmapBacking)(PixmapPtr pPixmap, void *handle);
} ExaDriverRec, *ExaDriverPtr;
/** @name EXA driver flags
* @{
*/
/**
* EXA_OFFSCREEN_PIXMAPS indicates to EXA that the driver can support
* offscreen pixmaps.
*/
#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
/**
* EXA_OFFSCREEN_ALIGN_POT indicates to EXA that the driver needs pixmaps
* to have a power-of-two pitch.
*/
#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
/**
* EXA_TWO_BITBLT_DIRECTIONS indicates to EXA that the driver can only
* support copies that are (left-to-right, top-to-bottom) or
* (right-to-left, bottom-to-top).
*/
#define EXA_TWO_BITBLT_DIRECTIONS (1 << 2)
/**
* EXA_HANDLES_PIXMAPS indicates to EXA that the driver can handle
* all pixmap addressing and migration.
*/
#define EXA_HANDLES_PIXMAPS (1 << 3)
/**
* EXA_SUPPORTS_PREPARE_AUX indicates to EXA that the driver can handle the
* EXA_PREPARE_AUX* indices in the Prepare/FinishAccess hooks. If there are no
* such hooks, this flag has no effect.
*/
#define EXA_SUPPORTS_PREPARE_AUX (1 << 4)
/**
* EXA_SUPPORTS_OFFSCREEN_OVERLAPS indicates to EXA that the driver Copy hooks
* can handle the source and destination occupying overlapping offscreen memory
* areas. This allows the offscreen memory defragmentation code to defragment
* areas where the defragmented position overlaps the fragmented position.
*
* Typically this is supported by traditional 2D engines but not by 3D engines.
*/
#define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5)
/**
* EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the
* problem known software fallbacks like trapezoids. This only migrates pixmaps one way
* into a driver pixmap and then pins it.
*/
#define EXA_MIXED_PIXMAPS (1 << 6)
/** @} */
/* in exa.c */
extern _X_EXPORT ExaDriverPtr exaDriverAlloc(void);
extern _X_EXPORT Bool
exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo);
extern _X_EXPORT void
exaDriverFini(ScreenPtr pScreen);
extern _X_EXPORT void
exaMarkSync(ScreenPtr pScreen);
extern _X_EXPORT void
exaWaitSync(ScreenPtr pScreen);
extern _X_EXPORT unsigned long
exaGetPixmapOffset(PixmapPtr pPix);
extern _X_EXPORT unsigned long
exaGetPixmapPitch(PixmapPtr pPix);
extern _X_EXPORT unsigned long
exaGetPixmapSize(PixmapPtr pPix);
extern _X_EXPORT void *exaGetPixmapDriverPrivate(PixmapPtr p);
/* in exa_offscreen.c */
extern _X_EXPORT ExaOffscreenArea *exaOffscreenAlloc(ScreenPtr pScreen,
int size, int align,
Bool locked,
ExaOffscreenSaveProc save,
void *privData);
extern _X_EXPORT ExaOffscreenArea *exaOffscreenFree(ScreenPtr pScreen,
ExaOffscreenArea * area);
extern _X_EXPORT void
ExaOffscreenMarkUsed(PixmapPtr pPixmap);
extern _X_EXPORT void
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable);
extern _X_EXPORT Bool
exaDrawableIsOffscreen(DrawablePtr pDrawable);
/* in exa.c */
extern _X_EXPORT void
exaMoveInPixmap(PixmapPtr pPixmap);
extern _X_EXPORT void
exaMoveOutPixmap(PixmapPtr pPixmap);
/* in exa_unaccel.c */
extern _X_EXPORT CARD32
exaGetPixmapFirstPixel(PixmapPtr pPixmap);
/**
* Returns TRUE if the given planemask covers all the significant bits in the
* pixel values for pDrawable.
*/
#define EXA_PM_IS_SOLID(_pDrawable, _pm) \
(((_pm) & FbFullMask((_pDrawable)->depth)) == \
FbFullMask((_pDrawable)->depth))
#endif /* EXA_H */

1297
exa/exa_accel.c Normal file

File diff suppressed because it is too large Load Diff

265
exa/exa_classic.c Normal file
View File

@ -0,0 +1,265 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* 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.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the classic exa specific implementation. */
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
return pExaPixmap->fb_ptr;
else
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*
* If width and height are 0, this won't be a full-fledged pixmap and it will
* get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
* ModifyPixmapHeader() would break migration. These types of pixmaps are used
* for scratch pixmaps, or to represent the visible screen.
*/
PixmapPtr
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
BoxRec box;
int bpp;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
pExaPixmap->driverPriv = NULL;
/* Scratch pixmaps may have w/h equal to zero, and may not be
* migrated.
*/
if (!w || !h)
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
else
pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
pPixmap->devPrivate.ptr = NULL;
pExaPixmap->use_gpu_copy = FALSE;
pExaPixmap->fb_ptr = NULL;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
if (pExaPixmap->fb_pitch > 131071) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(NULL, NULL,
DamageReportNone, TRUE,
pScreen, pPixmap);
if (pExaPixmap->pDamage == NULL) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current operation. */
/* This is used by exa to optimize migration. */
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
pExaPixmap->area = NULL;
/* We set the initial pixmap as completely valid for a simple reason.
* Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
* could form single pixel rects as part of a region. Setting the complete region
* as valid is a natural defragmentation of the region.
*/
box.x1 = 0;
box.y1 = 0;
box.x2 = w;
box.y2 = h;
RegionInit(&pExaPixmap->validSys, &box, 0);
RegionInit(&pExaPixmap->validFB, &box, 0);
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap) {
if (pPixData)
pExaPixmap->sys_ptr = pPixData;
if (devKind > 0)
pExaPixmap->sys_pitch = devKind;
/* Classic EXA:
* - Framebuffer.
* - Scratch pixmap with gpu memory.
*/
if (pExaScr->info->memoryBase && pPixData) {
if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
((CARD8 *) pPixData - pExaScr->info->memoryBase) <
pExaScr->info->memorySize) {
pExaPixmap->fb_ptr = pPixData;
pExaPixmap->fb_pitch = devKind;
pExaPixmap->use_gpu_copy = TRUE;
}
}
if (width > 0 && height > 0 && bitsPerPixel > 0) {
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
}
/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
* gpu memory, so there's no need to track damage.
*/
if (pExaPixmap->pDamage) {
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
}
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_classic(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaPixmap->area) {
DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
(void *) pPixmap->drawable.id,
ExaGetPixmapPriv(pPixmap)->area->offset,
pPixmap->drawable.width, pPixmap->drawable.height));
/* Free the offscreen area */
exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
}
RegionUninit(&pExaPixmap->validSys);
RegionUninit(&pExaPixmap->validFB);
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
Bool ret;
if (pExaScr->info->PixmapIsOffscreen) {
void *old_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = old_ptr;
}
else
ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
return ret;
}

230
exa/exa_driver.c Normal file
View File

@ -0,0 +1,230 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* 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.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the driver allocated pixmaps specific implementation. */
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*
* Pixmaps are always marked as pinned, because exa has no control over them.
*/
PixmapPtr
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
int bpp;
size_t paddedWidth, datasize;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
/* Set this before driver hooks, to allow for driver pixmaps without gpu
* memory to back it. These pixmaps have a valid pointer at all times.
*/
pPixmap->devPrivate.ptr = NULL;
if (pExaScr->info->CreatePixmap2) {
int new_pitch = 0;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
&new_pitch);
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
}
else {
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
if (paddedWidth / 4 > 32767 || h > 32767)
return NullPixmap;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
if (paddedWidth < pExaPixmap->fb_pitch)
paddedWidth = pExaPixmap->fb_pitch;
datasize = h * paddedWidth;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap(pScreen, datasize, 0);
}
if (!pExaPixmap->driverPriv) {
swap(pExaScr, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return NULL;
}
/* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
pExaPixmap->fb_ptr = NULL;
pExaPixmap->pDamage = NULL;
pExaPixmap->sys_ptr = NULL;
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
pExaPixmap->area = NULL;
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap) {
if (pPixData)
pExaPixmap->sys_ptr = pPixData;
if (devKind > 0)
pExaPixmap->sys_pitch = devKind;
if (width > 0 && height > 0 && bitsPerPixel > 0) {
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
}
}
if (pExaScr->info->ModifyPixmapHeader) {
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind,
pPixData);
/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
* If pPixmap->devPrivate.ptr is non-NULL, then we've got a
* !has_gpu_copy pixmap. We need to store the pointer,
* because PrepareAccess won't be called.
*/
if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
}
if (ret == TRUE)
goto out;
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
out:
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_driver(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaPixmap->driverPriv)
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
void *saved_ptr;
Bool ret;
saved_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = saved_ptr;
return ret;
}

839
exa/exa_glyphs.c Normal file
View File

@ -0,0 +1,839 @@
/*
* Copyright © 2008 Red Hat, Inc.
* Partly based on code Copyright © 2000 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Red Hat not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Red Hat makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Owen Taylor <otaylor@fishsoup.net>
* Based on code by: Keith Packard
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdlib.h>
#include "exa_priv.h"
#include "mipict.h"
#if DEBUG_GLYPH_CACHE
#define DBG_GLYPH_CACHE(a) ErrorF a
#else
#define DBG_GLYPH_CACHE(a)
#endif
/* Width of the pixmaps we use for the caches; this should be less than
* max texture size of the driver; this may need to actually come from
* the driver.
*/
#define CACHE_PICTURE_WIDTH 1024
/* Maximum number of glyphs we buffer on the stack before flushing
* rendering to the mask or destination surface.
*/
#define GLYPH_BUFFER_SIZE 256
typedef struct {
PicturePtr mask;
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
int count;
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
typedef enum {
ExaGlyphSuccess, /* Glyph added to render buffer */
ExaGlyphFail, /* out of memory, etc */
ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */
} ExaGlyphCacheResult;
void
exaGlyphsInit(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
int i = 0;
memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
pExaScr->glyphCaches[i].format = PICT_a8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
16;
i++;
pExaScr->glyphCaches[i].format = PICT_a8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
32;
i++;
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
16;
i++;
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
32;
i++;
assert(i == EXA_NUM_GLYPH_CACHES);
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
pExaScr->glyphCaches[i].columns =
CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
pExaScr->glyphCaches[i].size = 256;
pExaScr->glyphCaches[i].hashSize = 557;
}
}
static void
exaUnrealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
{
ExaScreenPriv(pScreen);
int i;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (cache->format != format)
continue;
if (cache->picture) {
FreePicture((void *) cache->picture, (XID) 0);
cache->picture = NULL;
}
free(cache->hashEntries);
cache->hashEntries = NULL;
free(cache->glyphs);
cache->glyphs = NULL;
cache->glyphCount = 0;
}
}
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
/* All caches for a single format share a single pixmap for glyph storage,
* allowing mixing glyphs of different sizes without paying a penalty
* for switching between mask pixmaps. (Note that for a size of font
* right at the border between two sizes, we might be switching for almost
* every glyph.)
*
* This function allocates the storage pixmap, and then fills in the
* rest of the allocated structures for all caches with the given format.
*/
static Bool
exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
{
ExaScreenPriv(pScreen);
int depth = PIXMAN_FORMAT_DEPTH(format);
PictFormatPtr pPictFormat;
PixmapPtr pPixmap;
PicturePtr pPicture;
CARD32 component_alpha;
int height;
int i;
int error;
pPictFormat = PictureMatchFormat(pScreen, depth, format);
if (!pPictFormat)
return FALSE;
/* Compute the total vertical size needed for the format */
height = 0;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
int rows;
if (cache->format != format)
continue;
cache->yOffset = height;
rows = (cache->size + cache->columns - 1) / cache->columns;
height += rows * cache->glyphHeight;
}
/* Now allocate the pixmap and picture */
pPixmap = (*pScreen->CreatePixmap) (pScreen,
CACHE_PICTURE_WIDTH, height, depth, 0);
if (!pPixmap)
return FALSE;
component_alpha = NeedsComponent(pPictFormat->format);
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
CPComponentAlpha, &component_alpha, serverClient,
&error);
(*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
if (!pPicture)
return FALSE;
/* And store the picture in all the caches for the format */
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
int j;
if (cache->format != format)
continue;
cache->picture = pPicture;
cache->picture->refcnt++;
cache->hashEntries = xallocarray(cache->hashSize, sizeof(int));
cache->glyphs = xallocarray(cache->size, sizeof(ExaCachedGlyphRec));
cache->glyphCount = 0;
if (!cache->hashEntries || !cache->glyphs)
goto bail;
for (j = 0; j < cache->hashSize; j++)
cache->hashEntries[j] = -1;
cache->evictionPosition = rand() % cache->size;
}
/* Each cache references the picture individually */
FreePicture((void *) pPicture, (XID) 0);
return TRUE;
bail:
exaUnrealizeGlyphCaches(pScreen, format);
return FALSE;
}
void
exaGlyphsFini(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
int i;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (cache->picture)
exaUnrealizeGlyphCaches(pScreen, cache->format);
}
}
static int
exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, GlyphPtr pGlyph)
{
int slot;
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
int entryPos = cache->hashEntries[slot];
if (entryPos == -1)
return -1;
if (memcmp
(pGlyph->sha1, cache->glyphs[entryPos].sha1,
sizeof(pGlyph->sha1)) == 0) {
return entryPos;
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
static void
exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, GlyphPtr pGlyph, int pos)
{
int slot;
memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
if (cache->hashEntries[slot] == -1) {
cache->hashEntries[slot] = pos;
return;
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
static void
exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, int pos)
{
int slot;
int emptiedSlot = -1;
slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
while (TRUE) { /* hash table can never be full */
int entryPos = cache->hashEntries[slot];
if (entryPos == -1)
return;
if (entryPos == pos) {
cache->hashEntries[slot] = -1;
emptiedSlot = slot;
}
else if (emptiedSlot != -1) {
/* See if we can move this entry into the emptied slot, we can't
* do that if if entry would have hashed between the current position
* and the emptied slot. (taking wrapping into account). Bad positions
* are:
*
* | XXXXXXXXXX |
* i j
*
* |XXX XXXX|
* j i
*
* i - slot, j - emptiedSlot
*
* (Knuth 6.4R)
*/
int entrySlot =
(*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
(emptiedSlot < slot &&
(entrySlot < emptiedSlot || entrySlot >= slot)))) {
cache->hashEntries[emptiedSlot] = entryPos;
cache->hashEntries[slot] = -1;
emptiedSlot = slot;
}
}
slot--;
if (slot < 0)
slot = cache->hashSize - 1;
}
}
#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
/* The most efficient thing to way to upload the glyph to the screen
* is to use the UploadToScreen() driver hook; this allows us to
* pipeline glyph uploads and to avoid creating gpu backed pixmaps for
* glyphs that we'll never use again.
*
* If we can't do it with UploadToScreen (because the glyph has a gpu copy,
* etc), we fall back to CompositePicture.
*
* We need to damage the cache pixmap manually in either case because the damage
* layer unwrapped the picture screen before calling exaGlyphs.
*/
static void
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
{
ExaScreenPriv(pScreen);
PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
ExaPixmapPriv(pGlyphPixmap);
PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
pExaPixmap->accel_blocked)
goto composite;
/* If the glyph pixmap is already uploaded, no point in doing
* things this way */
if (exaPixmapHasGpuCopy(pGlyphPixmap))
goto composite;
/* UploadToScreen only works if bpp match */
if (pGlyphPixmap->drawable.bitsPerPixel !=
pCachePixmap->drawable.bitsPerPixel)
goto composite;
if (pExaScr->do_migration) {
ExaMigrationRec pixmaps[1];
/* cache pixmap must have a gpu copy. */
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pCachePixmap;
pixmaps[0].pReg = NULL;
exaDoMigration(pixmaps, 1, TRUE);
}
if (!exaPixmapHasGpuCopy(pCachePixmap))
goto composite;
/* x,y are in pixmap coordinates, no need for cache{X,Y}off */
if (pExaScr->info->UploadToScreen(pCachePixmap,
x,
y,
pGlyph->info.width,
pGlyph->info.height,
(char *) pExaPixmap->sys_ptr,
pExaPixmap->sys_pitch))
goto damage;
composite:
CompositePicture(PictOpSrc,
pGlyphPicture,
None,
cache->picture,
0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);
damage:
/* The cache pixmap isn't a window, so no need to offset coordinates. */
exaPixmapDirty(pCachePixmap,
x, y, x + cache->glyphWidth, y + cache->glyphHeight);
}
static ExaGlyphCacheResult
exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
ExaGlyphCachePtr cache,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
{
ExaCompositeRectPtr rect;
int pos;
int x, y;
if (buffer->mask && buffer->mask != cache->picture)
return ExaGlyphNeedFlush;
if (!cache->picture) {
if (!exaRealizeGlyphCaches(pScreen, cache->format))
return ExaGlyphFail;
}
DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
cache->glyphWidth, cache->glyphHeight,
cache->format == PICT_a8 ? "A" : "ARGB",
(long) *(CARD32 *) pGlyph->sha1));
pos = exaGlyphCacheHashLookup(cache, pGlyph);
if (pos != -1) {
DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
x = CACHE_X(pos);
y = CACHE_Y(pos);
}
else {
if (cache->glyphCount < cache->size) {
/* Space remaining; we fill from the start */
pos = cache->glyphCount;
x = CACHE_X(pos);
y = CACHE_Y(pos);
cache->glyphCount++;
DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
exaGlyphCacheHashInsert(cache, pGlyph, pos);
}
else {
/* Need to evict an entry. We have to see if any glyphs
* already in the output buffer were at this position in
* the cache
*/
pos = cache->evictionPosition;
x = CACHE_X(pos);
y = CACHE_Y(pos);
DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
if (buffer->count) {
int i;
for (i = 0; i < buffer->count; i++) {
if (pSrc ?
(buffer->rects[i].xMask == x &&
buffer->rects[i].yMask ==
y) : (buffer->rects[i].xSrc == x &&
buffer->rects[i].ySrc == y)) {
DBG_GLYPH_CACHE((" must flush buffer\n"));
return ExaGlyphNeedFlush;
}
}
}
/* OK, we're all set, swap in the new glyph */
exaGlyphCacheHashRemove(cache, pos);
exaGlyphCacheHashInsert(cache, pGlyph, pos);
/* And pick a new eviction position */
cache->evictionPosition = rand() % cache->size;
}
exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
}
buffer->mask = cache->picture;
rect = &buffer->rects[buffer->count];
if (pSrc) {
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = x;
rect->yMask = y;
}
else {
rect->xSrc = x;
rect->ySrc = y;
rect->xMask = 0;
rect->yMask = 0;
}
rect->pDst = pDst;
rect->xDst = xDst;
rect->yDst = yDst;
rect->width = pGlyph->info.width;
rect->height = pGlyph->info.height;
buffer->count++;
return ExaGlyphSuccess;
}
#undef CACHE_X
#undef CACHE_Y
static ExaGlyphCacheResult
exaBufferGlyph(ScreenPtr pScreen,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
{
ExaScreenPriv(pScreen);
unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
int width = pGlyph->info.width;
int height = pGlyph->info.height;
ExaCompositeRectPtr rect;
PicturePtr mask;
int i;
if (buffer->count == GLYPH_BUFFER_SIZE)
return ExaGlyphNeedFlush;
if (PICT_FORMAT_BPP(format) == 1)
format = PICT_a8;
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
if (format == cache->format &&
width <= cache->glyphWidth && height <= cache->glyphHeight) {
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
&pExaScr->
glyphCaches
[i],
buffer,
pGlyph,
pSrc,
pDst,
xSrc, ySrc,
xMask, yMask,
xDst, yDst);
switch (result) {
case ExaGlyphFail:
break;
case ExaGlyphSuccess:
case ExaGlyphNeedFlush:
return result;
}
}
}
/* Couldn't find the glyph in the cache, use the glyph picture directly */
mask = GetGlyphPicture(pGlyph, pScreen);
if (buffer->mask && buffer->mask != mask)
return ExaGlyphNeedFlush;
buffer->mask = mask;
rect = &buffer->rects[buffer->count];
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = xMask;
rect->yMask = yMask;
rect->xDst = xDst;
rect->yDst = yDst;
rect->width = width;
rect->height = height;
buffer->count++;
return ExaGlyphSuccess;
}
static void
exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer)
{
exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
buffer->count, buffer->rects);
buffer->count = 0;
buffer->mask = NULL;
}
static void
exaGlyphsToDst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ExaGlyphBufferPtr buffer)
{
exaCompositeRects(op, pSrc, buffer->mask, pDst, buffer->count,
buffer->rects);
buffer->count = 0;
buffer->mask = NULL;
}
/* Cut and paste from render/glyph.c - probably should export it instead */
static void
GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
{
int x1, x2, y1, y2;
int n;
GlyphPtr glyph;
int x, y;
x = 0;
y = 0;
extents->x1 = MAXSHORT;
extents->x2 = MINSHORT;
extents->y1 = MAXSHORT;
extents->y2 = MINSHORT;
while (nlist--) {
x += list->xOff;
y += list->yOff;
n = list->len;
list++;
while (n--) {
glyph = *glyphs++;
x1 = x - glyph->info.x;
if (x1 < MINSHORT)
x1 = MINSHORT;
y1 = y - glyph->info.y;
if (y1 < MINSHORT)
y1 = MINSHORT;
x2 = x1 + glyph->info.width;
if (x2 > MAXSHORT)
x2 = MAXSHORT;
y2 = y1 + glyph->info.height;
if (y2 > MAXSHORT)
y2 = MAXSHORT;
if (x1 < extents->x1)
extents->x1 = x1;
if (x2 > extents->x2)
extents->x2 = x2;
if (y1 < extents->y1)
extents->y1 = y1;
if (y2 > extents->y2)
extents->y2 = y2;
x += glyph->info.xOff;
y += glyph->info.yOff;
}
}
}
void
exaGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
PixmapPtr pMaskPixmap = 0;
PicturePtr pMask = NULL;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
int width = 0, height = 0;
int x, y;
int first_xOff = list->xOff, first_yOff = list->yOff;
int n;
GlyphPtr glyph;
int error;
BoxRec extents = { 0, 0, 0, 0 };
CARD32 component_alpha;
ExaGlyphBuffer buffer;
if (maskFormat) {
ExaScreenPriv(pScreen);
GCPtr pGC;
xRectangle rect;
GlyphExtents(nlist, list, glyphs, &extents);
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
return;
width = extents.x2 - extents.x1;
height = extents.y2 - extents.y1;
if (maskFormat->depth == 1) {
PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8);
if (a8Format)
maskFormat = a8Format;
}
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pMaskPixmap)
return;
component_alpha = NeedsComponent(maskFormat->format);
pMask = CreatePicture(0, &pMaskPixmap->drawable,
maskFormat, CPComponentAlpha, &component_alpha,
serverClient, &error);
if (!pMask ||
(!component_alpha && pExaScr->info->CheckComposite &&
!(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
{
PictFormatPtr argbFormat;
(*pScreen->DestroyPixmap) (pMaskPixmap);
if (!pMask)
return;
/* The driver can't seem to composite to a8, let's try argb (but
* without component-alpha) */
FreePicture((void *) pMask, (XID) 0);
argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
if (argbFormat)
maskFormat = argbFormat;
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pMaskPixmap)
return;
pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0,
serverClient, &error);
if (!pMask) {
(*pScreen->DestroyPixmap) (pMaskPixmap);
return;
}
}
pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
ValidateGC(&pMaskPixmap->drawable, pGC);
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
FreeScratchGC(pGC);
x = -extents.x1;
y = -extents.y1;
}
else {
x = 0;
y = 0;
}
buffer.count = 0;
buffer.mask = NULL;
while (nlist--) {
x += list->xOff;
y += list->yOff;
n = list->len;
while (n--) {
glyph = *glyphs++;
if (glyph->info.width > 0 && glyph->info.height > 0) {
/* pGlyph->info.{x,y} compensate for empty space in the glyph. */
if (maskFormat) {
if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x - glyph->info.x,
y - glyph->info.y) ==
ExaGlyphNeedFlush) {
exaGlyphsToMask(pMask, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x - glyph->info.x,
y - glyph->info.y);
}
}
else {
if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + (x - glyph->info.x) - first_xOff,
ySrc + (y - glyph->info.y) - first_yOff,
0, 0, x - glyph->info.x,
y - glyph->info.y)
== ExaGlyphNeedFlush) {
exaGlyphsToDst(op, pSrc, pDst, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + (x - glyph->info.x) - first_xOff,
ySrc + (y - glyph->info.y) - first_yOff,
0, 0, x - glyph->info.x,
y - glyph->info.y);
}
}
}
x += glyph->info.xOff;
y += glyph->info.yOff;
}
list++;
}
if (buffer.count) {
if (maskFormat)
exaGlyphsToMask(pMask, &buffer);
else
exaGlyphsToDst(op, pSrc, pDst, &buffer);
}
if (maskFormat) {
x = extents.x1;
y = extents.y1;
CompositePicture(op,
pSrc,
pMask,
pDst,
xSrc + x - first_xOff,
ySrc + y - first_yOff, 0, 0, x, y, width, height);
FreePicture((void *) pMask, (XID) 0);
(*pScreen->DestroyPixmap) (pMaskPixmap);
}
}

761
exa/exa_migration_classic.c Normal file
View File

@ -0,0 +1,761 @@
/*
* Copyright © 2006 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Michel Dänzer <michel@tungstengraphics.com>
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
#if DEBUG_MIGRATE
#define DBG_MIGRATE(a) ErrorF a
#else
#define DBG_MIGRATE(a)
#endif
/**
* The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
* and exaCopyDirtyToFb both needed to do this loop.
*/
static void
exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
CARD8 *dst, int dst_pitch)
{
int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
int bytes = (pbox->x2 - pbox->x1) * cpp;
src += pbox->y1 * src_pitch + pbox->x1 * cpp;
dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
for (i = pbox->y2 - pbox->y1; i; i--) {
memcpy(dst, src, bytes);
src += src_pitch;
dst += dst_pitch;
}
}
/**
* Returns TRUE if the pixmap is dirty (has been modified in its current
* location compared to the other), or lacks a private for tracking
* dirtiness.
*/
static Bool
exaPixmapIsDirty(PixmapPtr pPix)
{
ExaPixmapPriv(pPix);
if (pExaPixmap == NULL)
EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
if (!pExaPixmap->pDamage)
return FALSE;
return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
!RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
}
/**
* Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
* to be considered "should be in framebuffer". That's just anything that has
* had more acceleration than fallbacks, or has no score yet.
*
* Only valid if using a migration scheme that tracks score.
*/
static Bool
exaPixmapShouldBeInFB(PixmapPtr pPix)
{
ExaPixmapPriv(pPix);
if (exaPixmapIsPinned(pPix))
return TRUE;
return pExaPixmap->score >= 0;
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* FB to system or vice versa. Both areas must be allocated.
*/
static void
exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
char *sys, int sys_pitch), int fallback_index,
void (*sync) (ScreenPtr pScreen))
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
RegionRec CopyReg;
Bool save_use_gpu_copy;
int save_pitch;
BoxPtr pBox;
int nbox;
Bool access_prepared = FALSE;
Bool need_sync = FALSE;
/* Damaged bits are valid in current copy but invalid in other one */
if (pExaPixmap->use_gpu_copy) {
RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
}
else {
RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
}
RegionEmpty(damage);
/* Copy bits valid in source but not in destination */
RegionNull(&CopyReg);
RegionSubtract(&CopyReg, pValidSrc, pValidDst);
if (migrate->as_dst) {
ExaScreenPriv(pPixmap->drawable.pScreen);
/* XXX: The pending damage region will be marked as damaged after the
* operation, so it should serve as an upper bound for the region that
* needs to be synchronized for the operation. Unfortunately, this
* causes corruption in some cases, e.g. when starting compiz. See
* https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
*/
if (pExaScr->optimize_migration) {
RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
#if DEBUG_MIGRATE
if (RegionNil(pending_damage)) {
static Bool firsttime = TRUE;
if (firsttime) {
ErrorF("%s: Pending damage region empty!\n", __func__);
firsttime = FALSE;
}
}
#endif
/* Try to prevent destination valid region from growing too many
* rects by filling it up to the extents of the union of the
* destination valid region and the pending damage region.
*/
if (RegionNumRects(pValidDst) > 10) {
BoxRec box;
BoxPtr pValidExt, pDamageExt;
RegionRec closure;
pValidExt = RegionExtents(pValidDst);
pDamageExt = RegionExtents(pending_damage);
box.x1 = min(pValidExt->x1, pDamageExt->x1);
box.y1 = min(pValidExt->y1, pDamageExt->y1);
box.x2 = max(pValidExt->x2, pDamageExt->x2);
box.y2 = max(pValidExt->y2, pDamageExt->y2);
RegionInit(&closure, &box, 0);
RegionIntersect(&CopyReg, &CopyReg, &closure);
}
else
RegionIntersect(&CopyReg, &CopyReg, pending_damage);
}
/* The caller may provide a region to be subtracted from the calculated
* dirty region. This is to avoid migration of bits that don't
* contribute to the result of the operation.
*/
if (migrate->pReg)
RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
}
else {
/* The caller may restrict the region to be migrated for source pixmaps
* to what's relevant for the operation.
*/
if (migrate->pReg)
RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
}
pBox = RegionRects(&CopyReg);
nbox = RegionNumRects(&CopyReg);
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
save_pitch = pPixmap->devKind;
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
while (nbox--) {
pBox->x1 = max(pBox->x1, 0);
pBox->y1 = max(pBox->y1, 0);
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
if (!transfer || !transfer(pPixmap,
pBox->x1, pBox->y1,
pBox->x2 - pBox->x1,
pBox->y2 - pBox->y1,
(char *) (pExaPixmap->sys_ptr
+ pBox->y1 * pExaPixmap->sys_pitch
+
pBox->x1 *
pPixmap->drawable.bitsPerPixel /
8), pExaPixmap->sys_pitch)) {
if (!access_prepared) {
ExaDoPrepareAccess(pPixmap, fallback_index);
access_prepared = TRUE;
}
if (fallback_index == EXA_PREPARE_DEST) {
exaMemcpyBox(pPixmap, pBox,
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
pPixmap->devPrivate.ptr, pPixmap->devKind);
}
else {
exaMemcpyBox(pPixmap, pBox,
pPixmap->devPrivate.ptr, pPixmap->devKind,
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
}
}
else
need_sync = TRUE;
pBox++;
}
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
pPixmap->devKind = save_pitch;
/* Try to prevent source valid region from growing too many rects by
* removing parts of it which are also in the destination valid region.
* Removing anything beyond that would lead to data loss.
*/
if (RegionNumRects(pValidSrc) > 20)
RegionSubtract(pValidSrc, pValidSrc, pValidDst);
/* The copied bits are now valid in destination */
RegionUnion(pValidDst, pValidDst, &CopyReg);
RegionUninit(&CopyReg);
if (access_prepared)
exaFinishAccess(&pPixmap->drawable, fallback_index);
else if (need_sync && sync)
sync(pPixmap->drawable.pScreen);
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* the framebuffer memory copy to the system memory copy. Both areas must be
* allocated.
*/
void
exaCopyDirtyToSys(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv(pPixmap->drawable.pScreen);
ExaPixmapPriv(pPixmap);
exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
exaWaitSync);
}
/**
* If the pixmap is currently dirty, this copies at least the dirty area from
* the system memory copy to the framebuffer memory copy. Both areas must be
* allocated.
*/
void
exaCopyDirtyToFb(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaScreenPriv(pPixmap->drawable.pScreen);
ExaPixmapPriv(pPixmap);
exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
}
/**
* Allocates a framebuffer copy of the pixmap if necessary, and then copies
* any necessary pixmap data into the framebuffer copy and points the pixmap at
* it.
*
* Note that when first allocated, a pixmap will have FALSE dirty flag.
* This is intentional because pixmap data starts out undefined. So if we move
* it in due to the first operation against it being accelerated, it will have
* undefined framebuffer contents that we didn't have to upload. If we do
* moveouts (and moveins) after the first movein, then we will only have to copy
* back and forth if the pixmap was written to after the last synchronization of
* the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
* we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
* all the data, since it's almost surely all valid now.
*/
static void
exaDoMoveInPixmap(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
/* If we're VT-switched away, no touching card memory allowed. */
if (pExaScr->swappedOut)
return;
/* If we're not allowed to move, then fail. */
if (exaPixmapIsPinned(pPixmap))
return;
/* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
* fragility in EXA, and <8bpp is probably not used enough any more to care
* (at least, not in acceleratd paths).
*/
if (pPixmap->drawable.bitsPerPixel < 8)
return;
if (pExaPixmap->accel_blocked)
return;
if (pExaPixmap->area == NULL) {
pExaPixmap->area =
exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
pExaScr->info->pixmapOffsetAlign, FALSE,
exaPixmapSave, (void *) pPixmap);
if (pExaPixmap->area == NULL)
return;
pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
pExaPixmap->area->offset;
}
exaCopyDirtyToFb(migrate);
if (exaPixmapHasGpuCopy(pPixmap))
return;
DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
void
exaMoveInPixmap_classic(PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
.pReg = NULL
};
migrate.pPix = pPixmap;
exaDoMoveInPixmap(&migrate);
}
/**
* Switches the current active location of the pixmap to system memory, copying
* updated data out if necessary.
*/
static void
exaDoMoveOutPixmap(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
return;
exaCopyDirtyToSys(migrate);
if (exaPixmapHasGpuCopy(pPixmap)) {
DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
(void *) (ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
pExaPixmap->use_gpu_copy = FALSE;
pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
}
void
exaMoveOutPixmap_classic(PixmapPtr pPixmap)
{
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
.pReg = NULL
};
migrate.pPix = pPixmap;
exaDoMoveOutPixmap(&migrate);
}
/**
* Copies out important pixmap data and removes references to framebuffer area.
* Called when the memory manager decides it's time to kick the pixmap out of
* framebuffer entirely.
*/
void
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
{
PixmapPtr pPixmap = area->privData;
ExaPixmapPriv(pPixmap);
exaMoveOutPixmap(pPixmap);
pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
* next time */
RegionEmpty(&pExaPixmap->validFB);
}
/**
* For the "greedy" migration scheme, pushes the pixmap toward being located in
* framebuffer memory.
*/
static void
exaMigrateTowardFb(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
(void *) pPixmap));
return;
}
DBG_MIGRATE(("UseScreen %p score %d\n",
(void *) pPixmap, pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
exaDoMoveInPixmap(migrate);
pExaPixmap->score = 0;
}
if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
pExaPixmap->score++;
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
!exaPixmapHasGpuCopy(pPixmap)) {
exaDoMoveInPixmap(migrate);
}
if (exaPixmapHasGpuCopy(pPixmap)) {
exaCopyDirtyToFb(migrate);
ExaOffscreenMarkUsed(pPixmap);
}
else
exaCopyDirtyToSys(migrate);
}
/**
* For the "greedy" migration scheme, pushes the pixmap toward being located in
* system memory.
*/
static void
exaMigrateTowardSys(ExaMigrationPtr migrate)
{
PixmapPtr pPixmap = migrate->pPix;
ExaPixmapPriv(pPixmap);
DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
return;
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
pExaPixmap->score = 0;
if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
pExaPixmap->score--;
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
exaDoMoveOutPixmap(migrate);
if (exaPixmapHasGpuCopy(pPixmap)) {
exaCopyDirtyToFb(migrate);
ExaOffscreenMarkUsed(pPixmap);
}
else
exaCopyDirtyToSys(migrate);
}
/**
* If the pixmap has both a framebuffer and system memory copy, this function
* asserts that both of them are the same.
*/
static Bool
exaAssertNotDirty(PixmapPtr pPixmap)
{
ExaPixmapPriv(pPixmap);
CARD8 *dst, *src;
RegionRec ValidReg;
int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
BoxPtr pBox;
Bool ret = TRUE, save_use_gpu_copy;
if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
return ret;
RegionNull(&ValidReg);
RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
nbox = RegionNumRects(&ValidReg);
if (!nbox)
goto out;
pBox = RegionRects(&ValidReg);
dst_pitch = pExaPixmap->sys_pitch;
src_pitch = pExaPixmap->fb_pitch;
cpp = pPixmap->drawable.bitsPerPixel / 8;
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
save_pitch = pPixmap->devKind;
pExaPixmap->use_gpu_copy = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch;
if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
goto skip;
while (nbox--) {
int rowbytes;
pBox->x1 = max(pBox->x1, 0);
pBox->y1 = max(pBox->y1, 0);
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
rowbytes = (pBox->x2 - pBox->x1) * cpp;
src =
(CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
pBox->x1 * cpp;
dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
for (y = pBox->y1; y < pBox->y2;
y++, src += src_pitch, dst += dst_pitch) {
if (memcmp(dst, src, rowbytes) != 0) {
ret = FALSE;
exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
break;
}
}
}
skip:
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
pPixmap->devKind = save_pitch;
out:
RegionUninit(&ValidReg);
return ret;
}
/**
* Performs migration of the pixmaps according to the operation information
* provided in pixmaps and can_accel and the migration scheme chosen in the
* config file.
*/
void
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
ExaScreenPriv(pScreen);
int i, j;
/* If this debugging flag is set, check each pixmap for whether it is marked
* as clean, and if so, actually check if that's the case. This should help
* catch issues with failing to mark a drawable as dirty. While it will
* catch them late (after the operation happened), it at least explains what
* went wrong, and instrumenting the code to find what operation happened
* to the pixmap last shouldn't be hard.
*/
if (pExaScr->checkDirtyCorrectness) {
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
!exaAssertNotDirty(pixmaps[i].pPix))
ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
__func__, i);
}
}
/* If anything is pinned in system memory, we won't be able to
* accelerate.
*/
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
pixmaps[i].pPix->drawable.width,
pixmaps[i].pPix->drawable.height));
can_accel = FALSE;
break;
}
}
if (pExaScr->migration == ExaMigrationSmart) {
/* If we've got something as a destination that we shouldn't cause to
* become newly dirtied, take the unaccelerated route.
*/
for (i = 0; i < npixmaps; i++) {
if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
!exaPixmapIsDirty(pixmaps[i].pPix)) {
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty(pixmaps[i].pPix))
exaDoMoveOutPixmap(pixmaps + i);
}
return;
}
}
/* If we aren't going to accelerate, then we migrate everybody toward
* system memory, and kick out if it's free.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardSys(pixmaps + i);
if (!exaPixmapIsDirty(pixmaps[i].pPix))
exaDoMoveOutPixmap(pixmaps + i);
}
return;
}
/* Finally, the acceleration path. Move them all in. */
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardFb(pixmaps + i);
exaDoMoveInPixmap(pixmaps + i);
}
}
else if (pExaScr->migration == ExaMigrationGreedy) {
/* If we can't accelerate, either because the driver can't or because one of
* the pixmaps is pinned in system memory, then we migrate everybody toward
* system memory.
*
* We also migrate toward system if all pixmaps involved are currently in
* system memory -- this can mitigate thrashing when there are significantly
* more pixmaps active than would fit in memory.
*
* If not, then we migrate toward FB so that hopefully acceleration can
* happen.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps + i);
return;
}
for (i = 0; i < npixmaps; i++) {
if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
/* Found one in FB, so move all to FB. */
for (j = 0; j < npixmaps; j++)
exaMigrateTowardFb(pixmaps + i);
return;
}
}
/* Nobody's in FB, so move all away from FB. */
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps + i);
}
else if (pExaScr->migration == ExaMigrationAlways) {
/* Always move the pixmaps out if we can't accelerate. If we can
* accelerate, try to move them all in. If that fails, then move them
* back out.
*/
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaDoMoveOutPixmap(pixmaps + i);
return;
}
/* Now, try to move them all into FB */
for (i = 0; i < npixmaps; i++) {
exaDoMoveInPixmap(pixmaps + i);
}
/* If we couldn't fit everything in, abort */
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
return;
}
}
/* Yay, everything has a gpu copy, mark memory as used */
for (i = 0; i < npixmaps; i++) {
ExaOffscreenMarkUsed(pixmaps[i].pPix);
}
}
}
void
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
{
ExaMigrationRec pixmaps[1];
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
}
else {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
}
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = pReg;
exaDoMigration(pixmaps, 1, FALSE);
(void) ExaDoPrepareAccess(pPixmap, index);
}

270
exa/exa_migration_mixed.c Normal file
View File

@ -0,0 +1,270 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* 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.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
void
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
int usage_hint = pPixmap->usage_hint;
int paddedWidth = pExaPixmap->sys_pitch;
/* Already done. */
if (pExaPixmap->driverPriv)
return;
if (exaPixmapIsPinned(pPixmap))
return;
/* Can't accel 1/4 bpp. */
if (pExaPixmap->accel_blocked || bpp < 8)
return;
if (pExaScr->info->CreatePixmap2) {
int new_pitch = 0;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
&new_pitch);
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
}
else {
if (paddedWidth < pExaPixmap->fb_pitch)
paddedWidth = pExaPixmap->fb_pitch;
pExaPixmap->driverPriv =
pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
}
if (!pExaPixmap->driverPriv)
return;
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
}
void
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
int i;
/* If anything is pinned in system memory, we won't be able to
* accelerate.
*/
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
can_accel = FALSE;
break;
}
}
/* We can do nothing. */
if (!can_accel)
return;
for (i = 0; i < npixmaps; i++) {
PixmapPtr pPixmap = pixmaps[i].pPix;
ExaPixmapPriv(pPixmap);
if (!pExaPixmap->driverPriv)
exaCreateDriverPixmap_mixed(pPixmap);
if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
ExaScreenPriv(pPixmap->drawable.pScreen);
/* This pitch is needed for proper acceleration. For some reason
* there are pixmaps without pDamage and a bad fb_pitch value.
* So setting devKind when only exaPixmapHasGpuCopy() is true
* causes corruption. Pixmaps without pDamage are not migrated
* and should have a valid devKind at all times, so that's why this
* isn't causing problems. Pixmaps have their gpu pitch set the
* first time in the MPH call from exaCreateDriverPixmap_mixed().
*/
pPixmap->devKind = pExaPixmap->fb_pitch;
exaCopyDirtyToFb(pixmaps + i);
if (pExaScr->deferred_mixed_pixmap == pPixmap &&
!pixmaps[i].as_dst && !pixmaps[i].pReg)
pExaScr->deferred_mixed_pixmap = NULL;
}
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
}
}
void
exaMoveInPixmap_mixed(PixmapPtr pPixmap)
{
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = NULL;
exaDoMigration(pixmaps, 1, TRUE);
}
void
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
{
PixmapPtr pPixmap = closure;
ExaPixmapPriv(pPixmap);
/* Move back results of software rendering on system memory copy of mixed driver
* pixmap (see exaPrepareAccessReg_mixed).
*
* Defer moving the destination back into the driver pixmap, to try and save
* overhead on multiple subsequent software fallbacks.
*/
if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
ExaScreenPriv(pPixmap->drawable.pScreen);
if (pExaScr->deferred_mixed_pixmap &&
pExaScr->deferred_mixed_pixmap != pPixmap)
exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
pExaScr->deferred_mixed_pixmap = pPixmap;
}
}
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
* use the DownloadFromScreen hook to retrieve contents to a copy in system
* memory, perform software rendering on that and move back the results with the
* UploadToScreen hook (see exaDamageReport_mixed).
*/
void
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
{
ExaPixmapPriv(pPixmap);
Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
Bool success;
success = ExaDoPrepareAccess(pPixmap, index);
if (success && has_gpu_copy && pExaPixmap->pDamage) {
/* You cannot do accelerated operations while a buffer is mapped. */
exaFinishAccess(&pPixmap->drawable, index);
/* Update the gpu view of both deferred destination pixmaps and of
* source pixmaps that were migrated with a bounding region.
*/
exaMoveInPixmap_mixed(pPixmap);
success = ExaDoPrepareAccess(pPixmap, index);
if (success) {
/* We have a gpu pixmap that can be accessed, we don't need the cpu
* copy anymore. Drivers that prefer DFS, should fail prepare
* access.
*/
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
return;
}
}
if (!success) {
ExaMigrationRec pixmaps[1];
/* Do we need to allocate our system buffer? */
if (!pExaPixmap->sys_ptr) {
pExaPixmap->sys_ptr = xallocarray(pExaPixmap->sys_pitch,
pPixmap->drawable.height);
if (!pExaPixmap->sys_ptr)
FatalError("EXA: malloc failed for size %d bytes\n",
pExaPixmap->sys_pitch * pPixmap->drawable.height);
}
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
}
else {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
}
pixmaps[0].pPix = pPixmap;
pixmaps[0].pReg = pReg;
if (!pExaPixmap->pDamage &&
(has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
Bool as_dst = pixmaps[0].as_dst;
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
DamageReportNonEmpty, TRUE,
pPixmap->drawable.pScreen,
pPixmap);
if (pExaPixmap->pDamage) {
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current
* operation. This is used by exa to optimize migration.
*/
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
}
if (has_gpu_copy) {
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
pPixmap->drawable.height);
/* We don't know which region of the destination will be damaged,
* have to assume all of it
*/
if (as_dst) {
pixmaps[0].as_dst = FALSE;
pixmaps[0].as_src = TRUE;
pixmaps[0].pReg = NULL;
}
exaCopyDirtyToSys(pixmaps);
}
if (as_dst)
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
pPixmap->drawable.height);
}
else if (has_gpu_copy)
exaCopyDirtyToSys(pixmaps);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
pExaPixmap->use_gpu_copy = FALSE;
}
}

330
exa/exa_mixed.c Normal file
View File

@ -0,0 +1,330 @@
/*
* Copyright © 2009 Maarten Maathuis
*
* 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.
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include "exa.h"
/* This file holds the driver allocated pixmaps + better initial placement code.
*/
static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)
{
ExaPixmapPriv(p);
return pExaPixmap->sys_ptr;
}
/**
* exaCreatePixmap() creates a new pixmap.
*/
PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
ExaPixmapPrivPtr pExaPixmap;
int bpp;
size_t paddedWidth;
ExaScreenPriv(pScreen);
if (w > 32767 || h > 32767)
return NullPixmap;
swap(pExaScr, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
swap(pExaScr, pScreen, CreatePixmap);
if (!pPixmap)
return NULL;
pExaPixmap = ExaGetPixmapPriv(pPixmap);
pExaPixmap->driverPriv = NULL;
bpp = pPixmap->drawable.bitsPerPixel;
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
if (paddedWidth / 4 > 32767 || h > 32767)
return NullPixmap;
/* We will allocate the system pixmap later if needed. */
pPixmap->devPrivate.ptr = NULL;
pExaPixmap->sys_ptr = NULL;
pExaPixmap->sys_pitch = paddedWidth;
pExaPixmap->area = NULL;
pExaPixmap->fb_ptr = NULL;
pExaPixmap->pDamage = NULL;
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
/* A scratch pixmap will become a driver pixmap right away. */
if (!w || !h) {
exaCreateDriverPixmap_mixed(pPixmap);
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
}
else {
pExaPixmap->use_gpu_copy = FALSE;
if (w == 1 && h == 1) {
pExaPixmap->sys_ptr = malloc(paddedWidth);
/* Set up damage tracking */
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
DamageReportNonEmpty, TRUE,
pPixmap->drawable.pScreen,
pPixmap);
if (pExaPixmap->pDamage) {
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
/* This ensures that pending damage reflects the current
* operation. This is used by exa to optimize migration.
*/
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
}
}
}
/* During a fallback we must prepare access. */
if (pExaScr->fallback_counter)
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
return pPixmap;
}
Bool
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, void *pPixData)
{
ScreenPtr pScreen;
ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap;
Bool ret, has_gpu_copy;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pPixData) {
if (pExaPixmap->driverPriv) {
if (pExaPixmap->pDamage) {
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
}
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
}
pExaPixmap->use_gpu_copy = FALSE;
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
}
has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
if (width <= 0)
width = pPixmap->drawable.width;
if (height <= 0)
height = pPixmap->drawable.height;
if (bitsPerPixel <= 0) {
if (depth <= 0)
bitsPerPixel = pPixmap->drawable.bitsPerPixel;
else
bitsPerPixel = BitsPerPixel(depth);
}
if (depth <= 0)
depth = pPixmap->drawable.depth;
if (width != pPixmap->drawable.width ||
height != pPixmap->drawable.height ||
depth != pPixmap->drawable.depth ||
bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
if (pExaPixmap->driverPriv) {
if (devKind > 0)
pExaPixmap->fb_pitch = devKind;
else
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
RegionEmpty(&pExaPixmap->validFB);
}
/* Need to re-create system copy if there's also a GPU copy */
if (has_gpu_copy) {
if (pExaPixmap->sys_ptr) {
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL;
RegionEmpty(&pExaPixmap->validSys);
if (pExaScr->deferred_mixed_pixmap == pPixmap)
pExaScr->deferred_mixed_pixmap = NULL;
}
pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
}
}
if (has_gpu_copy) {
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
pPixmap->devKind = pExaPixmap->fb_pitch;
}
else {
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
}
/* Only pass driver pixmaps to the driver. */
if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind,
pPixData);
if (ret == TRUE)
goto out;
}
swap(pExaScr, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
swap(pExaScr, pScreen, ModifyPixmapHeader);
out:
if (has_gpu_copy) {
pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->fb_pitch = pPixmap->devKind;
}
else {
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
pExaPixmap->sys_pitch = pPixmap->devKind;
}
/* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL;
return ret;
}
Bool
exaDestroyPixmap_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret;
if (pPixmap->refcnt == 1) {
ExaPixmapPriv(pPixmap);
exaDestroyPixmap(pPixmap);
if (pExaScr->deferred_mixed_pixmap == pPixmap)
pExaScr->deferred_mixed_pixmap = NULL;
if (pExaPixmap->driverPriv)
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
if (pExaPixmap->pDamage) {
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL;
pExaPixmap->pDamage = NULL;
}
}
swap(pExaScr, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
swap(pExaScr, pScreen, DestroyPixmap);
return ret;
}
Bool
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap);
void *saved_ptr;
Bool ret;
if (!pExaPixmap->driverPriv)
return FALSE;
saved_ptr = pPixmap->devPrivate.ptr;
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
pPixmap->devPrivate.ptr = saved_ptr;
return ret;
}
Bool
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret = FALSE;
exaMoveInPixmap(pPixmap);
/* get the driver to give us a handle */
if (pExaScr->info->SharePixmapBacking)
ret = pExaScr->info->SharePixmapBacking(pPixmap, secondary, handle_p);
return ret;
}
Bool
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen);
Bool ret = FALSE;
if (pExaScr->info->SetSharedPixmapBacking)
ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
if (ret == TRUE)
exaMoveInPixmap(pPixmap);
return ret;
}

677
exa/exa_offscreen.c Normal file
View File

@ -0,0 +1,677 @@
/*
* Copyright © 2003 Anders Carlsson
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Anders Carlsson not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Anders Carlsson makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/** @file
* This allocator allocates blocks of memory by maintaining a list of areas.
* When allocating, the contiguous block of areas with the minimum eviction
* cost is found and evicted in order to make room for the new allocation.
*/
#include "exa_priv.h"
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#if DEBUG_OFFSCREEN
#define DBG_OFFSCREEN(a) ErrorF a
#else
#define DBG_OFFSCREEN(a)
#endif
#if DEBUG_OFFSCREEN
static void
ExaOffscreenValidate(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *prev = 0, *area;
assert(pExaScr->info->offScreenAreas->base_offset ==
pExaScr->info->offScreenBase);
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
assert(area->offset >= area->base_offset);
assert(area->offset < (area->base_offset + area->size));
if (prev)
assert(prev->base_offset + prev->size == area->base_offset);
prev = area;
}
assert(prev->base_offset + prev->size == pExaScr->info->memorySize);
}
#else
#define ExaOffscreenValidate(s)
#endif
static ExaOffscreenArea *
ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area)
{
if (area->save)
(*area->save) (pScreen, area);
return exaOffscreenFree(pScreen, area);
}
static void
exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter)
{
unsigned age;
if (area->state == ExaOffscreenAvail)
return;
age = offScreenCounter - area->last_use;
/* This is unlikely to happen, but could result in a division by zero... */
if (age > (UINT_MAX / 2)) {
age = UINT_MAX / 2;
area->last_use = offScreenCounter - age;
}
area->eviction_cost = area->size / age;
}
static ExaOffscreenArea *
exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align)
{
ExaOffscreenArea *begin, *end, *best;
unsigned cost, best_cost;
int avail, real_size;
best_cost = UINT_MAX;
begin = end = pExaScr->info->offScreenAreas;
avail = 0;
cost = 0;
best = 0;
while (end != NULL) {
restart:
while (begin != NULL && begin->state == ExaOffscreenLocked)
begin = end = begin->next;
if (begin == NULL)
break;
/* adjust size needed to account for alignment loss for this area */
real_size = size + (begin->base_offset + begin->size - size) % align;
while (avail < real_size && end != NULL) {
if (end->state == ExaOffscreenLocked) {
/* Can't more room here, restart after this locked area */
avail = 0;
cost = 0;
begin = end;
goto restart;
}
avail += end->size;
exaUpdateEvictionCost(end, pExaScr->offScreenCounter);
cost += end->eviction_cost;
end = end->next;
}
/* Check the cost, update best */
if (avail >= real_size && cost < best_cost) {
best = begin;
best_cost = cost;
}
avail -= begin->size;
cost -= begin->eviction_cost;
begin = begin->next;
}
return best;
}
/**
* exaOffscreenAlloc allocates offscreen memory
*
* @param pScreen current screen
* @param size size in bytes of the allocation
* @param align byte alignment requirement for the offset of the allocated area
* @param locked whether the allocated area is locked and can't be kicked out
* @param save callback for when the area is evicted from memory
* @param privdata private data for the save callback.
*
* Allocates offscreen memory from the device associated with pScreen. size
* and align determine where and how large the allocated area is, and locked
* will mark whether it should be held in card memory. privdata may be any
* pointer for the save callback when the area is removed.
*
* Note that locked areas do get evicted on VT switch unless the driver
* requested version 2.1 or newer behavior. In that case, the save callback is
* still called.
*/
ExaOffscreenArea *
exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
Bool locked, ExaOffscreenSaveProc save, void *privData)
{
ExaOffscreenArea *area;
ExaScreenPriv(pScreen);
int real_size = 0, largest_avail = 0;
#if DEBUG_OFFSCREEN
static int number = 0;
ErrorF("================= ============ allocating a new pixmap %d\n",
++number);
#endif
ExaOffscreenValidate(pScreen);
if (!align)
align = 1;
if (!size) {
DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size));
return NULL;
}
/* throw out requests that cannot fit */
if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) {
DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
pExaScr->info->memorySize -
pExaScr->info->offScreenBase));
return NULL;
}
/* Try to find a free space that'll fit. */
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
/* skip allocated areas */
if (area->state != ExaOffscreenAvail)
continue;
/* adjust size to match alignment requirement */
real_size = size + (area->base_offset + area->size - size) % align;
/* does it fit? */
if (real_size <= area->size)
break;
if (area->size > largest_avail)
largest_avail = area->size;
}
if (!area) {
area = exaFindAreaToEvict(pExaScr, size, align);
if (!area) {
DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size));
/* Could not allocate memory */
ExaOffscreenValidate(pScreen);
return NULL;
}
/* adjust size needed to account for alignment loss for this area */
real_size = size + (area->base_offset + area->size - size) % align;
/*
* Kick out first area if in use
*/
if (area->state != ExaOffscreenAvail)
area = ExaOffscreenKickOut(pScreen, area);
/*
* Now get the system to merge the other needed areas together
*/
while (area->size < real_size) {
assert(area->next);
assert(area->next->state == ExaOffscreenRemovable);
(void) ExaOffscreenKickOut(pScreen, area->next);
}
}
/* save extra space in new area */
if (real_size < area->size) {
ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea));
if (!new_area)
return NULL;
new_area->base_offset = area->base_offset;
new_area->offset = new_area->base_offset;
new_area->align = 0;
new_area->size = area->size - real_size;
new_area->state = ExaOffscreenAvail;
new_area->save = NULL;
new_area->last_use = 0;
new_area->eviction_cost = 0;
new_area->next = area;
new_area->prev = area->prev;
if (area->prev->next)
area->prev->next = new_area;
else
pExaScr->info->offScreenAreas = new_area;
area->prev = new_area;
area->base_offset = new_area->base_offset + new_area->size;
area->size = real_size;
}
else
pExaScr->numOffscreenAvailable--;
/*
* Mark this area as in use
*/
if (locked)
area->state = ExaOffscreenLocked;
else
area->state = ExaOffscreenRemovable;
area->privData = privData;
area->save = save;
area->last_use = pExaScr->offScreenCounter++;
area->offset = (area->base_offset + align - 1);
area->offset -= area->offset % align;
area->align = align;
ExaOffscreenValidate(pScreen);
DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size,
area->base_offset, area->offset));
return area;
}
/**
* Ejects all offscreen areas, and uninitializes the offscreen memory manager.
*/
void
ExaOffscreenSwapOut(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenValidate(pScreen);
/* loop until a single free area spans the space */
for (;;) {
ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
if (!area)
break;
if (area->state == ExaOffscreenAvail) {
area = area->next;
if (!area)
break;
}
assert(area->state != ExaOffscreenAvail);
(void) ExaOffscreenKickOut(pScreen, area);
ExaOffscreenValidate(pScreen);
}
ExaOffscreenValidate(pScreen);
ExaOffscreenFini(pScreen);
}
/** Ejects all pixmaps managed by EXA. */
static void
ExaOffscreenEjectPixmaps(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenValidate(pScreen);
/* loop until a single free area spans the space */
for (;;) {
ExaOffscreenArea *area;
for (area = pExaScr->info->offScreenAreas; area != NULL;
area = area->next) {
if (area->state == ExaOffscreenRemovable &&
area->save == exaPixmapSave) {
(void) ExaOffscreenKickOut(pScreen, area);
ExaOffscreenValidate(pScreen);
break;
}
}
if (area == NULL)
break;
}
ExaOffscreenValidate(pScreen);
}
void
ExaOffscreenSwapIn(ScreenPtr pScreen)
{
exaOffscreenInit(pScreen);
}
/**
* Prepares EXA for disabling of FB access, or restoring it.
*
* In version 2.1, the disabling results in pixmaps being ejected, while other
* allocations remain. With this plus the prevention of migration while
* swappedOut is set, EXA by itself should not cause any access of the
* framebuffer to occur while swapped out. Any remaining issues are the
* responsibility of the driver.
*
* Prior to version 2.1, all allocations, including locked ones, are ejected
* when access is disabled, and the allocator is torn down while swappedOut
* is set. This is more drastic, and caused implementation difficulties for
* many drivers that could otherwise handle the lack of FB access while
* swapped out.
*/
void
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable)
{
ExaScreenPriv(pScreen);
if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
return;
if (!enable && pExaScr->disableFbCount++ == 0) {
if (pExaScr->info->exa_minor < 1)
ExaOffscreenSwapOut(pScreen);
else
ExaOffscreenEjectPixmaps(pScreen);
pExaScr->swappedOut = TRUE;
}
if (enable && --pExaScr->disableFbCount == 0) {
if (pExaScr->info->exa_minor < 1)
ExaOffscreenSwapIn(pScreen);
pExaScr->swappedOut = FALSE;
}
}
/* merge the next free area into this one */
static void
ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area)
{
ExaOffscreenArea *next = area->next;
/* account for space */
area->size += next->size;
/* frob pointer */
area->next = next->next;
if (area->next)
area->next->prev = area;
else
pExaScr->info->offScreenAreas->prev = area;
free(next);
pExaScr->numOffscreenAvailable--;
}
/**
* exaOffscreenFree frees an allocation.
*
* @param pScreen current screen
* @param area offscreen area to free
*
* exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that
* the save callback of the area is not called, and it is up to the driver to
* do any cleanup necessary as a result.
*
* @return pointer to the newly freed area. This behavior should not be relied
* on.
*/
ExaOffscreenArea *
exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *next = area->next;
ExaOffscreenArea *prev;
DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size,
area->base_offset, area->offset));
ExaOffscreenValidate(pScreen);
area->state = ExaOffscreenAvail;
area->save = NULL;
area->last_use = 0;
area->eviction_cost = 0;
/*
* Find previous area
*/
if (area == pExaScr->info->offScreenAreas)
prev = NULL;
else
prev = area->prev;
pExaScr->numOffscreenAvailable++;
/* link with next area if free */
if (next && next->state == ExaOffscreenAvail)
ExaOffscreenMerge(pExaScr, area);
/* link with prev area if free */
if (prev && prev->state == ExaOffscreenAvail) {
area = prev;
ExaOffscreenMerge(pExaScr, area);
}
ExaOffscreenValidate(pScreen);
DBG_OFFSCREEN(("\tdone freeing\n"));
return area;
}
void
ExaOffscreenMarkUsed(PixmapPtr pPixmap)
{
ExaPixmapPriv(pPixmap);
ExaScreenPriv(pPixmap->drawable.pScreen);
if (!pExaPixmap || !pExaPixmap->area)
return;
pExaPixmap->area->last_use = pExaScr->offScreenCounter++;
}
/**
* Defragment offscreen memory by compacting allocated areas at the end of it,
* leaving the total amount of memory available as a single area at the
* beginning (when there are no pinned allocations).
*/
_X_HIDDEN ExaOffscreenArea *
ExaOffscreenDefragment(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area, *largest_available = NULL;
int largest_size = 0;
PixmapPtr pDstPix;
ExaPixmapPrivPtr pExaDstPix;
pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0);
if (!pDstPix)
return NULL;
pExaDstPix = ExaGetPixmapPriv(pDstPix);
pExaDstPix->use_gpu_copy = TRUE;
for (area = pExaScr->info->offScreenAreas->prev;
area != pExaScr->info->offScreenAreas;) {
ExaOffscreenArea *prev = area->prev;
PixmapPtr pSrcPix;
ExaPixmapPrivPtr pExaSrcPix;
Bool save_use_gpu_copy;
int save_pitch;
if (area->state != ExaOffscreenAvail ||
prev->state == ExaOffscreenLocked ||
(prev->state == ExaOffscreenRemovable &&
prev->save != exaPixmapSave)) {
area = prev;
continue;
}
if (prev->state == ExaOffscreenAvail) {
if (area == largest_available) {
largest_available = prev;
largest_size += prev->size;
}
area = prev;
ExaOffscreenMerge(pExaScr, area);
continue;
}
if (area->size > largest_size) {
largest_available = area;
largest_size = area->size;
}
pSrcPix = prev->privData;
pExaSrcPix = ExaGetPixmapPriv(pSrcPix);
pExaDstPix->fb_ptr = pExaScr->info->memoryBase +
area->base_offset + area->size - prev->size + prev->base_offset -
prev->offset;
pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align;
if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) {
area = prev;
continue;
}
if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) &&
(pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) {
area = prev;
continue;
}
save_use_gpu_copy = pExaSrcPix->use_gpu_copy;
save_pitch = pSrcPix->devKind;
pExaSrcPix->use_gpu_copy = TRUE;
pSrcPix->devKind = pExaSrcPix->fb_pitch;
pDstPix->drawable.width = pSrcPix->drawable.width;
pDstPix->devKind = pSrcPix->devKind;
pDstPix->drawable.height = pSrcPix->drawable.height;
pDstPix->drawable.depth = pSrcPix->drawable.depth;
pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel;
if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) {
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
pSrcPix->devKind = save_pitch;
area = prev;
continue;
}
pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width,
pDstPix->drawable.height);
pExaScr->info->DoneCopy(pDstPix);
exaMarkSync(pScreen);
DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size));
/* Calculate swapped area offsets and sizes */
area->base_offset = prev->base_offset;
area->offset = area->base_offset;
prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr;
assert(prev->offset >= pExaScr->info->offScreenBase);
assert(prev->offset < pExaScr->info->memorySize);
prev->base_offset = prev->offset;
if (area->next)
prev->size = area->next->base_offset - prev->base_offset;
else
prev->size = pExaScr->info->memorySize - prev->base_offset;
area->size = prev->base_offset - area->base_offset;
DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size));
/* Swap areas in list */
if (area->next)
area->next->prev = prev;
else
pExaScr->info->offScreenAreas->prev = prev;
if (prev->prev->next)
prev->prev->next = area;
else
pExaScr->info->offScreenAreas = area;
prev->next = area->next;
area->next = prev;
area->prev = prev->prev;
prev->prev = area;
if (!area->prev->next)
pExaScr->info->offScreenAreas = area;
#if DEBUG_OFFSCREEN
if (prev->prev == prev || prev->next == prev)
ErrorF("Whoops, prev points to itself!\n");
if (area->prev == area || area->next == area)
ErrorF("Whoops, area points to itself!\n");
#endif
pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr;
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
pSrcPix->devKind = save_pitch;
}
pDstPix->drawable.width = 0;
pDstPix->drawable.height = 0;
pDstPix->drawable.depth = 0;
pDstPix->drawable.bitsPerPixel = 0;
(*pScreen->DestroyPixmap) (pDstPix);
if (area->state == ExaOffscreenAvail && area->size > largest_size)
return area;
return largest_available;
}
/**
* exaOffscreenInit initializes the offscreen memory manager.
*
* @param pScreen current screen
*
* exaOffscreenInit is called by exaDriverInit to set up the memory manager for
* the screen, if any offscreen memory is available.
*/
Bool
exaOffscreenInit(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area;
/* Allocate a big free area */
area = malloc(sizeof(ExaOffscreenArea));
if (!area)
return FALSE;
area->state = ExaOffscreenAvail;
area->base_offset = pExaScr->info->offScreenBase;
area->offset = area->base_offset;
area->align = 0;
area->size = pExaScr->info->memorySize - area->base_offset;
area->save = NULL;
area->next = NULL;
area->prev = area;
area->last_use = 0;
area->eviction_cost = 0;
/* Add it to the free areas */
pExaScr->info->offScreenAreas = area;
pExaScr->offScreenCounter = 1;
pExaScr->numOffscreenAvailable = 1;
ExaOffscreenValidate(pScreen);
return TRUE;
}
void
ExaOffscreenFini(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
ExaOffscreenArea *area;
/* just free all of the area records */
while ((area = pExaScr->info->offScreenAreas)) {
pExaScr->info->offScreenAreas = area->next;
free(area);
}
}

735
exa/exa_priv.h Normal file
View File

@ -0,0 +1,735 @@
/*
*
* Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Zack Rusin, Trolltech
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#ifndef EXAPRIV_H
#define EXAPRIV_H
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "exa.h"
#include <X11/X.h>
#include <X11/Xproto.h>
#ifdef MITSHM
#include "shmint.h"
#endif
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "servermd.h"
#include "colormapst.h"
#include "gcstruct.h"
#include "input.h"
#include "mipointer.h"
#include "mi.h"
#include "dix.h"
#include "fb.h"
#include "fboverlay.h"
#include "fbpict.h"
#include "glyphstr.h"
#include "damage.h"
#define DEBUG_TRACE_FALL 0
#define DEBUG_MIGRATE 0
#define DEBUG_PIXMAP 0
#define DEBUG_OFFSCREEN 0
#define DEBUG_GLYPH_CACHE 0
#if DEBUG_TRACE_FALL
#define EXA_FALLBACK(x) \
do { \
ErrorF("EXA fallback at %s: ", __FUNCTION__); \
ErrorF x; \
} while (0)
char
exaDrawableLocation(DrawablePtr pDrawable);
#else
#define EXA_FALLBACK(x)
#endif
#if DEBUG_PIXMAP
#define DBG_PIXMAP(a) ErrorF a
#else
#define DBG_PIXMAP(a)
#endif
#ifndef EXA_MAX_FB
#define EXA_MAX_FB FB_OVERLAY_MAX
#endif
#ifdef DEBUG
#define EXA_FatalErrorDebug(x) FatalError x
#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x
#else
#define EXA_FatalErrorDebug(x) ErrorF x
#define EXA_FatalErrorDebugWithRet(x, ret) \
do { \
ErrorF x; \
return ret; \
} while (0)
#endif
/**
* This is the list of migration heuristics supported by EXA. See
* exaDoMigration() for what their implementations do.
*/
enum ExaMigrationHeuristic {
ExaMigrationGreedy,
ExaMigrationAlways,
ExaMigrationSmart
};
typedef struct {
unsigned char sha1[20];
} ExaCachedGlyphRec, *ExaCachedGlyphPtr;
typedef struct {
/* The identity of the cache, statically configured at initialization */
unsigned int format;
int glyphWidth;
int glyphHeight;
int size; /* Size of cache; eventually this should be dynamically determined */
/* Hash table mapping from glyph sha1 to position in the glyph; we use
* open addressing with a hash table size determined based on size and large
* enough so that we always have a good amount of free space, so we can
* use linear probing. (Linear probing is preferable to double hashing
* here because it allows us to easily remove entries.)
*/
int *hashEntries;
int hashSize;
ExaCachedGlyphPtr glyphs;
int glyphCount; /* Current number of glyphs */
PicturePtr picture; /* Where the glyphs of the cache are stored */
int yOffset; /* y location within the picture where the cache starts */
int columns; /* Number of columns the glyphs are laid out in */
int evictionPosition; /* Next random position to evict a glyph */
} ExaGlyphCacheRec, *ExaGlyphCachePtr;
#define EXA_NUM_GLYPH_CACHES 4
#define EXA_FALLBACK_COPYWINDOW (1 << 0)
#define EXA_ACCEL_COPYWINDOW (1 << 1)
typedef struct _ExaMigrationRec {
Bool as_dst;
Bool as_src;
PixmapPtr pPix;
RegionPtr pReg;
} ExaMigrationRec, *ExaMigrationPtr;
typedef void (*EnableDisableFBAccessProcPtr) (ScreenPtr, Bool);
typedef struct {
ExaDriverPtr info;
ScreenBlockHandlerProcPtr SavedBlockHandler;
ScreenWakeupHandlerProcPtr SavedWakeupHandler;
CreateGCProcPtr SavedCreateGC;
CloseScreenProcPtr SavedCloseScreen;
GetImageProcPtr SavedGetImage;
GetSpansProcPtr SavedGetSpans;
CreatePixmapProcPtr SavedCreatePixmap;
DestroyPixmapProcPtr SavedDestroyPixmap;
CopyWindowProcPtr SavedCopyWindow;
ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
BitmapToRegionProcPtr SavedBitmapToRegion;
CreateScreenResourcesProcPtr SavedCreateScreenResources;
ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader;
SharePixmapBackingProcPtr SavedSharePixmapBacking;
SetSharedPixmapBackingProcPtr SavedSetSharedPixmapBacking;
SourceValidateProcPtr SavedSourceValidate;
CompositeProcPtr SavedComposite;
TrianglesProcPtr SavedTriangles;
GlyphsProcPtr SavedGlyphs;
TrapezoidsProcPtr SavedTrapezoids;
AddTrapsProcPtr SavedAddTraps;
void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps,
Bool can_accel);
Bool (*pixmap_has_gpu_copy) (PixmapPtr pPixmap);
void (*do_move_in_pixmap) (PixmapPtr pPixmap);
void (*do_move_out_pixmap) (PixmapPtr pPixmap);
void (*prepare_access_reg) (PixmapPtr pPixmap, int index, RegionPtr pReg);
Bool swappedOut;
enum ExaMigrationHeuristic migration;
Bool checkDirtyCorrectness;
unsigned disableFbCount;
Bool optimize_migration;
unsigned offScreenCounter;
unsigned numOffscreenAvailable;
CARD32 lastDefragment;
CARD32 nextDefragment;
PixmapPtr deferred_mixed_pixmap;
/* Reference counting for accessed pixmaps */
struct {
PixmapPtr pixmap;
int count;
Bool retval;
} access[EXA_NUM_PREPARE_INDICES];
/* Holds information on fallbacks that cannot be relayed otherwise. */
unsigned int fallback_flags;
unsigned int fallback_counter;
ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES];
/**
* Regions affected by fallback composite source / mask operations.
*/
RegionRec srcReg;
RegionRec maskReg;
PixmapPtr srcPix;
PixmapPtr maskPix;
DevPrivateKeyRec pixmapPrivateKeyRec;
DevPrivateKeyRec gcPrivateKeyRec;
} ExaScreenPrivRec, *ExaScreenPrivPtr;
extern DevPrivateKeyRec exaScreenPrivateKeyRec;
#define exaScreenPrivateKey (&exaScreenPrivateKeyRec)
#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivate(&(s)->devPrivates, exaScreenPrivateKey))
#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
#define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixGetPrivateAddr(&(gc)->devPrivates, &ExaGetScreenPriv(gc->pScreen)->gcPrivateKeyRec))
#define ExaGCPriv(gc) ExaGCPrivPtr pExaGC = ExaGetGCPriv(gc)
/*
* Some macros to deal with function wrapping.
*/
#define wrap(priv, real, mem, func) {\
priv->Saved##mem = real->mem; \
real->mem = func; \
}
#define unwrap(priv, real, mem) {\
real->mem = priv->Saved##mem; \
}
#ifdef HAVE_TYPEOF
#define swap(priv, real, mem) {\
typeof(real->mem) tmp = priv->Saved##mem; \
priv->Saved##mem = real->mem; \
real->mem = tmp; \
}
#else
#define swap(priv, real, mem) {\
const void *tmp = priv->Saved##mem; \
priv->Saved##mem = real->mem; \
real->mem = tmp; \
}
#endif
#define EXA_PRE_FALLBACK(_screen_) \
ExaScreenPriv(_screen_); \
pExaScr->fallback_counter++;
#define EXA_POST_FALLBACK(_screen_) \
pExaScr->fallback_counter--;
#define EXA_PRE_FALLBACK_GC(_gc_) \
ExaScreenPriv(_gc_->pScreen); \
ExaGCPriv(_gc_); \
pExaScr->fallback_counter++; \
swap(pExaGC, _gc_, ops);
#define EXA_POST_FALLBACK_GC(_gc_) \
pExaScr->fallback_counter--; \
swap(pExaGC, _gc_, ops);
/** Align an offset to an arbitrary alignment */
#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
(((offset) + (align) - 1) % (align)))
/** Align an offset to a power-of-two alignment */
#define EXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
#define EXA_PIXMAP_SCORE_MOVE_IN 10
#define EXA_PIXMAP_SCORE_MAX 20
#define EXA_PIXMAP_SCORE_MOVE_OUT -10
#define EXA_PIXMAP_SCORE_MIN -20
#define EXA_PIXMAP_SCORE_PINNED 1000
#define EXA_PIXMAP_SCORE_INIT 1001
#define ExaGetPixmapPriv(p) ((ExaPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &ExaGetScreenPriv((p)->drawable.pScreen)->pixmapPrivateKeyRec))
#define ExaPixmapPriv(p) ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv(p)
#define EXA_RANGE_PITCH (1 << 0)
#define EXA_RANGE_WIDTH (1 << 1)
#define EXA_RANGE_HEIGHT (1 << 2)
typedef struct {
ExaOffscreenArea *area;
int score; /**< score for the move-in vs move-out heuristic */
Bool use_gpu_copy;
CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */
int sys_pitch; /**< pitch of pixmap in system memory */
CARD8 *fb_ptr; /**< pointer to pixmap data in framebuffer memory */
int fb_pitch; /**< pitch of pixmap in framebuffer memory */
unsigned int fb_size; /**< size of pixmap in framebuffer memory */
/**
* Holds information about whether this pixmap can be used for
* acceleration (== 0) or not (> 0).
*
* Contains a OR'ed combination of the following values:
* EXA_RANGE_PITCH - set if the pixmap's pitch is out of range
* EXA_RANGE_WIDTH - set if the pixmap's width is out of range
* EXA_RANGE_HEIGHT - set if the pixmap's height is out of range
*/
unsigned int accel_blocked;
/**
* The damage record contains the areas of the pixmap's current location
* (framebuffer or system) that have been damaged compared to the other
* location.
*/
DamagePtr pDamage;
/**
* The valid regions mark the valid bits (at least, as they're derived from
* damage, which may be overreported) of a pixmap's system and FB copies.
*/
RegionRec validSys, validFB;
/**
* Driver private storage per EXA pixmap
*/
void *driverPriv;
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
typedef struct {
/* GC values from the layer below. */
const GCOps *Savedops;
const GCFuncs *Savedfuncs;
} ExaGCPrivRec, *ExaGCPrivPtr;
typedef struct {
PicturePtr pDst;
INT16 xSrc;
INT16 ySrc;
INT16 xMask;
INT16 yMask;
INT16 xDst;
INT16 yDst;
INT16 width;
INT16 height;
} ExaCompositeRectRec, *ExaCompositeRectPtr;
/**
* exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
* to set EXA options or hook in screen functions to handle using EXA as the AA.
*/
void exaDDXDriverInit(ScreenPtr pScreen);
/* exa_unaccel.c */
void
exaPrepareAccessGC(GCPtr pGC);
void
exaFinishAccessGC(GCPtr pGC);
void
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted);
void
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
void
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format,
char *bits);
void
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure);
RegionPtr
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty);
RegionPtr
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty,
unsigned long bitPlane);
void
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr pptInit);
void
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt);
void
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment * pSegInit);
void
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs);
void
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle *prect);
void
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase);
void
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase);
void
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable, int w, int h, int x, int y);
void
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
void
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d);
void
ExaCheckGetSpans(DrawablePtr pDrawable,
int wMax,
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart);
void
ExaCheckAddTraps(PicturePtr pPicture,
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps);
/* exa_accel.c */
static _X_INLINE Bool
exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask,
unsigned int fillStyle, unsigned char alu,
Bool clientClip)
{
return ((alu != GXcopy && alu != GXclear && alu != GXset &&
alu != GXcopyInverted) || fillStyle == FillStippled ||
clientClip != FALSE || !EXA_PM_IS_SOLID(pDrawable, planemask));
}
void
exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
Bool
exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
Bool clientClip);
void
exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d);
RegionPtr
exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty);
Bool
exaHWCopyNtoN(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
void
exaCopyNtoN(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
extern const GCOps exaOps;
void
ExaCheckComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
void
ExaCheckGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
/* exa_offscreen.c */
void
ExaOffscreenSwapOut(ScreenPtr pScreen);
void
ExaOffscreenSwapIn(ScreenPtr pScreen);
ExaOffscreenArea *ExaOffscreenDefragment(ScreenPtr pScreen);
Bool
exaOffscreenInit(ScreenPtr pScreen);
void
ExaOffscreenFini(ScreenPtr pScreen);
/* exa.c */
Bool
ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
void
exaPrepareAccess(DrawablePtr pDrawable, int index);
void
exaFinishAccess(DrawablePtr pDrawable, int index);
void
exaDestroyPixmap(PixmapPtr pPixmap);
void
exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
void
exaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
int *xp, int *yp);
Bool
exaPixmapHasGpuCopy(PixmapPtr p);
PixmapPtr
exaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp);
PixmapPtr
exaGetDrawablePixmap(DrawablePtr pDrawable);
void
exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
int w, int h, int bpp);
void
exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
int w, int h, int bpp);
void
exaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
Bool
exaPixmapIsPinned(PixmapPtr pPix);
extern const GCFuncs exaGCFuncs;
/* exa_classic.c */
PixmapPtr
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
Bool
exaDestroyPixmap_classic(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap);
/* exa_driver.c */
PixmapPtr
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
Bool
exaDestroyPixmap_driver(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap);
/* exa_mixed.c */
PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
Bool
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, void *pPixData);
Bool
exaDestroyPixmap_mixed(PixmapPtr pPixmap);
Bool
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap);
/* exa_migration_mixed.c */
void
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
void
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void
exaMoveInPixmap_mixed(PixmapPtr pPixmap);
void
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure);
void
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
Bool
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle);
Bool
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
/* exa_render.c */
Bool
exaOpReadsDestination(CARD8 op);
void
exaComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
void
exaCompositeRects(CARD8 op,
PicturePtr Src,
PicturePtr pMask,
PicturePtr pDst, int nrect, ExaCompositeRectPtr rects);
void
exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntrap, xTrapezoid * traps);
void
exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntri, xTriangle * tris);
/* exa_glyph.c */
void
exaGlyphsInit(ScreenPtr pScreen);
void
exaGlyphsFini(ScreenPtr pScreen);
void
exaGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
/* exa_migration_classic.c */
void
exaCopyDirtyToSys(ExaMigrationPtr migrate);
void
exaCopyDirtyToFb(ExaMigrationPtr migrate);
void
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area);
void
exaMoveOutPixmap_classic(PixmapPtr pPixmap);
void
exaMoveInPixmap_classic(PixmapPtr pPixmap);
void
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
#endif /* EXAPRIV_H */

1229
exa/exa_render.c Normal file

File diff suppressed because it is too large Load Diff

733
exa/exa_unaccel.c Normal file
View File

@ -0,0 +1,733 @@
/*
*
* Copyright © 1999 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "exa_priv.h"
#include "mipict.h"
/*
* These functions wrap the low-level fb rendering functions and
* synchronize framebuffer/accelerated drawing by stalling until
* the accelerator is idle
*/
/**
* Calls exaPrepareAccess with EXA_PREPARE_SRC for the tile, if that is the
* current fill style.
*
* Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
* 1bpp and never in fb, so we don't worry about them.
* We should worry about them for completeness sake and going forward.
*/
void
exaPrepareAccessGC(GCPtr pGC)
{
if (pGC->stipple)
exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
if (pGC->fillStyle == FillTiled)
exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
}
/**
* Finishes access to the tile in the GC, if used.
*/
void
exaFinishAccessGC(GCPtr pGC)
{
if (pGC->fillStyle == FillTiled)
exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
if (pGC->stipple)
exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
}
#if DEBUG_TRACE_FALL
char
exaDrawableLocation(DrawablePtr pDrawable)
{
return exaDrawableIsOffscreen(pDrawable) ? 's' : 'm';
}
#endif /* DEBUG_TRACE_FALL */
void
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format,
char *bits)
{
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
ExaPixmapPriv(pPixmap);
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage ||
exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
pGC->alu, pGC->clientClip != NULL))
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
else
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
DamagePendingRegion(pExaPixmap->pDamage));
pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
bits);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure)
{
RegionRec reg;
int xoff, yoff;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
if (pExaScr->prepare_access_reg && RegionInitBoxes(&reg, pbox, nbox)) {
PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc);
exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff);
RegionTranslate(&reg, xoff + dx, yoff + dy);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pSrc, EXA_PREPARE_SRC);
if (pExaScr->prepare_access_reg &&
!exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle,
pGC->alu, pGC->clientClip != NULL) &&
RegionInitBoxes(&reg, pbox, nbox)) {
PixmapPtr pPixmap = exaGetDrawablePixmap(pDst);
exaGetDrawableDeltas(pDst, pPixmap, &xoff, &yoff);
RegionTranslate(&reg, xoff, yoff);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pDst, EXA_PREPARE_DEST);
/* This will eventually call fbCopyNtoN, with some calculation overhead. */
while (nbox--) {
pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
pbox->y1 - pSrc->y + dy, pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1, pbox->x1 - pDst->x,
pbox->y1 - pDst->y);
pbox++;
}
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
static void
ExaFallbackPrepareReg(DrawablePtr pDrawable,
GCPtr pGC,
int x, int y, int width, int height,
int index, Bool checkReads)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv(pScreen);
if (pExaScr->prepare_access_reg &&
!(checkReads && exaGCReadsDestination(pDrawable, pGC->planemask,
pGC->fillStyle, pGC->alu,
pGC->clientClip != NULL))) {
BoxRec box;
RegionRec reg;
int xoff, yoff;
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
box.x1 = pDrawable->x + x + xoff;
box.y1 = pDrawable->y + y + yoff;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
RegionInit(&reg, &box, 1);
pExaScr->prepare_access_reg(pPixmap, index, &reg);
RegionUninit(&reg);
}
else
exaPrepareAccess(pDrawable, index);
}
RegionPtr
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty)
{
RegionPtr ret;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
return ret;
}
RegionPtr
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty,
unsigned long bitPlane)
{
RegionPtr ret;
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
bitPlane);
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
exaFinishAccess(pDst, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
return ret;
}
void
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr pptInit)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
pDrawable, exaDrawableLocation(pDrawable),
pGC->lineWidth, mode, npt));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment * pSegInit)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle *prect)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, void *pglyphBase)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu));
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
exaPrepareAccessGC(pGC);
pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
exaFinishAccessGC(pGC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable, int w, int h, int x, int y)
{
EXA_PRE_FALLBACK_GC(pGC);
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
exaDrawableLocation(&pBitmap->drawable),
exaDrawableLocation(pDrawable)));
ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, EXA_PREPARE_DEST, TRUE);
ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h,
EXA_PREPARE_SRC, FALSE);
exaPrepareAccessGC(pGC);
pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
exaFinishAccessGC(pGC);
exaFinishAccess(&pBitmap->drawable, EXA_PREPARE_SRC);
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK_GC(pGC);
}
void
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
DrawablePtr pDrawable = &pWin->drawable;
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p\n", pWin));
/* Only need the source bits, the destination region will be overwritten */
if (pExaScr->prepare_access_reg) {
PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin);
int xoff, yoff;
exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff);
RegionTranslate(prgnSrc, xoff, yoff);
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc);
RegionTranslate(prgnSrc, -xoff, -yoff);
}
else
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
swap(pExaScr, pScreen, CopyWindow);
pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
swap(pExaScr, pScreen, CopyWindow);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d)
{
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, EXA_PREPARE_SRC, FALSE);
swap(pExaScr, pScreen, GetImage);
pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
swap(pExaScr, pScreen, GetImage);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckGetSpans(DrawablePtr pDrawable,
int wMax,
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
{
ScreenPtr pScreen = pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
swap(pExaScr, pScreen, GetSpans);
pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
swap(pExaScr, pScreen, GetSpans);
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
EXA_POST_FALLBACK(pScreen);
}
static void
ExaSrcValidate(DrawablePtr pDrawable,
int x, int y, int width, int height, unsigned int subWindowMode)
{
ScreenPtr pScreen = pDrawable->pScreen;
ExaScreenPriv(pScreen);
PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
BoxRec box;
RegionRec reg;
RegionPtr dst;
int xoff, yoff;
if (pExaScr->srcPix == pPix)
dst = &pExaScr->srcReg;
else if (pExaScr->maskPix == pPix)
dst = &pExaScr->maskReg;
else
return;
exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
box.x1 = x + xoff;
box.y1 = y + yoff;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
RegionInit(&reg, &box, 1);
RegionUnion(dst, dst, &reg);
RegionUninit(&reg);
swap(pExaScr, pScreen, SourceValidate);
pScreen->SourceValidate(pDrawable, x, y, width, height, subWindowMode);
swap(pExaScr, pScreen, SourceValidate);
}
static Bool
ExaPrepareCompositeReg(ScreenPtr pScreen,
CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
RegionRec region;
RegionPtr dstReg = NULL;
RegionPtr srcReg = NULL;
RegionPtr maskReg = NULL;
PixmapPtr pSrcPix = NULL;
PixmapPtr pMaskPix = NULL;
PixmapPtr pDstPix;
ExaScreenPriv(pScreen);
Bool ret;
RegionNull(&region);
if (pSrc->pDrawable) {
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
RegionNull(&pExaScr->srcReg);
srcReg = &pExaScr->srcReg;
pExaScr->srcPix = pSrcPix;
if (pSrc != pDst)
RegionTranslate(pSrc->pCompositeClip,
-pSrc->pDrawable->x, -pSrc->pDrawable->y);
} else
pExaScr->srcPix = NULL;
if (pMask && pMask->pDrawable) {
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
RegionNull(&pExaScr->maskReg);
maskReg = &pExaScr->maskReg;
pExaScr->maskPix = pMaskPix;
if (pMask != pDst && pMask != pSrc)
RegionTranslate(pMask->pCompositeClip,
-pMask->pDrawable->x, -pMask->pDrawable->y);
} else
pExaScr->maskPix = NULL;
RegionTranslate(pDst->pCompositeClip,
-pDst->pDrawable->x, -pDst->pDrawable->y);
pExaScr->SavedSourceValidate = ExaSrcValidate;
swap(pExaScr, pScreen, SourceValidate);
ret = miComputeCompositeRegion(&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
swap(pExaScr, pScreen, SourceValidate);
RegionTranslate(pDst->pCompositeClip,
pDst->pDrawable->x, pDst->pDrawable->y);
if (pSrc->pDrawable && pSrc != pDst)
RegionTranslate(pSrc->pCompositeClip,
pSrc->pDrawable->x, pSrc->pDrawable->y);
if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
RegionTranslate(pMask->pCompositeClip,
pMask->pDrawable->x, pMask->pDrawable->y);
if (!ret) {
if (srcReg)
RegionUninit(srcReg);
if (maskReg)
RegionUninit(maskReg);
return FALSE;
}
/**
* Don't limit alphamaps readbacks for now until we've figured out how that
* should be done.
*/
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pSrc->alphaMap->pDrawable),
EXA_PREPARE_AUX_SRC, NULL);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pMask->alphaMap->pDrawable),
EXA_PREPARE_AUX_MASK, NULL);
if (pSrcPix)
pExaScr->prepare_access_reg(pSrcPix, EXA_PREPARE_SRC, srcReg);
if (pMaskPix)
pExaScr->prepare_access_reg(pMaskPix, EXA_PREPARE_MASK, maskReg);
if (srcReg)
RegionUninit(srcReg);
if (maskReg)
RegionUninit(maskReg);
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
if (!exaOpReadsDestination(op)) {
int xoff;
int yoff;
exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
RegionTranslate(&region, pDst->pDrawable->x + xoff,
pDst->pDrawable->y + yoff);
dstReg = &region;
}
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
pExaScr->
prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
EXA_PREPARE_AUX_DEST, dstReg);
pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg);
RegionUninit(&region);
return TRUE;
}
void
ExaCheckComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
EXA_PRE_FALLBACK(pScreen);
if (pExaScr->prepare_access_reg) {
if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc,
ySrc, xMask, yMask, xDst, yDst, width,
height))
goto out_no_clip;
}
else {
/* We need to prepare access to any separate alpha maps first,
* in case the driver doesn't support EXA_PREPARE_AUX*,
* in which case EXA_PREPARE_SRC may be used for moving them out.
*/
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
exaPrepareAccess(pDst->pDrawable, EXA_PREPARE_DEST);
EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
if (pSrc->pDrawable != NULL)
exaPrepareAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
if (pMask && pMask->pDrawable != NULL)
exaPrepareAccess(pMask->pDrawable, EXA_PREPARE_MASK);
}
swap(pExaScr, ps, Composite);
ps->Composite(op,
pSrc,
pMask,
pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
swap(pExaScr, ps, Composite);
if (pMask && pMask->pDrawable != NULL)
exaFinishAccess(pMask->pDrawable, EXA_PREPARE_MASK);
if (pSrc->pDrawable != NULL)
exaFinishAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
exaFinishAccess(pDst->pDrawable, EXA_PREPARE_DEST);
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
out_no_clip:
EXA_POST_FALLBACK(pScreen);
}
/**
* Avoid migration ping-pong when using a mask.
*/
void
ExaCheckGlyphs(CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
EXA_PRE_FALLBACK(pScreen);
miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
EXA_POST_FALLBACK(pScreen);
}
void
ExaCheckAddTraps(PicturePtr pPicture,
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
{
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
EXA_PRE_FALLBACK(pScreen);
EXA_FALLBACK(("to pict %p (%c)\n", pPicture,
exaDrawableLocation(pPicture->pDrawable)));
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
swap(pExaScr, ps, AddTraps);
ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
swap(pExaScr, ps, AddTraps);
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
EXA_POST_FALLBACK(pScreen);
}
/**
* Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
* that happen to be 1x1. Pixmap must be at least 8bpp.
*/
CARD32
exaGetPixmapFirstPixel(PixmapPtr pPixmap)
{
switch (pPixmap->drawable.bitsPerPixel) {
case 32:
{
CARD32 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
case 16:
{
CARD16 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
case 8:
case 4:
case 1:
{
CARD8 pixel;
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
ZPixmap, ~0, (char *) &pixel);
return pixel;
}
default:
FatalError("%s called for invalid bpp %d\n", __func__,
pPixmap->drawable.bitsPerPixel);
}
}

24
exa/meson.build Normal file
View File

@ -0,0 +1,24 @@
srcs_exa = [
'exa.c',
'exa_classic.c',
'exa_migration_classic.c',
'exa_driver.c',
'exa_mixed.c',
'exa_migration_mixed.c',
'exa_accel.c',
'exa_glyphs.c',
'exa_offscreen.c',
'exa_render.c',
'exa_unaccel.c',
]
libxserver_exa = static_library('libxserver_exa',
srcs_exa,
include_directories: inc,
dependencies: common_dep,
c_args: '-DHAVE_XORG_CONFIG_H'
)
if build_xorg
install_data('exa.h', install_dir: xorgsdkdir)
endif

49
fb/Makefile.am Normal file
View File

@ -0,0 +1,49 @@
noinst_LTLIBRARIES = libfb.la libwfb.la
AM_CFLAGS = $(DIX_CFLAGS)
if XORG
sdk_HEADERS = fb.h fbrop.h fboverlay.h wfbrename.h fbpict.h
endif
libfb_la_CFLAGS = $(AM_CFLAGS)
libfb_la_LIBADD = $(PIXMAN_LIBS)
libwfb_la_CFLAGS = $(AM_CFLAGS) -DFB_ACCESS_WRAPPER
libwfb_la_LIBADD = $(PIXMAN_LIBS)
libfb_la_SOURCES = \
fb.h \
fballpriv.c \
fbarc.c \
fbbits.c \
fbbits.h \
fbblt.c \
fbbltone.c \
fbcmap_mi.c \
fbcopy.c \
fbfill.c \
fbfillrect.c \
fbfillsp.c \
fbgc.c \
fbgetsp.c \
fbglyph.c \
fbimage.c \
fbline.c \
fboverlay.c \
fboverlay.h \
fbpict.c \
fbpict.h \
fbpixmap.c \
fbpoint.c \
fbpush.c \
fbrop.h \
fbscreen.c \
fbseg.c \
fbsetsp.c \
fbsolid.c \
fbtrap.c \
fbutil.c \
fbwindow.c
libwfb_la_SOURCES = $(libfb_la_SOURCES)

View File

@ -53,3 +53,7 @@ libxserver_wfb = static_library('libxserver_wfb',
pic: true,
build_by_default: false,
)
if build_xorg
install_data(hdrs_fb, install_dir: xorgsdkdir)
endif

62
glamor/Makefile.am Normal file
View File

@ -0,0 +1,62 @@
noinst_LTLIBRARIES = libglamor.la libglamor_egl_stubs.la
libglamor_la_LIBADD = $(GLAMOR_LIBS)
AM_CFLAGS = $(CWARNFLAGS) $(DIX_CFLAGS) $(GLAMOR_CFLAGS)
libglamor_la_SOURCES = \
glamor.c \
glamor_context.h \
glamor_copy.c \
glamor_core.c \
glamor_dash.c \
glamor_debug.h \
glamor_font.c \
glamor_font.h \
glamor_glx.c \
glamor_composite_glyphs.c \
glamor_image.c \
glamor_lines.c \
glamor_segs.c \
glamor_render.c \
glamor_gradient.c \
glamor_prepare.c \
glamor_prepare.h \
glamor_program.c \
glamor_program.h \
glamor_rects.c \
glamor_spans.c \
glamor_text.c \
glamor_transfer.c \
glamor_transfer.h \
glamor_transform.c \
glamor_transform.h \
glamor_trapezoid.c \
glamor_triangles.c\
glamor_addtraps.c\
glamor_glyphblt.c\
glamor_points.c\
glamor_priv.h\
glamor_pixmap.c\
glamor_largepixmap.c\
glamor_picture.c\
glamor_vbo.c \
glamor_window.c\
glamor_fbo.c\
glamor_compositerects.c\
glamor_utils.c\
glamor_utils.h\
glamor_sync.c \
glamor.h
if XV
libglamor_la_SOURCES += \
glamor_xv.c
endif
libglamor_egl_stubs_la_SOURCES = \
glamor_egl_stubs.c \
glamor_egl_ext.h \
glamor_egl.h
sdk_HEADERS = glamor.h

View File

@ -746,7 +746,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
* have instanced arrays, but this is not always the case.
* etnaviv offers GLSL 140 with OpenGL 2.1.
*/
if (glamor_priv->glsl_version >= 130 &&
if (glamor_glsl_has_ints(glamor_priv) &&
!epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
glamor_priv->glsl_version = 120;
} else {
@ -772,6 +772,10 @@ glamor_init(ScreenPtr screen, unsigned int flags)
goto fail;
}
if (!glamor_priv->is_gles && glamor_priv->glsl_version == 120 &&
epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
glamor_priv->use_gpu_shader4 = epoxy_has_gl_extension("GL_EXT_gpu_shader4");
glamor_priv->has_rw_pbo = FALSE;
if (!glamor_priv->is_gles)
glamor_priv->has_rw_pbo = TRUE;
@ -799,7 +803,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
epoxy_gl_version() >= 30 ||
epoxy_has_gl_extension("GL_NV_pack_subimage");
glamor_priv->has_dual_blend =
glamor_priv->glsl_version >= 130 &&
glamor_glsl_has_ints(glamor_priv) &&
epoxy_has_gl_extension("GL_ARB_blend_func_extended");
glamor_priv->has_clear_texture =
epoxy_gl_version() >= 44 ||
@ -817,7 +821,8 @@ glamor_init(ScreenPtr screen, unsigned int flags)
* cached IB.
*/
if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
strstr((char *)glGetString(GL_RENDERER), "VC4"))
(strstr((char *)glGetString(GL_RENDERER), "VC4") ||
strstr((char *)glGetString(GL_RENDERER), "V3D")))
glamor_priv->use_quads = FALSE;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);

View File

@ -208,11 +208,6 @@ static const glamor_facet glamor_facet_composite_glyphs_120 = {
.locations = glamor_program_location_atlas,
};
static inline Bool
glamor_glyph_use_130(glamor_screen_private *glamor_priv) {
return glamor_priv->glsl_version >= 130;
}
static Bool
glamor_glyphs_init_facet(ScreenPtr screen)
{
@ -274,7 +269,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
box->y2 - box->y1);
box++;
if (glamor_glyph_use_130(glamor_priv))
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
else
glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
@ -287,7 +282,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
glDisable(GL_SCISSOR_TEST);
if (glamor_glyph_use_130(glamor_priv)) {
if (glamor_glsl_has_ints(glamor_priv)) {
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
}
@ -305,7 +300,7 @@ glamor_glyph_start(ScreenPtr screen, int count)
/* Set up the vertex buffers for the font and destination */
if (glamor_glyph_use_130(glamor_priv)) {
if (glamor_glsl_has_ints(glamor_priv)) {
v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
@ -439,7 +434,7 @@ glamor_composite_glyphs(CARD8 op,
/* First glyph in the current atlas?
*/
if (_X_UNLIKELY(glyphs_queued == 0)) {
if (glamor_glyph_use_130(glamor_priv))
if (glamor_glsl_has_ints(glamor_priv))
prog = glamor_setup_program_render(op, src, glyph_pict, dst,
glyphs_program,
&glamor_facet_composite_glyphs_130,
@ -458,7 +453,7 @@ glamor_composite_glyphs(CARD8 op,
*/
glyphs_queued++;
if (_X_LIKELY(glamor_glyph_use_130(glamor_priv))) {
if (_X_LIKELY(glamor_glsl_has_ints(glamor_priv))) {
v[0] = x - glyph->info.x;
v[1] = y - glyph->info.y;
v[2] = glyph_draw->width;

View File

@ -1060,9 +1060,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
goto error;
}
if (strstr((const char *)renderer, "llvmpipe")) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Refusing to try glamor on llvmpipe\n");
goto error;
if (scrn->confScreen->num_gpu_devices)
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Allowing glamor on llvmpipe for PRIME\n");
else {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Refusing to try glamor on llvmpipe\n");
goto error;
}
}
/*

View File

@ -47,7 +47,7 @@ glamor_font_get(ScreenPtr screen, FontPtr font)
unsigned long count;
char *bits;
if (glamor_priv->glsl_version < 130)
if (!glamor_glsl_has_ints(glamor_priv))
return NULL;
privates = FontGetPrivate(font, glamor_font_private_index);
@ -210,7 +210,7 @@ glamor_font_init(ScreenPtr screen)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
if (glamor_priv->glsl_version < 130)
if (!glamor_glsl_has_ints(glamor_priv))
return TRUE;
if (glamor_font_generation != serverGeneration) {

View File

@ -213,6 +213,7 @@ typedef struct glamor_screen_private {
Bool has_texture_swizzle;
Bool is_core_profile;
Bool can_copyplane;
Bool use_gpu_shader4;
int max_fbo_size;
struct glamor_format formats[33];

View File

@ -187,6 +187,7 @@ fs_location_vars(glamor_program_location locations)
static const char vs_template[] =
"%s" /* version */
"%s" /* exts */
"%s" /* defines */
"%s" /* prim vs_vars */
"%s" /* fill vs_vars */
@ -199,6 +200,7 @@ static const char vs_template[] =
static const char fs_template[] =
"%s" /* version */
"%s" /* exts */
GLAMOR_DEFAULT_PRECISION
"%s" /* defines */
"%s" /* prim fs_vars */
@ -262,6 +264,7 @@ glamor_build_program(ScreenPtr screen,
char *fs_prog_string;
GLint fs_prog, vs_prog;
Bool gpu_shader4 = FALSE;
if (!fill)
fill = &facet_null_fill;
@ -270,8 +273,14 @@ glamor_build_program(ScreenPtr screen,
flags |= fill->flags;
version = MAX(version, fill->version);
if (version > glamor_priv->glsl_version)
goto fail;
if (version > glamor_priv->glsl_version) {
if (version == 130 && !glamor_priv->use_gpu_shader4)
goto fail;
else {
version = 120;
gpu_shader4 = TRUE;
}
}
vs_vars = vs_location_vars(locations);
fs_vars = fs_location_vars(locations);
@ -291,6 +300,7 @@ glamor_build_program(ScreenPtr screen,
if (asprintf(&vs_prog_string,
vs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
str(defines),
str(prim->vs_vars),
str(fill->vs_vars),
@ -302,6 +312,7 @@ glamor_build_program(ScreenPtr screen,
if (asprintf(&fs_prog_string,
fs_template,
str(version_string),
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
str(defines),
str(prim->fs_vars),
str(fill->fs_vars),

View File

@ -69,7 +69,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
glamor_bounds_union_rect(&bounds, &prect[i]);
}
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
prog = glamor_use_program_fill(pixmap, gc,
&glamor_priv->poly_fill_rect_program,
&glamor_facet_polyfillrect_130);
@ -151,7 +151,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
scissor.y1 + off_y,
scissor.x2 - scissor.x1,
scissor.y2 - scissor.y1);
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nrect);
else {
glamor_glDrawArrays_GL_QUADS(glamor_priv, nrect);
@ -163,7 +163,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
bail:
glDisable(GL_SCISSOR_TEST);
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);

View File

@ -560,8 +560,8 @@ glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
case PictFilterGood:
case PictFilterBest:
case PictFilterBilinear:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
break;
}

View File

@ -64,7 +64,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
glamor_make_current(glamor_priv);
if (glamor_priv->glsl_version >= 130) {
if (glamor_glsl_has_ints(glamor_priv)) {
prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program,
&glamor_facet_fillspans_130);
@ -134,7 +134,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
box->x2 - box->x1,
box->y2 - box->y1);
box++;
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, n);
else {
glamor_glDrawArrays_GL_QUADS(glamor_priv, n);
@ -146,7 +146,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
bail:
glDisable(GL_SCISSOR_TEST);
if (glamor_priv->glsl_version >= 130)
if (glamor_glsl_has_ints(glamor_priv))
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);

View File

@ -732,5 +732,9 @@ glamor_glDrawArrays_GL_QUADS(glamor_screen_private *glamor_priv, unsigned count)
}
}
static inline Bool
glamor_glsl_has_ints(glamor_screen_private *glamor_priv) {
return glamor_priv->glsl_version >= 130 || glamor_priv->use_gpu_shader4;
}
#endif

View File

@ -380,15 +380,15 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@ -397,8 +397,8 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
case FOURCC_I420:
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
break;

View File

@ -54,3 +54,7 @@ glamor_egl_stubs = static_library('glamor_egl_stubs',
include_directories: inc,
dependencies: common_dep,
)
if build_xorg
install_data('glamor.h', install_dir: xorgsdkdir)
endif

95
glx/Makefile.am Normal file
View File

@ -0,0 +1,95 @@
if DRI2
GLXDRI_LIBRARY = libglxdri.la
endif
noinst_LTLIBRARIES = libglx.la $(GLXDRI_LIBRARY) libglxvnd.la
AM_CFLAGS = \
@DIX_CFLAGS@ \
@GL_CFLAGS@ \
@XLIB_CFLAGS@ \
@LIBDRM_CFLAGS@ \
@GLX_DEFINES@ \
@GLX_ARCH_DEFINES@
sdk_HEADERS = vndserver.h
AM_CPPFLAGS = \
-I$(top_srcdir)/hw/xfree86/os-support \
-I$(top_srcdir)/hw/xfree86/os-support/bus \
-I$(top_srcdir)/hw/xfree86/common \
-I$(top_srcdir)/hw/xfree86/dri \
-I$(top_srcdir)/hw/xfree86/dri2 \
-I$(top_srcdir)/mi \
-I$(top_srcdir)/present
indirect_sources = \
indirect_dispatch.c \
indirect_dispatch.h \
indirect_dispatch_swap.c \
indirect_reqsize.c \
indirect_reqsize.h \
indirect_size.h \
indirect_size_get.c \
indirect_size_get.h \
indirect_table.c
libglxdri_la_SOURCES =
if DRI2
libglxdri_la_SOURCES += glxdri2.c
endif
libglxdri_la_LIBADD = $(DLOPEN_LIBS)
libglx_la_SOURCES = \
$(indirect_sources) \
clientinfo.c \
createcontext.c \
extension_string.c \
extension_string.h \
indirect_util.c \
indirect_util.h \
indirect_program.c \
indirect_table.h \
indirect_texture_compression.c \
glxbyteorder.h \
glxcmds.c \
glxcmdsswap.c \
glxcontext.h \
glxdrawable.h \
glxext.c \
glxext.h \
glxdriswrast.c \
glxdricommon.c \
glxdricommon.h \
glxscreens.c \
glxscreens.h \
glxserver.h \
glxutil.h \
render2.c \
render2swap.c \
renderpix.c \
renderpixswap.c \
rensize.c \
single2.c \
single2swap.c \
singlepix.c \
singlepixswap.c \
singlesize.c \
singlesize.h \
swap_interval.c \
unpack.h \
xfont.c
libglx_la_LIBADD = $(DLOPEN_LIBS) $(top_builddir)/Xext/libhashtable.la
libglxvnd_la_SOURCES = \
vndcmds.c \
vndext.c \
vndservermapping.c \
vndservervendor.h \
vndservervendor.c
libglxvnd_la_LIBADD = $(top_builddir)/Xext/libhashtable.la
EXTRA_DIST = vnd_dispatch_stubs.c

View File

@ -993,7 +993,6 @@ __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
/* Pad with zeroes, so that attributes count is constant. */
while (p < GLX_VIS_CONFIG_TOTAL) {
buf[p++] = 0;
buf[p++] = 0;
}
assert(p == GLX_VIS_CONFIG_TOTAL);
@ -1882,7 +1881,7 @@ DoGetDrawableAttributes(__GLXclientState * cl, XID drawId)
int err = dixLookupWindow((WindowPtr *)&pDraw, drawId, client,
DixGetAttrAccess);
if (err != Success)
return error;
return __glXError(GLXBadDrawable);
}
if (pGlxDraw)
pDraw = pGlxDraw->pDraw;

View File

@ -51,7 +51,7 @@ if build_glx
endif
srcs_glxdri2 = []
if build_dri3
if build_dri2 or build_dri3
srcs_glxdri2 = files('glxdri2.c')
endif
@ -78,4 +78,8 @@ if build_glx
dependency('gl', version: '>= 1.2'),
],
)
if build_xorg
install_data(hdrs_vnd, install_dir : xorgsdkdir)
endif
endif

View File

@ -92,6 +92,9 @@ static void SetReplyHeader(ClientPtr client, void *replyPtr)
xGenericReply *rep = (xGenericReply *) replyPtr;
rep->type = X_Reply;
rep->sequenceNumber = client->sequence;
if (client->swapped) {
swaps(&rep->sequenceNumber);
}
rep->length = 0;
}

46
hw/Makefile.am Normal file
View File

@ -0,0 +1,46 @@
if DMX
DMX_SUBDIRS = dmx
endif
if XORG
XORG_SUBDIRS = xfree86
endif
if XVFB
XVFB_SUBDIRS = vfb
endif
if XNEST
XNEST_SUBDIRS = xnest
endif
if XWIN
XWIN_SUBDIRS = xwin
endif
if KDRIVE
KDRIVE_SUBDIRS = kdrive
endif
if XQUARTZ
XQUARTZ_SUBDIRS = xquartz
endif
if XWAYLAND
XWAYLAND_SUBDIRS = xwayland
endif
SUBDIRS = \
$(XORG_SUBDIRS) \
$(XWIN_SUBDIRS) \
$(XVFB_SUBDIRS) \
$(XNEST_SUBDIRS) \
$(DMX_SUBDIRS) \
$(KDRIVE_SUBDIRS) \
$(XQUARTZ_SUBDIRS) \
$(XWAYLAND_SUBDIRS)
DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
relink:
$(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done

2
hw/dmx/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Add & Override for this directory and its subdirectories
Xdmx

87
hw/dmx/Makefile.am Normal file
View File

@ -0,0 +1,87 @@
SUBDIRS = input config examples doc doxygen man
bin_PROGRAMS = Xdmx
if XINERAMA
PANORAMIX_SRCS = $(top_srcdir)/Xext/panoramiX.c
endif
if GLX
SUBDIRS += glxProxy
GLX_LIBS = glxProxy/libglxproxy.a
GLX_SRCS = $(PANORAMIX_SRCS) dmx_glxvisuals.c dmx_glxvisuals.h
GLX_INCS = -I$(top_srcdir)/hw/xfree86/dixmods/extmod
GLX_DEFS = @GL_CFLAGS@
endif
AM_CFLAGS = \
-DHAVE_DMX_CONFIG_H \
$(DIX_CFLAGS) \
$(GLX_INCS) \
$(GLX_DEFS) \
$(DMX_CFLAGS) \
@DMXMODULES_CFLAGS@
Xdmx_SOURCES = dmx.c \
dmxcb.c \
dmxcb.h \
dmxclient.h \
dmxcmap.c \
dmxcmap.h \
dmx-config.h \
dmxcursor.c \
dmxcursor.h \
dmxdpms.c \
dmxdpms.h \
dmxextension.c \
dmxextension.h \
dmxfont.c \
dmxfont.h \
dmxgc.c \
dmxgc.h \
dmxgcops.c \
dmxgcops.h \
dmx.h \
dmxinit.c \
dmxinit.h \
dmxinput.c \
dmxinput.h \
dmxlog.c \
dmxlog.h \
dmxpict.c \
dmxpict.h \
dmxpixmap.c \
dmxpixmap.h \
dmxprop.c \
dmxprop.h \
dmxscrinit.c \
dmxscrinit.h \
dmxstat.c \
dmxstat.h \
dmxsync.c \
dmxsync.h \
dmxvisual.c \
dmxvisual.h \
dmxwindow.c \
dmxwindow.h \
$(top_srcdir)/mi/miinitext.c \
$(top_srcdir)/mi/miinitext.h \
$(GLX_SRCS)
#if COMPOSITE
#Xdmx_SOURCES += fakecw.c
#endif
XDMX_LIBS = \
$(GLX_LIBS) \
@XDMX_LIBS@ \
input/libdmxinput.a \
config/libdmxconfig.a
Xdmx_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
Xdmx_DEPENDENCIES= $(XDMX_LIBS)
Xdmx_LDADD = $(XDMX_LIBS) $(XDMX_SYS_LIBS) $(XSERVER_SYS_LIBS)
relink:
$(AM_V_at)rm -f Xdmx$(EXEEXT) && $(MAKE) Xdmx$(EXEEXT)

7
hw/dmx/config/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# Add & Override for this directory and its subdirectories
dmxtodmx
parser.c
parser.h
scanner.c
vdltodmx
xdmxconfig

165
hw/dmx/config/Canvas.c Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright 1987, 1998 The Open Group
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
*
* The above copyright notice and this permission notice 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
* OPEN GROUP 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.
*
* Except as contained in this notice, the name of The Open Group shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from The Open Group.
*/
/*
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* 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 on 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
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* 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.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This file was originally taken from xc/lib/Xaw/Template.c
*/
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "CanvasP.h"
static void
CanvasInitialize(Widget request, Widget w, ArgList args, Cardinal * num_args)
{
}
static void
CanvasExpose(Widget w, XEvent * event, Region region)
{
CanvasExposeDataRec data;
data.w = w;
data.event = event;
data.region = region;
if (!XtIsRealized(w))
return;
XtCallCallbacks(w, XtNcanvasExposeCallback, (XtPointer) &data);
}
static void
CanvasResize(Widget w)
{
if (!XtIsRealized(w))
return;
XtCallCallbacks(w, XtNcanvasResizeCallback, (XtPointer) w);
}
static void
CanvasAction(Widget w, XEvent * event, String * params, Cardinal * num_params)
{
XtCallCallbacks(w, XtNcallback, (XtPointer) event);
}
#define offset(field) XtOffsetOf(CanvasRec, canvas.field)
static XtResource resources[] = {
{XtNcallback, XtCCallback, XtRCallback,
sizeof(XtCallbackList), offset(input_callback), XtRCallback, NULL}
,
{(char *) XtNcanvasExposeCallback, (char *) XtCcanvasExposeCallback, XtRCallback,
sizeof(XtCallbackList), offset(expose_callback), XtRCallback, NULL}
,
{(char *) XtNcanvasResizeCallback, (char *) XtCcanvasResizeCallback, XtRCallback,
sizeof(XtCallbackList), offset(resize_callback), XtRCallback, NULL}
,
};
#undef offset
static XtActionsRec actions[] = {
{(char *) "canvas", CanvasAction},
};
static char translations[] = "<Key>: canvas()\n\
<Motion>: canvas()\n\
<BtnDown>: canvas()\n\
<BtnUp>: canvas()\n\
";
#define Superclass (&widgetClassRec)
CanvasClassRec canvasClassRec = {
/* core */
{
(WidgetClass) Superclass, /* superclass */
(char *) "Canvas", /* class_name */
sizeof(CanvasRec), /* widget_size */
NULL, /* class_initialize */
NULL, /* class_part_initialize */
False, /* class_inited */
CanvasInitialize, /* initialize */
NULL, /* initialize_hook */
XtInheritRealize, /* realize */
actions, /* actions */
XtNumber(actions), /* num_actions */
resources, /* resources */
XtNumber(resources), /* num_resources */
NULLQUARK, /* xrm_class */
True, /* compress_motion */
True, /* compress_exposure */
True, /* compress_enterleave */
False, /* visible_interest */
NULL, /* destroy */
CanvasResize, /* resize */
CanvasExpose, /* expose */
NULL, /* set_values */
NULL, /* set_values_hook */
XtInheritSetValuesAlmost, /* set_values_almost */
NULL, /* get_values_hook */
NULL, /* accept_focus */
XtVersion, /* version */
NULL, /* callback_private */
translations, /* tm_table */
XtInheritQueryGeometry, /* query_geometry */
XtInheritDisplayAccelerator, /* display_accelerator */
NULL, /* extension */
}
,
/* canvas */
{
NULL, /* extension */
}
};
WidgetClass canvasWidgetClass = (WidgetClass) &canvasClassRec;

55
hw/dmx/config/Canvas.h Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright 1987, 1998 The Open Group
Copyright 2002 Red Hat Inc., Durham, North Carolina.
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice 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
OPEN GROUP 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.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
* This file was originally taken from xc/lib/Xaw/Template.h
*/
#ifndef _Canvas_h
#define _Canvas_h
#include <X11/Intrinsic.h>
#define XtNcanvasExposeCallback "canvasExposeCallback"
#define XtCcanvasExposeCallback "CanvasExposeCallback"
#define XtNcanvasResizeCallback "canvasResizeCallback"
#define XtCcanvasResizeCallback "CanvasResizeCallback"
typedef struct _CanvasClassRec *CanvasWidgetClass;
typedef struct _CanvasRec *CanvasWidget;
extern WidgetClass canvasWidgetClass;
typedef struct _CanvasExposeDataRec {
Widget w;
XEvent *event;
Region region;
} CanvasExposeDataRec, *CanvasExposeDataPtr;
#endif /* _Canvas_h */

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