Compare commits

...

154 commits

Author SHA1 Message Date
Olivier Fourdan
449b197e7e Bump version to 24.1.8
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2030>
2025-06-18 18:00:16 +02:00
Olivier Fourdan
d2a7903154 os: Check for integer overflow on BigRequest length
Check for another possible integer overflow once we get a complete xReq
with BigRequest.

Related to CVE-2025-49176

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Peter Harris <pharris2@rocketsoftware.com>
(cherry picked from commit 4fc4d76b2c)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2030>
2025-06-18 17:59:36 +02:00
Olivier Fourdan
2c5e87e3df Bump version to 24.1.7
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:08:26 +02:00
Olivier Fourdan
fce91bcbe2 randr: Check for overflow in RRChangeProviderProperty()
A client might send a request causing an integer overflow when computing
the total size to allocate in RRChangeProviderProperty().

To avoid the issue, check that total length in bytes won't exceed the
maximum integer value.

CVE-2025-49180

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 3c3a4b767b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:08:17 +02:00
Olivier Fourdan
9d20532389 record: Check for overflow in RecordSanityCheckRegisterClients()
The RecordSanityCheckRegisterClients() checks for the request length,
but does not check for integer overflow.

A client might send a very large value for either the number of clients
or the number of protocol ranges that will cause an integer overflow in
the request length computation, defeating the check for request length.

To avoid the issue, explicitly check the number of clients against the
limit of clients (which is much lower than an maximum integer value) and
the number of protocol ranges (multiplied by the record length) do not
exceed the maximum integer value.

This way, we ensure that the final computation for the request length
will not overflow the maximum integer limit.

CVE-2025-49179

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 2bde9ca49a)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:08:10 +02:00
Olivier Fourdan
41ae2e70ad os: Account for bytes to ignore when sharing input buffer
When reading requests from the clients, the input buffer might be shared
and used between different clients.

If a given client sends a full request with non-zero bytes to ignore,
the bytes to ignore may still be non-zero even though the request is
full, in which case the buffer could be shared with another client who's
request will not be processed because of those bytes to ignore, leading
to a possible hang of the other client request.

To avoid the issue, make sure we have zero bytes to ignore left in the
input request when sharing the input buffer with another client.

CVE-2025-49178

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit d55c54cecb)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:08:02 +02:00
Olivier Fourdan
b7c5685a26 xfixes: Check request length for SetClientDisconnectMode
The handler of XFixesSetClientDisconnectMode does not check the client
request length.

A client could send a shorter request and read data from a former
request.

Fix the issue by checking the request size matches.

CVE-2025-49177

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Fixes: e167299f6 - xfixes: Add ClientDisconnectMode
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit ab02fb96b1)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:07:52 +02:00
Olivier Fourdan
437a0cad0b os: Do not overflow the integer size with BigRequest
The BigRequest extension allows requests larger than the 16-bit length
limit.

It uses integers for the request length and checks for the size not to
exceed the maxBigRequestSize limit, but does so after translating the
length to integer by multiplying the given size in bytes by 4.

In doing so, it might overflow the integer size limit before actually
checking for the overflow, defeating the purpose of the test.

To avoid the issue, make sure to check that the request size does not
overflow the maxBigRequestSize limit prior to any conversion.

The caller Dispatch() function however expects the return value to be in
bytes, so we cannot just return the converted value in case of error, as
that would also overflow the integer size.

To preserve the existing API, we use a negative value for the X11 error
code BadLength as the function only return positive values, 0 or -1 and
update the caller Dispatch() function to take that case into account to
return the error code to the offending client.

CVE-2025-49176

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
(cherry picked from commit 03731b326a)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:07:43 +02:00
Olivier Fourdan
fa6b40037a render: Avoid 0 or less animated cursors
Animated cursors use a series of cursors that the client can set.

By default, the Xserver assumes at least one cursor is specified
while a client may actually pass no cursor at all.

That causes an out-of-bound read creating the animated cursor and a
crash of the Xserver:

 | Invalid read of size 8
 |    at 0x5323F4: AnimCursorCreate (animcur.c:325)
 |    by 0x52D4C5: ProcRenderCreateAnimCursor (render.c:1817)
 |    by 0x52DC80: ProcRenderDispatch (render.c:1999)
 |    by 0x4A1E9D: Dispatch (dispatch.c:560)
 |    by 0x4B0169: dix_main (main.c:284)
 |    by 0x4287F5: main (stubmain.c:34)
 |  Address 0x59aa010 is 0 bytes after a block of size 0 alloc'd
 |    at 0x48468D3: reallocarray (vg_replace_malloc.c:1803)
 |    by 0x52D3DA: ProcRenderCreateAnimCursor (render.c:1802)
 |    by 0x52DC80: ProcRenderDispatch (render.c:1999)
 |    by 0x4A1E9D: Dispatch (dispatch.c:560)
 |    by 0x4B0169: dix_main (main.c:284)
 |    by 0x4287F5: main (stubmain.c:34)
 |
 | Invalid read of size 2
 |    at 0x5323F7: AnimCursorCreate (animcur.c:325)
 |    by 0x52D4C5: ProcRenderCreateAnimCursor (render.c:1817)
 |    by 0x52DC80: ProcRenderDispatch (render.c:1999)
 |    by 0x4A1E9D: Dispatch (dispatch.c:560)
 |    by 0x4B0169: dix_main (main.c:284)
 |    by 0x4287F5: main (stubmain.c:34)
 |  Address 0x8 is not stack'd, malloc'd or (recently) free'd

To avoid the issue, check the number of cursors specified and return a
BadValue error in both the proc handler (early) and the animated cursor
creation (as this is a public function) if there is 0 or less cursor.

CVE-2025-49175

This issue was discovered by Nils Emmerich <nemmerich@ernw.de> and
reported by Julian Suleder via ERNW Vulnerability Disclosure.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: José Expósito <jexposit@redhat.com>
(cherry picked from commit 0885e0b262)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2026>
2025-06-17 15:07:32 +02:00
Peter Hutterer
34ef671aa5 dix: pick the right keyboard for focus FollowKeyboard
This fixes a crash when we try to send focus events and dereference
FollowKeyboardWin (0x3) as WindowPtr.

A device set to XSetDeviceFocus(FollowKeyboard) is supposed to follow
the focus of the corresponding master device. During ActivateKeyboard
a slave device is detached from the master for the duration for the grab
so we don't actually have a master to follow - leaving our oldWin set to
the FollowKeyboardWin constant. This later crashes when we try to
dereference it.

Fix this by getting the current master (if any), or the saved master (if
temporarily detached due to a grab). And if failing that, use the VCK
as fallback device - that is technically wrong but it's such a niche use
case that it shouldn't matter.

Reproducer:
     window = XCreateSimpleWindow(...)
     deviceid = any device that is IsXExtensionKeyboard device
     XSetDeviceFocus(deviceid, FollowKeyboard, ...)
     XGrabDevice(deviceid, window, ...)

Fixes: f01ee198ff ("dix: don't use inputInfo.keyboard to get the focus window in ActivateKbdGrab")

Found-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
Tested-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit cab9017485)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:06:12 +02:00
Peter Hutterer
a50e6a2e33 dix: fix erroneous BUG_RETURN check
Check was inverted, we want to complain if evcount exceeds our target
array.

Fixes: 219c54b8a3 ("dix: fix DeviceStateNotify event calculation")
(cherry picked from commit 2bca68f41b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:06:02 +02:00
Alan Coopersmith
1119ea220a dix-config.h: define HAVE_STRUCT_SOCKADDR_STORAGE for xtrans 1.6
xtrans 1.6 will use struct sockaddr_storage if HAVE_STRUCT_SOCKADDR_STORAGE
is defined, even if IPv6 is disabled, unlike previous versions which tied
it to the IPv6 #define.

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 4b5d410591)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:05:49 +02:00
Alan Coopersmith
6f1acb0dff pkgconfig files: Add URL
https://github.com/pkgconf/pkgconf/blob/master/man/pc.5 says it's
a mandatory field in *.pc files.

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit b73cd6066a)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:05:31 +02:00
Peter Hutterer
3a6d035aec Xi: disallow grabbing disabled devices
Grabbing a disabled (pointer) device will lead to a segfault later
in the myriad of places where we look at the device's spriteInfo - which
will be NULL.

As a workaround, disallow grabbing a disabled device by pretending it's
already grabbed. Since the point of a grab is to receive all events by
that device and disabled devices cannot send events, this should be Good
Enough.

Tested-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 797f63b8be)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:04:53 +02:00
Alan Coopersmith
91e42e523c xkb: Add tbGetBufferString helper function
Handles common case of allocating & copying string to temporary buffer

(cherry picked from xorg/lib/libxkbfile@8a91517ca6ea77633476595b0eb5b213357c60e5)

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 42a1f25faf)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:55 +02:00
Martin Burggraf
bd43d90cd1 xkb: correcting mathematical nonsense in XkbGeomFPText
Fixes formatting of negative numbers, so they don't show minus sign
after the decimal point.

(cherry picked from xorg/lib/libxkbfile@d2ec504fec2550f4fd046e801b34317ef4a4bab9)

Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 7a23010232)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:50 +02:00
Alan Coopersmith
ed54cc2a03 xkb: Convert more sprintf calls to snprintf in xkbtext.c
Based on xorg/lib/libxkbfile@390acfe5bb88cdab509b5eaae4041f265e969d2b

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 60419d8e4a)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:45 +02:00
José Expósito
b32d637f51 xkb: Check that needed is > 0 in XkbResizeKeyActions
Passing a negative value in `needed` to the `XkbResizeKeyActions()`
function can create a `newActs` array of an unespected size.
Check the value and return if it is invalid.

This error has been found by a static analysis tool. This is the report:

    Error: OVERRUN (CWE-119):
    libX11-1.8.7/src/xkb/XKBMAlloc.c:811: cond_const:
      Checking "xkb->server->size_acts == 0" implies that
      "xkb->server->size_acts" is 0 on the true branch.
    libX11-1.8.7/src/xkb/XKBMAlloc.c:811: buffer_alloc:
      "calloc" allocates 8 bytes dictated by parameters
      "(size_t)((xkb->server->size_acts == 0) ? 1 : xkb->server->size_acts)"
      and "8UL".
    libX11-1.8.7/src/xkb/XKBMAlloc.c:811: var_assign:
      Assigning: "newActs" = "calloc((size_t)((xkb->server->size_acts == 0) ? 1 : xkb->server->size_acts), 8UL)".
    libX11-1.8.7/src/xkb/XKBMAlloc.c:815: assignment:
      Assigning: "nActs" = "1".
    libX11-1.8.7/src/xkb/XKBMAlloc.c:829: cond_at_least:
      Checking "nCopy > 0" implies that "nCopy" is at least 1 on the
      true branch.
    libX11-1.8.7/src/xkb/XKBMAlloc.c:830: overrun-buffer-arg:
      Overrunning buffer pointed to by "&newActs[nActs]" of 8 bytes by
      passing it to a function which accesses it at byte offset 15
      using argument "nCopy * 8UL" (which evaluates to 8).
    #  828|
    #  829|           if (nCopy > 0)
    #  830|->             memcpy(&newActs[nActs], XkbKeyActionsPtr(xkb, i),
    #  831|                      nCopy * sizeof(XkbAction));
    #  832|           if (nCopy < nKeyActs)

(cherry picked from xorg/lib/libx11@af1312d2873d2ce49b18708a5029895aed477392)

Signed-off-by: José Expósito <jexposit@redhat.com>
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 6d33834186)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:40 +02:00
Alan Coopersmith
852595a51d xkb: ensure XkbAllocNames sets num_rg to 0 on allocation failure
If there was a previous radio_groups array which we failed to realloc
and freed instead, clear the array size in the XkbNamesRec.

Taken from xorg/lib/libx11@258a8ced681dc1bc50396be7439fce23f9807e2a

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 09c6f09eb7)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:35 +02:00
Peter Hutterer
15075baac2 mi: guard miPointer functions against NULL dereferences
Already in place for some functions, let's add it to most others.
The only function missing is miPointerSetPosition() which needs to
return the ScreenPtr and that one is unclear if we don't have a screen -
returning NULL will crash the caller(s) so let's wait for something to
trigger this bug before we try to fix it wrongly.

Related to #1782

(cherry picked from commit 68c17477d2)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:30 +02:00
Peter Hutterer
6d33c347ea mi: don't crash on miPointerGetPosition for disabled devices
If a device is disabled, its master device is forcibly reset to NULL but
unlike a floating device it doesn't have a sprite allocated. Calling
miPointerGetPosition for a disabled device thus crashes.

Avoid this by returning 0/0 for any device without a miPointer.
This is a quick fix only, a proper fix for this issue is rather more
involved.

Closes #1782

(cherry picked from commit acbdd0ecdd)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1895>
2025-04-08 10:03:25 +02:00
Olivier Fourdan
5b1d9da00f Bump version to 24.1.6
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
9dbe93ebee sync: Apply changes last in SyncChangeAlarmAttributes()
SyncChangeAlarmAttributes() would apply the various changes while
checking for errors.

If one of the changes triggers an error, the changes for the trigger,
counter or delta value would remain, possibly leading to inconsistent
changes.

Postpone the actual changes until we're sure nothing else can go wrong.

Related to CVE-2025-26601, ZDI-CAN-25870

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit c285798984)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
6f567221a6 sync: Do not fail SyncAddTriggerToSyncObject()
We do not want to return a failure at the very last step in
SyncInitTrigger() after having all changes applied.

SyncAddTriggerToSyncObject() must not fail on memory allocation, if the
allocation of the SyncTriggerList fails, trigger a FatalError() instead.

Related to CVE-2025-26601, ZDI-CAN-25870

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 8cbc90c881)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
fb6df2a68c sync: Check values before applying changes
In SyncInitTrigger(), we would set the CheckTrigger function before
validating the counter value.

As a result, if the counter value overflowed, we would leave the
function SyncInitTrigger() with the CheckTrigger applied but without
updating the trigger object.

To avoid that issue, move the portion of code checking for the trigger
check value before updating the CheckTrigger function.

Related to CVE-2025-26601, ZDI-CAN-25870

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit f52cea2f93)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
1932abe3d0 sync: Do not let sync objects uninitialized
When changing an alarm, the change mask values are evaluated one after
the other, changing the trigger values as requested and eventually,
SyncInitTrigger() is called.

SyncInitTrigger() will evaluate the XSyncCACounter first and may free
the existing sync object.

Other changes are then evaluated and may trigger an error and an early
return, not adding the new sync object.

This can be used to cause a use after free when the alarm eventually
triggers.

To avoid the issue, delete the existing sync object as late as possible
only once we are sure that no further error will cause an early exit.

CVE-2025-26601, ZDI-CAN-25870

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 16a1242d0f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
842f4abde4 dix: Dequeue pending events on frozen device on removal
When a device is removed while still frozen, the events queued for that
device remain while the device itself is freed.

As a result, replaying the events will cause a use after free.

To avoid the issue, make sure to dequeue and free any pending events on
a frozen device when removed.

CVE-2025-26600, ZDI-CAN-25871

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 6e0f332ba4)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
318085a6f5 composite: initialize border clip even when pixmap alloc fails
If it fails to allocate the pixmap, the function compAllocPixmap() would
return early and leave the borderClip region uninitialized, which may
lead to the use of uninitialized value as reported by valgrind:

 Conditional jump or move depends on uninitialised value(s)
    at 0x4F9B33: compClipNotify (compwindow.c:317)
    by 0x484FC9: miComputeClips (mivaltree.c:476)
    by 0x48559A: miValidateTree (mivaltree.c:679)
    by 0x4F0685: MapWindow (window.c:2693)
    by 0x4A344A: ProcMapWindow (dispatch.c:922)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)
  Uninitialised value was created by a heap allocation
    at 0x4841866: malloc (vg_replace_malloc.c:446)
    by 0x4F47BC: compRedirectWindow (compalloc.c:171)
    by 0x4FA8AD: compCreateWindow (compwindow.c:592)
    by 0x4EBB89: CreateWindow (window.c:925)
    by 0x4A2E6E: ProcCreateWindow (dispatch.c:768)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)

 Conditional jump or move depends on uninitialised value(s)
    at 0x48EEDBC: pixman_region_translate (pixman-region.c:2233)
    by 0x4F9255: RegionTranslate (regionstr.h:312)
    by 0x4F9B7E: compClipNotify (compwindow.c:319)
    by 0x484FC9: miComputeClips (mivaltree.c:476)
    by 0x48559A: miValidateTree (mivaltree.c:679)
    by 0x4F0685: MapWindow (window.c:2693)
    by 0x4A344A: ProcMapWindow (dispatch.c:922)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)
  Uninitialised value was created by a heap allocation
    at 0x4841866: malloc (vg_replace_malloc.c:446)
    by 0x4F47BC: compRedirectWindow (compalloc.c:171)
    by 0x4FA8AD: compCreateWindow (compwindow.c:592)
    by 0x4EBB89: CreateWindow (window.c:925)
    by 0x4A2E6E: ProcCreateWindow (dispatch.c:768)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)

 Conditional jump or move depends on uninitialised value(s)
    at 0x48EEE33: UnknownInlinedFun (pixman-region.c:2241)
    by 0x48EEE33: pixman_region_translate (pixman-region.c:2225)
    by 0x4F9255: RegionTranslate (regionstr.h:312)
    by 0x4F9B7E: compClipNotify (compwindow.c:319)
    by 0x484FC9: miComputeClips (mivaltree.c:476)
    by 0x48559A: miValidateTree (mivaltree.c:679)
    by 0x4F0685: MapWindow (window.c:2693)
    by 0x4A344A: ProcMapWindow (dispatch.c:922)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)
  Uninitialised value was created by a heap allocation
    at 0x4841866: malloc (vg_replace_malloc.c:446)
    by 0x4F47BC: compRedirectWindow (compalloc.c:171)
    by 0x4FA8AD: compCreateWindow (compwindow.c:592)
    by 0x4EBB89: CreateWindow (window.c:925)
    by 0x4A2E6E: ProcCreateWindow (dispatch.c:768)
    by 0x4A25B5: Dispatch (dispatch.c:560)
    by 0x4B082A: dix_main (main.c:282)
    by 0x429233: main (stubmain.c:34)

Fix compAllocPixmap() to initialize the border clip even if the creation
of the backing pixmap has failed, to avoid depending later on
uninitialized border clip values.

Related to CVE-2025-26599, ZDI-CAN-25851

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit b07192a8be)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
40efa6359c composite: Handle failure to redirect in compRedirectWindow()
The function compCheckRedirect() may fail if it cannot allocate the
backing pixmap.

In that case, compRedirectWindow() will return a BadAlloc error.

However that failure code path will shortcut the validation of the
window tree marked just before, which leaves the validate data partly
initialized.

That causes a use of uninitialized pointer later.

The fix is to not shortcut the call to compHandleMarkedWindows() even in
the case of compCheckRedirect() returning an error.

CVE-2025-26599, ZDI-CAN-25851

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit c1ff84bef2)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
cc15c9fa40 Xi: Fix barrier device search
The function GetBarrierDevice() would search for the pointer device
based on its device id and return the matching value, or supposedly NULL
if no match was found.

Unfortunately, as written, it would return the last element of the list
if no matching device id was found which can lead to out of bounds
memory access.

Fix the search function to return NULL if not matching device is found,
and adjust the callers to handle the case where the device cannot be
found.

CVE-2025-26598, ZDI-CAN-25740

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit bba9df1a9d)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
39c7ed837b xkb: Fix buffer overflow in XkbChangeTypesOfKey()
If XkbChangeTypesOfKey() is called with nGroups == 0, it will resize the
key syms to 0 but leave the key actions unchanged.

If later, the same function is called with a non-zero value for nGroups,
this will cause a buffer overflow because the key actions are of the wrong
size.

To avoid the issue, make sure to resize both the key syms and key actions
when nGroups is 0.

CVE-2025-26597, ZDI-CAN-25683

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 0e4ed94952)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
60df821467 xkb: Fix computation of XkbSizeKeySyms
The computation of the length in XkbSizeKeySyms() differs from what is
actually written in XkbWriteKeySyms(), leading to a heap overflow.

Fix the calculation in XkbSizeKeySyms() to match what kbWriteKeySyms()
does.

CVE-2025-26596, ZDI-CAN-25543

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 80d69f0142)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
bfbb53e0b9 xkb: Fix buffer overflow in XkbVModMaskText()
The code in XkbVModMaskText() allocates a fixed sized buffer on the
stack and copies the virtual mod name.

There's actually two issues in the code that can lead to a buffer
overflow.

First, the bound check mixes pointers and integers using misplaced
parenthesis, defeating the bound check.

But even though, if the check fails, the data is still copied, so the
stack overflow will occur regardless.

Change the logic to skip the copy entirely if the bound check fails.

CVE-2025-26595, ZDI-CAN-25545

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

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 11fcda8753)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Peter Hutterer
80f8d0b8e2 dix: keep a ref to the rootCursor
CreateCursor returns a cursor with refcount 1 - that refcount is used by
the resource system, any caller needs to call RefCursor to get their own
reference. That happens correctly for normal cursors but for our
rootCursor we keep a variable to the cursor despite not having a ref for
ourselves.

Fix this by reffing/unreffing the rootCursor to ensure our pointer is
valid.

Related to CVE-2025-26594, ZDI-CAN-25544

Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit b0a09ba602)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
543708ae93 Cursor: Refuse to free the root cursor
If a cursor reference count drops to 0, the cursor is freed.

The root cursor however is referenced with a specific global variable,
and when the root cursor is freed, the global variable may still point
to freed memory.

Make sure to prevent the rootCursor from being explicitly freed by a
client.

CVE-2025-26594, ZDI-CAN-25544

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

v2: Explicitly forbid XFreeCursor() on the root cursor (Peter Hutterer
<peter.hutterer@who-t.net>)
v3: Return BadCursor instead of BadValue (Michel Dänzer
<michel@daenzer.net>)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 01642f263f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:11 +01:00
Olivier Fourdan
69f1580140 test: Fix xsync test
The xsync test is relying on the values being changed even in the case
of a BadMatch value.

Typically, it updates the delta but does not update the test type
comparison, so when passing a negative value, it generates a BadMatch.

That's actually not correct, and that will fail with the new fixes that
check the validity of the values prior to apply the changes.

Fix the test by updating the test type as needed.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 05e54fefaf)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1831>
2025-02-25 19:38:08 +01:00
Olivier Fourdan
f04096af3c Revert "xwayland: Don't run key behaviors and actions"
Due to a bug in gamescope who does not send the Wayland modifiers
events, this is causing a regression in X11 clients running on Xwayland
in gamescope, where the modifiers are not applied anymore.

This reverts commit cea92a3e09.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1790
See-also: https://github.com/ValveSoftware/gamescope/issues/1740
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1781>
2025-02-10 15:43:41 +01:00
Olivier Fourdan
ffc3aa63d3 Bump version to 24.1.5
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1769>
2025-02-05 13:51:33 +01:00
Olivier Fourdan
f18a83d6f1 xwayland/glamor: Disable GLAMOR after GBM cleanup
The cleanup function for GBM is called on the various error paths.

Once xwl_glamor_gbm_cleanup() has been called, GBM support is no longer
usable (and the corresponding data structures are freed), so there is
no way we can keep using GLAMOR after that point.

Make sure to explicitly disable GLAMOR support in that case, so we do
not crash later on trying to use GBM.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit e8784b7d89)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:06 +01:00
Michel Dänzer
f7e3397e4d xwayland/glamor: Clean-up GBM's screen private on failure
If we bail out initializing GBM glamor backend, the screen private for
the GBM backend may remain, pointing at freed memory.

To avoid that issue, make sure to clear up the screen's private for the
GBM backend.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1785
Signed-off-by: Michel Dänzer <michel@daenzer.net>
(cherry picked from commit b27b5cd5f3)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:06 +01:00
Julian Orth
cea92a3e09 xwayland: Don't run key behaviors and actions
Consider the following keymap:

```xkb
xkb_keymap {
    xkb_keycodes {
        <compose> = 135;
    };
    xkb_symbols {
        key <compose> {
            [ SetGroup(group = +1) ]
        };
    };
};
```

When the user presses the compose key, the following happens:

1. The compositor forwards the key to Xwayland.
2. Xwayland executes the SetGroup action and sets the base_group to 1
   and the effective group to 1.
3. The compositor updates its own state and sends the effective group,
   1, to Xwayland.
4. Xwayland sets the locked group to 1 and the effective group to
   1 + 1 = 2.

This is wrong since pressing compose should set the effective group to 1
but to X applications the effective group appears to be 2.

This commit makes it so that Xwayland completely ignores the key
behaviors and actions of the keymap and only updates the modifier and
group components in response to the wayland modifiers events.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
(cherry picked from commit 45c1d22ff6)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:06 +01:00
Julian Orth
1a8f0cb007 xwayland: copy repeat settings from the compositor map
Previously the repeat settings sent by the compositor were completely
ignored.

Signed-off-by: Julian Orth <ju.orth@gmail.com>
(cherry picked from commit 8d9184db5f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:06 +01:00
Pierre-Eric Pelloux-Prayer
e6a5d545ce glamor: reject configs using unsupported rgbBits size
The supported color depths is a hardcoded list for now, so we
need to honor the value exposed there otherwise we'll get
inconsistencies between what glXGetFBConfigs and XListDepths
report to applications.

Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
(cherry picked from commit 5397854877)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:06 +01:00
Pierre-Eric Pelloux-Prayer
e1b6193a9d glamor: use gbm_format_for_depth instead of open-coding it
This way glamor_back_pixmap_from_fd deals with the same depth
values as glamor_pixmap_from_fds.

Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
(cherry picked from commit 83b13387ab)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:05 +01:00
Pierre-Eric Pelloux-Prayer
f8e32cba6e glamor: return the result of gbm_format_for_depth
This way the caller knows if the conversion failed.
While at it, check for width/height at the same time.

Signed-off-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
(cherry picked from commit 87afcc7699)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 18:14:05 +01:00
Olivier Fourdan
1ae92b8f63 os/connection: Make sure partial is initialized
Following the change in Xtrans 1.5 that allows for partial connections
to succeed, we need to make sure partial is properly initialized at
first, otherwise we rely on an uninitialized variable.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Twaik Yont <twaikyont@gmail.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1783
(cherry picked from commit 080fb49eff)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:21:13 +01:00
Olivier Fourdan
ffd4d2a268 xkb: Always use MAP_LENGTH keymap size
Generating the modifier modmap, the helper function generate_modkeymap()
would check the entire range up to the MAP_LENGTH.

However, the given keymap might have less keycodes than MAP_LENGTH, in
which case we would go beyond the size of the modmap, as reported by
ASAN:

==ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1 at 0x5110001c225b thread T0
    #0 0x5e7369393873 in generate_modkeymap ../dix/inpututils.c:309
    #1 0x5e736930dcce in ProcGetModifierMapping ../dix/devices.c:1794
    #2 0x5e7369336489 in Dispatch ../dix/dispatch.c:550
    #3 0x5e736934407d in dix_main ../dix/main.c:275
    #5 0x7e46d47b2ecb in __libc_start_main
    #6 0x5e73691be324 in _start (xserver/build/hw/xwayland/Xwayland)

Address is located 0 bytes after 219-byte region
allocated by thread T0 here:
    #0 0x7e46d4cfc542 in realloc
    #1 0x5e73695aa90e in _XkbCopyClientMap ../xkb/xkbUtils.c:1142
    #2 0x5e73695aa90e in XkbCopyKeymap ../xkb/xkbUtils.c:1966
    #3 0x5e73695b1b2f in XkbDeviceApplyKeymap ../xkb/xkbUtils.c:2023
    #4 0x5e73691c6c18 in keyboard_handle_keymap ../hw/xwayland/xwayland-input.c:1194

As MAP_LENGTH is used in various code paths where the max keycode might
not be easily available, best is to always use MAP_LENGTH to allocate the
keymaps so that the code never run past the buffer size.

If the max key code is smaller than the MAP_LENGTH limit, fill-in the gap
with zeros.

That also simplifies the code slightly as we do not constantly need to
reallocate the keymap to adjust to the max key code size.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1780
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 92bcebfd7e)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:21:04 +01:00
Olivier Fourdan
efd3e1ca3d xwayland: Do not keep the cursor's pixmap around
Currently, Xwayland creates a pixmap backed by shared memory buffer as
soon as an X11 cursor is realized, which is destroyed when the cursor is
eventually unrealized.

If an X11 client is leaking cursors, Xwayland will be creating new
pixmaps continuously, which will eventually cause an error once the
limit is reached, and get Xwayland killed.

However, we do not need the shared memory buffer to stay around, we
already have the buffer retention mechanism which will take care of
keeping the buffer around until the Wayland compositor is done with it,
so we could just create and destroy the pixmap as needed when setting
the cursor.

That would not fix the leak in the X11 application, yet that would
mitigate the risk of Xwayland being killed by reaching the shared memory
limits, until the client itself reaches the limit of X11 resources.

v2: Don't increase the pixmap refcnt to destroy it just after (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Suggested-by: Michel Dänzer <michel@daenzer.net>
See-also: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1773
(cherry picked from commit 8707d2835c)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:20:54 +01:00
Michel Dänzer
5294c436ac xwayland: Always decrement expecting_event in xwl_output_create
If we bail without decrementing it, xwl_screen_init will keep waiting
indefinitely for an event which never arrives.

(cherry picked from commit 8c4b137237)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:19:58 +01:00
Michel Dänzer
15a169cd1a xwayland/glamor: Drop expecting_event bailing from xwl_drm_handle_device
If we bail without decrementing xwl_screen->expecting_event,
xwl_screen_init will keep waiting indefinitely for an event which never
arrives.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1648
Fixes: 2f113d68f6 ("xwayland: Add glamor and DRI3 support")
(cherry picked from commit 375c35a5e4)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:19:48 +01:00
Alan Coopersmith
f221e9f903 dix-config.h: add HAVE_SOCKLEN_T definition
Needed to build with IPv6 disabled using gcc 14 on some platforms to avoid:

In file included from /usr/X11/include/X11/Xtrans/transport.c:67,
                 from xstrans.c:17:
/usr/X11/include/X11/Xtrans/Xtranssock.c: In function ‘_XSERVTransSocketOpen’:
/usr/X11/include/X11/Xtrans/Xtranssock.c:467:28: error: passing argument 5
 of ‘getsockopt’ from incompatible pointer type [-Wincompatible-pointer-types]
  467 |             (char *) &val, &len) == 0 && val < 64 * 1024)
      |                            ^~~~
      |                            |
      |                            size_t * {aka long unsigned int *}

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit a1b5aa5a7f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:19:33 +01:00
Michel Dänzer
7c25024879 xwayland/present: Check allow_commits in xwl_present_flip
We're not supposed to call wl_surface_commit while
xwl_window->allow_commits is false. Bailing results in falling back to
a copy.

Noticed by inspection while looking into an issue which turned out to be
due to something else.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1764
(cherry picked from commit 56ba0b2a5f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:19:14 +01:00
Alan Coopersmith
f340f082b8 dix: limit checks to MAX_VALUATORS when generating Xi events
Previously, it was looping through sizeof(ev->valuators.mask) * 8
valuators, where valuators.mask is defined as an array of
(MAX_VALUATORS + 7) / 8 entries.  Since MAX_VALUATORS is defined as 36,
this made it actually loop through 40 entries.  The last 4 bits in this
array should never be set, so we should never access memory outside the
bounds of the arrays defined to be exactly MAX_VALUATORS in length, but
we can make the static analyzer happier and not waste time checking bits
that should never be set.

Found by Oracle Parfait 13.3 static analyzer:

   Read outside array bounds [read-outside-array-bounds]:
      In array dereference of ev->valuators.data[i] with index i
      Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
        at line 741 of dix/eventconvert.c in function 'eventToDeviceEvent'.

   Read outside array bounds [read-outside-array-bounds]:
      In array dereference of ev->valuators.data[i] with index i
      Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
        at line 808 of dix/eventconvert.c in function 'eventToRawEvent'.

   Read outside array bounds [read-outside-array-bounds]:
      In array dereference of ev->valuators.data_raw[i] with index i
      Array size is 36 elements (of 8 bytes each), index >= 0 and index <= 39
        at line 809 of dix/eventconvert.c in function 'eventToRawEvent'.

Fixes: b2ba77bac ("dix: add EventToXI2 and GetXI2Type.")
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit b65eea43dd)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:18:51 +01:00
Alan Coopersmith
30427d3ddc dix: fix button offset when generating DeviceButtonStateNotify events
Found by Oracle Parfait 13.3 static analyzer:
   Buffer Overflow in STD C function [buffer-overflow-call-stdc]:
      Buffer overflow in call to memcpy. Buffer &bev->buttons[4] of
       size 24 is written at an offset of 28
      Array size is 28 bytes, index is 32
        at line 743 of dix/enterleave.c in function
	 'DeliverStateNotifyEvent'.

Fixes: a85f0d6b9 ("Xi: fix use of button->down - bitflags instead of int arrays.")
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 4b073d65bb)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:18:43 +01:00
Alan Coopersmith
5e320e1193 render: avoid NULL pointer dereference if PictureFindVisual returns NULL
Found by Oracle Parfait 13.3:
   Null pointer dereference [null-pointer-deref]:
      Read from null pointer pVisual
        at line 257 of dix/colormap.c in function 'CreateColormap'.
          Null pointer introduced at line 412 of render/picture.c in
	   function 'PictureFindVisual'.
          Constant 'NULL' passed into function CreateColormap, argument
	   pVisual, from call at line 431 in function
	   'PictureInitIndexedFormat'.
          Function PictureFindVisual may return constant 'NULL' at
	   line 412, called at line 429.

Fixes: d4a101d4e ("Integration of DAMAGE-XFIXES branch to trunk")
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 7af077dd2f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:18:34 +01:00
Alan Coopersmith
cec5c7c3b2 Xi: avoid NULL pointer dereference if GetXTestDevice returns NULL
The comments in that function say "This only happens if master is a
slave device. don't do that" but static analysis doesn't respect that.

Found by Oracle Parfait 13.3:
   Null pointer dereference [null-pointer-deref]:
      Read from null pointer XTestptr
        at line 274 of Xi/xichangehierarchy.c in function 'remove_master'.
          Null pointer introduced at line 691 of Xext/xtest.c in function
	   'GetXTestDevice'.
          Function GetXTestDevice may return constant 'NULL' at line 691,
	   called at line 273 of Xi/xichangehierarchy.c in function
	   'remove_master'.
   Null pointer dereference [null-pointer-deref]:
      Read from null pointer XTestkeybd
        at line 279 of Xi/xichangehierarchy.c in function 'remove_master'.
          Null pointer introduced at line 691 of Xext/xtest.c in function
	   'GetXTestDevice'.
          Function GetXTestDevice may return constant 'NULL' at line 691,
	   called at line 278 of Xi/xichangehierarchy.c in function
	   'remove_master'.

Fixes: 0814f511d ("input: store the master device's ID in the devPrivate for XTest devices.")
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit d10589cc09)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:18:26 +01:00
Michel Dänzer
a939e47c13 xwayland/glamor/gbm: Don't close fence_fd after xwl_glamor_wait_fence
eglCreateSyncKHR takes ownership of the file descriptor. Noticed by
inspection.

While we're at it, move the fence_fd declaration to the scope where
it's used.

Last but not least, close the fd in xwl_glamor_wait_fence when bailing
before calling eglCreateSyncKHR, and document that it takes ownership.

(cherry picked from commit 91b5a003a5)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:17:46 +01:00
Alan Coopersmith
ce9d187101 os: NextDPMSTimeout: mark intentional fallthroughs in switch
The comment at the top of the function tells humans the fallthroughs
are intentional, but gcc doesn't parse that.

Clears 3 -Wimplicit-fallthrough warnings from gcc 14.1

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit b306df5a60)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:17:35 +01:00
YaoBing Xiao
ca0799e7f2 xwayland: prevent potential null pointer dereference
Signed-off-by: YaoBing Xiao <xiaoyaobing@uniontech.com>
(cherry picked from commit e12d9863fd)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1766>
2025-02-04 09:16:51 +01:00
José Expósito
3bfef8d7c0 Bump version to 24.1.4
Signed-off-by: José Expósito <jexposit@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1735>
2024-10-29 16:27:04 +01:00
Matthieu Herrb
26120df7aa xkb: Fix buffer overflow in _XkbSetCompatMap()
The _XkbSetCompatMap() function attempts to resize the `sym_interpret`
buffer.

However, It didn't update its size properly. It updated `num_si` only,
without updating `size_si`.

This may lead to local privilege escalation if the server is run as root
or remote code execution (e.g. x11 over ssh).

CVE-2024-9632, ZDI-CAN-24756

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

Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Tested-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: José Expósito <jexposit@redhat.com>
(cherry picked from commit 85b7765714)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1735>
2024-10-29 16:26:59 +01:00
Olivier Fourdan
113245b1ab Bump version to 24.1.3
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1708>
2024-10-02 10:02:15 +02:00
Mike Blumenkrantz
0713e7e382 xwayland: connect to the wl display before calling into EGL
using EGL (e.g., eglQueryString, epoxy_has_egl_extension)
before establishing this connection
enables the GBM/EGL implementation to potentially consume the
WAYLAND_SOCKET fd, which, if closed, will cause the compositor
to kill this xserver

(cherry picked from commit ff8ec59c97)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 11:33:13 +02:00
Olivier Fourdan
8d9b8249a7 os: Fix NULL pointer dereference
RemoveHost() can be called from DisableLocalHost() with a NULL client,
but doesn't actually check whether the given client pointer is valid on
error and assigns the error value unconditionally, leading to a possible
NULL pointer dereference and a crash of the Xserver.

To avoid the issue, simply check whether the client pointer is not NULL
prior to assign the errorValue.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1752
See-also: https://bugzilla.redhat.com/2313799
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 57a446c0f9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 11:33:13 +02:00
Alan Coopersmith
02546fa66a CI: update libdecor from 0.1.0 to 0.1.1
The install_demo meson_option was added in
libdecor/libdecor@7106f5e329
which is in the 0.1.1 tag, but not 0.1.0.

If we upgrade the version of meson used in the CI to 1.0.0, then it fails
to build libdecor 0.1.0 with: ERROR: Unknown options: "install_demo"

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 32adf434b7)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 11:33:02 +02:00
Alan Coopersmith
e4d9cbf0e9 CI: clone libdecor from fd.o instead of gnome.org
https://gitlab.gnome.org/jadahl/libdecor is archived and the README
says to use  https://gitlab.freedesktop.org/libdecor/libdecor instead.

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit fc8ba24413)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 11:31:46 +02:00
Alan Coopersmith
5d84e4779b dix: FindBestPixel: fix implicit fallthrough warning
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 9c9e1afeb2)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:51:08 +02:00
Alan Coopersmith
2d5494ebbb dix: GetPairedDevice: check if GetMaster returned NULL
Clears warning from gcc 14.1:

../dix/devices.c: In function ‘GetPairedDevice’:
../dix/devices.c:2734:15: warning: dereference of NULL ‘dev’
 [CWE-476] [-Wanalyzer-null-dereference]
 2734 |     return dev->spriteInfo? dev->spriteInfo->paired: NULL;
      |            ~~~^~~~~~~~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit e6fc0861d8)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:51:04 +02:00
Alan Coopersmith
cfda3969a1 dix: HashResourceID: use unsigned integers for bit shifting
Clears warning from gcc 14.1:

../dix/resource.c: In function ‘HashResourceID’:
../dix/resource.c:691:44: warning: left shift of negative value
 [-Wshift-negative-value]
  691 |     return (id ^ (id >> numBits)) & ~((~0) << numBits);
      |                                            ^~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 26a7ab09ea)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:51:00 +02:00
Alan Coopersmith
4335bdeb01 dix: ProcListProperties: skip unneeded work if numProps is 0
No real harm, but clears warning from gcc 14.1:

../dix/property.c: In function ‘ProcListProperties’:
..//dix/property.c:605:27: warning: dereference of NULL ‘temppAtoms’
 [CWE-476] [-Wanalyzer-null-dereference]
  605 |             *temppAtoms++ = pProp->propertyName;
      |             ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 39f337fd49)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:57 +02:00
Alan Coopersmith
6d384ab8bf dix: dixChangeWindowProperty: don't call memcpy if malloc failed
It shouldn't matter, since it would have a length of 0, but it
clears warnings from gcc 14.1:

../dix/property.c: In function ‘dixChangeWindowProperty’:
../dix/property.c:287:9: warning: use of possibly-NULL ‘data’ where
 non-null expected [CWE-690] [-Wanalyzer-possible-null-argument]
  287 |         memcpy(data, value, totalSize);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../dix/property.c:324:13: warning: use of possibly-NULL ‘data’ where
 non-null expected [CWE-690] [-Wanalyzer-possible-null-argument]
  324 |             memcpy(data, value, totalSize);
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 10cafd0bbe)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:53 +02:00
Alan Coopersmith
fc7b6c7549 dix: InitPredictableAccelerationScheme: avoid memory leak on failure
Clears warning from gcc 14.1:

../dix/ptrveloc.c: In function ‘InitPredictableAccelerationScheme’:
../dix/ptrveloc.c:149:9: warning: leak of ‘<unknown>’
 [CWE-401] [-Wanalyzer-malloc-leak]
  149 |         free(vel);
      |         ^~~~~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 462d13c2f6)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:50 +02:00
Alan Coopersmith
83033ce108 dix: CreateScratchGC: avoid dereference of pointer we just set to NULL
Clears warning from gcc 14.1:

../dix/gc.c: In function ‘CreateScratchGC’:
../dix/gc.c:818:28: warning: dereference of NULL ‘pGC’
 [CWE-476] [-Wanalyzer-null-dereference]
  818 |     pGC->graphicsExposures = FALSE;

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 7ee3a52018)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:47 +02:00
Alan Coopersmith
44d1b7e4c1 dix: enterleave.c: fix implicit fallthrough warnings
Clears 7 -Wimplicit-fallthrough warnings from gcc 14.1

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 0cb826e3d0)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:43 +02:00
Alan Coopersmith
013311852d dix: SetFontPath: don't set errorValue on Success
Clears warning from gcc 14.1:

../dix/dixfonts.c: In function ‘SetFontPath’:
../dix/dixfonts.c:1697:28: warning: use of uninitialized value ‘bad’
 [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
 1697 |         client->errorValue = bad;
      |         ~~~~~~~~~~~~~~~~~~~^~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 1a86fba0d9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:40 +02:00
Alan Coopersmith
2f1ea65b6d dix: PolyText: fully initialize local_closure
Clears warning from gcc 14.1:

../dix/dixfonts.c:1352:15: warning: use of uninitialized value ‘*c.data’
 [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
 1352 |         free(c->data);
      |              ~^~~~~~

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit d78836a3a6)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:36 +02:00
Alan Coopersmith
0d1b7672e7 dix: check for calloc() failure in Xi event conversion routines
Clears up 12 -Wanalyzer-possible-null-dereference warnings from gcc 14.1

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 25762834c9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:33 +02:00
Olivier Fourdan
a73fb98dc3 build: Fix DRI3 on DragonFly and OpenBSD
Commit 96bdc156 added a check for <sys/eventfd.h> to enable DRI3.

DragonFly and OpenBSD however rely on epoll-shim for <sys/eventfd.h>,
so that must be added as a dependency for the <sys/eventfd.h> check.

Fixes: commit 96bdc156 - xwayland: Do not enable DRI3 without eventfd
Suggested-by: Jan Beich <jbeich@freebsd.org>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 8fe15a60c5)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:29 +02:00
Olivier Fourdan
98fb1d48c4 build: Add epoll to Xwayland for DragonFly and OpenBSD
DragonFly and OpenBSD rely on epoll-shim for <sys/eventfd>, add a
optional dependency to build Xwayland.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 7bcf2bcafc)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:50:25 +02:00
Olivier Fourdan
b701969331 build: Move epoll dependency check
DragonFly and OpenBSD rely on epoll-shim to provide eventfd.

Move the check for epoll dependency to the root meson.build script so
that we can use that for the <sys/evenfd.h> check as well.

This is preparation work for the following commits, no functional change
intended at this point.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 673b56e61c)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:49:33 +02:00
Peter Hutterer
16645b410d Xi: when removing a master search for a disabled paired device
If either the master pointer or keyboard was disabled, the respective
GetMaster() call returns NULL, causing a segfault later accessing the
deviceid.

Fix this by looking in the off_devices list for any master
device of the type we're looking for. Master devices lose the pairing
when disabled (on enabling a keyboard we simply pair with the first
available unpaired pointer).

And for readability, split the device we get from the protocol request
into a new "dev" variable instead of re-using ptr.

Fixes #1611

(cherry picked from commit e7c876ab0b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:48:02 +02:00
Peter Hutterer
13cfe2ec85 dix: don't push the XKB state to a non-existing master keyboard
If our master keyboard is disabled, GetMaster() returns NULL and
we segfault in XkbPushLockedStateToSlaves().

Fixes 45fb3a934d
Fixes #1611

(cherry picked from commit 9b983fecf9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:47:58 +02:00
Matthieu Herrb
11d0f4f19d Return NULL in *cmdname if the client argv or argv[0] is NULL
(cherry picked from commit 59f5445a7f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:47:54 +02:00
Matthieu Herrb
e50ea9181a Don't crash if the client argv or argv[0] is NULL.
Report from  bauerm at pestilenz dot org.

(cherry picked from commit a8512146ba)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:47:51 +02:00
Olivier Fourdan
fa70fdf961 xwayland: Report correct mode size when rootful
The vidmode extension emulation in Xwayland reports the modeline based
on the current mode.

To do so, it searches for the mode using `xwl_output_find_mode(-1, -1)`
which is supposed to return the current mode, whatever that mode is.

With XRandR emulation, in rootless mode, the default value is the mode
at index 0. That assumption, however is not true when running rootful.

That means that the vidmode extension will always return the highest
mode available, which is 5120x2880, with Xwayland running rootful:

  $ xwayland-run -geometry 1024x768 -- xvidtune -show
  "5120x2880"   1276.50   5120 5560 6128 7136   2880 2883 2888 2982 -hsync +vsync

Luckily, when Xwayland is running rootful, we have the current mode size
conveniently stored in dedicated fields of the xwayland output struct,
so we can use that to search for the right mode being used and report
that through the vidmode extension:

  $ xwayland-run -geometry 1024x768 -- xvidtune -show
  "1024x768"     63.50   1024 1064 1176 1328    768  771  775  798 -hsync +vsync

That fixes legacy games using the vidmode extension and rendering at the
wrong size when running within Xwayland rootful.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit e2e5842444)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1702>
2024-09-24 10:47:47 +02:00
Olivier Fourdan
05a3a4068b Bump version to 24.1.2
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1638>
2024-08-07 11:22:21 +02:00
Ian Douglas Scott
4262fb182b xwayland: Release keys on keyboard enter event if leave wasn't received
The code here assumed a `leave` event always occurs between two `enter`
events. On Sway (and presumably other compositors) this happens even if
the client has destroyed the `wl_surface`, but the client gets a null
`surface` here. (Which presumably on on the wire is the id of the
destroyed surface.)

This seems like a bad thing to rely on, and is easy to avoid. But if
this is correct to assume, the Wayland protocol should be explicit about
this.

(cherry picked from commit 386b54fbe9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
54a591b9b8 xwayland: Do not include sys/eventfd.h without DRI3
Now that we won't enable DRI3 if <sys/eventfd.h> is not available, there
is not point in trying to include that header without DRI3.

That allows to build Xwayland with GLAMOR enabled (without DRI3) on
platforms which do not support eventfd.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 23c295ea8b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
4d88af2228 xwayland: Do not enable DRI3 without eventfd
DRI3 version 1.4 which supports explicit buffers synchronization relies
on the eventfd interface.

As result, building would fail with DRI3 enabled on platforms without
the eventfd interface.

Check for the availability of the sys/eventfd.h header and disable DRI3
support if missing.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 96bdc156a1)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
2a360e5c0f xwayland: Fix build without DRI3 enabled
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1668
(cherry picked from commit a58352b985)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Nicolas Dufresne
a2446275c9 glamor: xv: Rewrite UYVY shader to match NV12/I420 CSC
This rewrites the shader so that we use the same (more flexible) CSC as
we have for I420 and NV12. This also fixes the reverse of odd/even which
caused chroma shift.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
(cherry picked from commit 39c8a6f367)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Konstantin
978093d1a5 glamor: xv: fix UYVY alignment
UYVY videos should be aligned by 2 to avoid breakups in the shader

Fixes: 832b392f7 - glamor: xv: enable UYVY acceleration
Suggested-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Konstantin <ria.freelander@gmail.com>
(cherry picked from commit eb26f32368)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Konstantin
4543d4a25a glamor: check BPP by render_format.
Check actual BPP by render_format in upload_boxes, not by drawable BPP.

It is required when we used different BPP formats for storing and
rendering (for example, in the case of UYVY).

The problem of UYVY size lies inside method of glamor downloading boxes.

When we set GLAMOR_CREATE_FORMAT_CBCR, it actually uses 16-bit GL and
Pixman formats, but before this change in glamor_download_boxes, that
function deduces GL and Pixman formats from BPP, which is wrong in this
case (will be deduced to 32).

When GL and Pixman format BPP is identical to drawable BPP, this change
does nothing, but when it is different - it will prioritize Pixman
format, not the format deduced from BPP.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1730
Signed-off-by: Konstantin Pugin <ria.freelander@gmail.com>
(cherry picked from commit 75f56b7923)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
8937d47d08 xwayland/ei: Dequeue events when all caps are available
Currently, we would start dequeuing events as soon as a device is
resumed, regardless of its capabilities.

If the capabilities are not available, we would just fallback to the
regular XTEST code path and not use input emulation.

As a result, it is very likely that we shall lose the first events until
the compositor resumes first a device with the requested capabilities.

To avoid that issue, start emulating only once we have the requested
capabilities, if they match the seat capabilities.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1732
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 0525b9a5b9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
a1651d41e7 xwayland/ei: Move code to helper function
This is a small code refactoring to help with clarity, simply move the
code from the switch case for device resume to a dedicated function.

No functional change.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 68ec297ee9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
b3635ba69e glamor: Fix possible double-free
If glamor_link_glsl_prog() fails, we may jump to the failed code path
which frees the variable vs_prog_string and fs_prog_string.

But those variables were already freed just before, so in that case we
end up freeing the memory twice.

Simply move the free at the end of the success code path so we are sure
to free the values only once, either in the successful of failed code
paths.

Fixes: 2906ee5e4 - glamor: Fix leak in glamor_build_program()
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 34ea020344)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
fac3486a66 xwayland/ei: Log the type name of unhandled events
Currently, we would log only the event type, use the libei API to also
log the name in plain text, so we can quickly identify the events we're
missing out.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 1a42fe40d0)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
ce7fb8139a xwayland/ei: Handle EI_EVENT_KEYBOARD_MODIFIERS
Although we do not do anything with that event, handle it so we don't
end up in the "Unhandled event" territory.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1722
Fixes: a133334270 - xwayland: Add XTEST support using EIS
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit bfabd3bdab)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Olivier Fourdan
98326b8c9f xwayland: Make sure output is suitable for fullscreen
Since commit d370f1e58, Xwayland can optionally be started rootful and
fullscreen.

To do so, it will setup a viewport to scale the root window to match the
size of the output.

However, if the rootful Xwayland window receives an xdg-surface configure
event before the output definition is complete, as with e.g. the labwc
Wayland compositor, we might end up trying to setup a viewport with a
destination size of 0x0 which is a protocol violation, and that kills
Xwayland.

To avoid that issue, only setup the viewport if the output size is
meaningful.

Also, please note that once the output definition is complete, i.e. when
the "done" event is eventually received, we shall recompute the size for
fullscreen again, hence achieving the desired fullscreen state.

Fixes: d370f1e58 - xwayland: add fullscreen mode for rootful
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1717
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 66f5e7e96a)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Alan Coopersmith
ca52da8cba Move sizeof to second argument in calloc calls
Clears -Wcalloc-transposed-args warnings from gcc 14.1, such as:

../dix/main.c:165:42: warning: ‘calloc’ sizes specified with ‘sizeof’ in the
 earlier argument and not in the later argument [-Wcalloc-transposed-args]
  165 |             serverClient = calloc(sizeof(ClientRec), 1);
      |                                          ^~~~~~~~~
../dix/main.c:165:42: note: earlier argument should specify number of
 elements, later size of each element

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
(cherry picked from commit 522f469fe9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 10:00:59 +02:00
Joaquim Monteiro
c0bd91f49e os: Fix assignment with incompatible pointer type
struct hostent->h_addr_list is of type char**, not const char**.
GCC considers this an error when in C99 mode or later.

Signed-off-by: Joaquim Monteiro <joaquim.monteiro@protonmail.com>
(cherry picked from commit 0ddcd87851)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1635>
2024-08-06 09:54:01 +02:00
Olivier Fourdan
cec99a3811 Bump version to 24.1.1
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1602>
2024-07-10 13:40:59 +02:00
Olivier Fourdan
8130fa083c xwayland: Check for pointer in xwl_seat_leave_ptr()
Since commit 792758fa ("xwayland: Update lost focus on deactivation"),
in rootful mode, if we receive an "activated" state from xdg-shell
indicating that the surface is no longer active, we shall end up calling
xwl_seat_leave_ptr().

But xwl_seat_leave_ptr() does not actually check whether the seat has
pointer capabilities, and if not, get_pointer_device() will return NULL.

As a result, we would crash using a NULL pointer in GetMaster(). This
typically can happen when using Xwayland rootful on headless compositors
such as "cage" which do not advertise any capabilities for the seat.

To avoid the issue, simply check whether get_pointer_device() returns a
valid non-null device and bail out early otherwise.

Fixes: 792758fa - xwayland: Update lost focus on deactivation
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1700
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 7203626173)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1592>
2024-07-09 11:35:49 +02:00
Olivier Fourdan
38060228c1 xwayland: Force disposal of windows buffers for root on destroy
With explicit buffer synchronization in use, the window buffers use a
file descriptor for event notification to keep the buffer alive for
synchronization purpose.

When running rootful, the root window (which is visible) is destroyed
directly from the resource manager on server reset, and the window
buffer's eventfd will trigger after the window is destroyed, leading to
a use after free and a crash of the xserver.

To avoid the issue, check whether the window being destroyed is the root
window in rootless mode, and make sure to force the disposal of the
window buffers in that case.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1699
(cherry picked from commit a5e863963e)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
4942b7c137 xwayland/window-buffers: optionally force disposal
For cases (to come) where we would want to force the disposal of the
window buffers, add a parameter to force the disposal by calling
dispose() directly instead of maybe_dispose().

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit fa04e15afc)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
f834e104aa xwayland/window-buffers: Move buffer disposal to its own function
No functional change, this is just preparation work for the next commit.

v2: Reshuffle functions (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 571cb13342)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
aa0ea88e13 xwayland: Make sure we do not leak xwl_window on destroy
Right now, we would dispose the xwl_window and all the data associated
with it on unrealize.

But not all window destruction go through the unrealize code path, for
example when the root window (running rootful) is destroyed from the
resource manager on server reset, we do not get to the unrealize window
step, but straight to destroy window.

As a result, we are leaking the xwl_window and all the data associated
with it, for example:

| 65,536 bytes in 1 blocks are possibly lost in loss record 12,462 of 12,488
|    at 0x484A0FC: calloc (vg_replace_malloc.c:1675)
|    by 0x48B661C: UnknownInlinedFun (pixman-bits-image.c:1273)
|    by 0x48B661C: _pixman_bits_image_init (pixman-bits-image.c:1296)
|    by 0x48B6754: create_bits_image_internal (pixman-bits-image.c:1349)
|    by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:380)
|    by 0x64180DE: UnknownInlinedFun (cairo-image-surface.c:366)
|    by 0x64180DE: cairo_image_surface_create (cairo-image-surface.c:432)
|    by 0x6346B44: UnknownInlinedFun (libdecor-gtk.c:467)
|    by 0x6346B44: libdecor_plugin_gtk_frame_new (libdecor-gtk.c:546)
|    by 0x4B7F297: libdecor_decorate (libdecor.c:559)
|    by 0x42C6F3: xwl_create_root_surface (xwayland-window.c:1266)
|    by 0x42CD97: ensure_surface_for_window (xwayland-window.c:1466)
|    by 0x42D0D1: xwl_realize_window (xwayland-window.c:1560)
|    by 0x50858F: compRealizeWindow (compwindow.c:279)
|    by 0x4FF2A2: MapWindow (window.c:2706)
|    by 0x4F9E7F: InitRootWindow (window.c:697)

To avoid that issue, check whether there is still an xwl_window
associated with the X11 window on destroy, and if that's the case,
dispose the xwl_window.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 0e1a98f52f)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
6a916c9658 xwayland: Move xwl_window disposal to its own function
No functional change intended, this is just preparation work for the
next commit.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 74be7a7f36)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
8f611b0f22 xwayland/window-buffers: Set syncpnts for all pixmaps
The wp_linux_drm_syncobj_v1 protocol states that :

| If at surface commit time there is a pending buffer attached but no
| pending release timeline point set, the no_release_point protocol
| error is raised.

So we need to set a release timeline point in any case from the swap
pixmap routine, even for the early out code paths.

Failing to do so may cause a Wayland protocol error that is fatal to the
Wayland client, in this case Xwayland:

| wp_linux_drm_syncobj_surface_v1: error 4: No Acquire point provided
| (EE) failed to dispatch Wayland events: Protocol error

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1688
Fixes: 87bf2cafcc - xwayland: add support for wp_linux_drm_syncobj_v1
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit bc9bf56360)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
33486519dc xwayland/window-buffers: Move code to submit pixmaps
Move the code which takes care of submitting pixmaps and the
synchronization points to its own function.

This will allow to reuse that code from different code path.

No functional change intended.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 33330f0dc9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
6636b7c003 xwayland/window-buffers: Do not always set syncpnts
The function xwl_window_swap_pixmap() can be called from two places,
either from xwl_window_attach_buffer() or from damage_report().

When called from xwl_window_attach_buffer(), the new buffer is attached
and the surface committed.

However, when called from damage_report(), a new buffer might not be
attached before the surface is committed.

That's fine with implicit synchronization, but if we use explicit
synchronization, committing a surface without a new buffer attached but
with a release timeline point set is a protocol error:

| If at surface commit time there is a pending release timeline point
| set but no pending buffer attached, a no_buffer error is raised.

To avoid such an issue, add a new parameter to xwl_window_swap_pixmap()
to hint whether it should set the synchronization points, and have the
synchronization points set only from xwl_window_attach_buffer().

v2: Rename param to handle_sync (Michel)

Suggested-by: Michel Dänzer <mdaenzer@redhat.com>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit aab01c7391)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
4382a4f84e xwayland/window-buffers: Use synchronization from GLAMOR/GBM
Now that we have the buffer synchronization implemented in the
GLAMOR/GBM code, switch to use that code.

At this point, there is still not functional change intended, this is
still preparation work for a fix that is still to come.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 256cef8b20)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
1539f208e2 xwayland/glamor/gbm: Copy explicit sync code to GLAMOR/GBM
Copy the code to deal with synchronization objects from the window
buffers to the GLAMOR/GBM code.

The idea is to deal with synchronizations for all pixmaps, even when
there is no window buffer involved.

This is still preparation work for the following commits, no functional
change intended at this point.

v2: Use a "xwl_window_buffer *" instead of a "void *data" (Michel)
v3: Bail early if there's no xwl_window_buffer (Michel)
v4: Rename xwl_window_submit_pixmap() to
    xwl_glamor_gbm_wait_release_fence() (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit cc021aca99)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
b1734ae737 xwayland/window-buffers: Add xwl_window_buffer_release()
We want to decorrelate the explicit buffer synchronization from the
window buffers, and move that to the GLAMOR/GBM code instead.

To do that, we need to be able to invoke the xwl_window_buffer's
release_callback() routine from outside the window buffer code.

For that purpose, introduce xwl_window_buffer_release() which calls
xwl_window_buffer_release_callback() for us.

This is preparation work for the following changes, no functional change
intended at this point.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit b5082073b0)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
23400afb72 xwayland/window-buffers: Promote xwl_window_buffer
Make the (opaque) definition of the xwl_window_buffer generally
available.

No functional change.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 0e0472a005)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
05f4411523 xwayland: Stop on first unmapped child
If a child window of the same size is unmapped, we should stop walking
the tree looking for the surface window to use.

Whatever lies beneath is not visible anyway.

This also fixes an issue with the Damage list becoming corrupted when
destroying a window, because the first thing that DeleteWindow() does
is to unmap the window and crush the window tree underneath it.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Fixes: 3a0fc268 - xwayland: Add xwl_window::surface_window
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1680
(cherry picked from commit 32e16082c5)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
fbd40e878b xwayland: Do not use manual redirect windows as surface window
While walking the window tree looking for the surface window to use, we
should ignore windows using manual redirection.

If a client manually redirects a window, it has control over how the
contents of that window are presented. It's not safe to present them
directly to the Wayland compositor.

v2: break instead of continue, reword commit message (Michel)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Fixes: 3a0fc268 - xwayland: Add xwl_window::surface_window
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1677
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1679
(cherry picked from commit 0509b13fa2)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Chenx Dust
526dcbe120 xwayland: fix segment fault in xwl_glamor_gbm_init_main_dev
Function `xwl_glamor_gbm_init_main_dev` does not check whether
`xwl_screen->default_feedback.main_dev` a.k.a. `main_dev` is a
valid pointer. This result in some special situation where main
linux-dmabuf device is not accessible, such as KWin nested desktop,
raising segment fault.

This commit add a null pointer check to prevent crashing.

Signed-off-by: Chenx Dust <chenx_dust@outlook.com>
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1683
Fixes: d7f1909e - xwayland/glamor/gbm: make wl_drm optional
See-also: https://bugzilla.redhat.com/2284141
(cherry picked from commit 7605833315)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Fotios Valasiadis
1d21f8db26 os: Explicitly include X11/Xmd.h for CARD32 definition to fix building on i686
Noticed this after trying to update to xorg-server-xwayland-24.1.0 in void linux https://github.com/void-linux/void-packages/pull/50457

Signed-off-by: Fotios Valasiadis <fvalasiad@gmail.com>
(cherry picked from commit af6180b2c9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Rouven Czerwinski
59bf93c770 xwayland: remove includedir from pkgconfig
Before this change, the xwayland pkgconfig file will always contain an
includedir directive, even though xwayland is not a linkable shared
library:

  prefix=/nix/store/3spcjqp5zcyg8arz6dnsj59fal5yk3jy-xwayland-23.2.6
  includedir=${prefix}/include

  exec_prefix=${prefix}
  xwayland=/nix/store/3spcjqp5zcyg8arz6dnsj59fal5yk3jy-xwayland-23.2.6/bin/Xwayland
  […]
  Cflags: -I${includedir}

According to a bug reporter this trips up cmake [1], which expects that
the include directory exists, which it does not since xwayland does not
install any header files.

Add the dataonly directive to pkgsconfig.generate() which will remove
the default "." subdir and ensures that includedir is not set inside the
pkgconfig file. Additionally enforce the install directory to
$libdir/pkgconfig, since it otherwise will be installed to
$datadir/pkgconfig, which precludes programs from finding the pkgconfig
because share/pkgconfig is usually not included in the search path.

The resulting pkgconfig does not contain an includedir:

  prefix=/nix/store/p7xhdzl65hfhzf36vxykzp2i9cyy7y6c-xwayland-23.2.6

  exec_prefix=${prefix}
  xwayland=/nix/store/p7xhdzl65hfhzf36vxykzp2i9cyy7y6c-xwayland-23.2.6/bin/Xwayland
  have_glamor=true
  have_eglstream=true
  have_initfd=true
  have_listenfd=true
  have_verbose=true
  have_terminate_delay=true
  have_no_touch_pointer_emulation=true
  have_force_xrandr_emulation=true
  have_geometry=true
  have_fullscreen=true
  have_host_grab=true
  have_decorate=false
  have_enable_ei_portal=true
  have_byteswappedclients=true

  Name: Xwayland
  Description: X Server for Wayland
  Version: 23.2.6

[1]: https://github.com/NixOS/nixpkgs/pull/309075#issuecomment-2108381428

Signed-off-by: Rouven Czerwinski <rouven@czerwinskis.de>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 9df084c8d1)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Matthieu Herrb
dc2e34aa0e present: On *BSD, epoll-shim is needed to emulate eventfd()
Signed-off-by: Matthieu Herrb <matthieu@herrb.eu>
(cherry picked from commit 89c3f35d92)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1569>
2024-07-04 08:36:40 +00:00
Olivier Fourdan
1126d55f80 Bump version to 24.1.0
Xwayland 24.1.0 final release

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1545>
2024-05-15 08:21:39 +02:00
Olivier Fourdan
ce0e52dd0b xwayland: Move XRandR emulation to the ResizeWindow hook
This restores the handling of the XRandR emulation for Xwayland rootless
where it was before commit fa7b1c20.

Some compositors may trigger a protocol error if the viewport source is
larger than the actual window size, having that handled in the window
resize hook makes sure we do not regress.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 702a419c39)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1535>
2024-05-13 13:43:31 +02:00
Olivier Fourdan
2d0dabbe10 xwayland: Handle rootful resize in ResizeWindow
Commit fa7b1c20 ("xwayland: Use ConfigNotify screen hook instead of
ResizeWindow") replaced the WindowResize hook with ConfigNotify.

However, that's breaking rootful Xwayland with libdecor because the root
window size is already set so the libdecor size is not updated, and the
root size will be reverted back as soon as the focus changes.

Reinstate the rootful size change in ResizeWindow to avoid that issue.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1669
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1671
Fixes: fa7b1c20 - xwayland: Use ConfigNotify screen hook instead of ResizeWindow
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 31d6f9998d)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1535>
2024-05-13 13:43:24 +02:00
Olivier Fourdan
ce6c665e77 xwayland: Restore the ResizeWindow handler
For now it just chains to ResizeWindow hook.

This is preparation work for the next commit, no functional change.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 539859bde0)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1535>
2024-05-13 13:43:21 +02:00
Joshua Ashton
3f4745cc4a xwayland: Send ei_device_frame on device_scroll_discrete
This fixes the scroll action in Steam Input in SteamOS/Gamescope when using the new libeis backend.

Fixes: a133334270 ("xwayland: Add XTEST support using EIS")
Signed-off-by: Joshua Ashton <joshua@froggi.es>
(cherry picked from commit 7745fde24e)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1535>
2024-05-13 13:43:07 +02:00
Vlad Zahorodnii
88ab664fab xwayland: Use correct xwl_window lookup function in xwl_set_shape
In xwl_set_shape(), xwl_window_set_input_region() should be called only
when the input shape of the toplevel window changes.

However, given that xwl_window_from_window() is going to walk the
ancestor tree until it finds an xwl_window, that lookup function cannot
be used. Instead, xwl_window_get() should be used. It's going to return
a valid xwl_window object iff the specified window has one associated
with it.

Fixes: a4ed100c0 - xwayland: Set wl_surface input region
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1672
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
Signed-off-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
(cherry picked from commit 8c2b9f4e71)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1535>
2024-05-13 13:42:41 +02:00
Olivier Fourdan
5a4b654334 Bump version to 24.0.99.902
Xwayland 24.1.0 release candidate 2.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1513>
2024-05-02 14:14:39 +02:00
Michel Dänzer
9f28e2a85d xwayland/present: Skip queued flip when a new one becomes ready
If multiple flips become ready for the same MSC, we would previously
execute them all sequentially, one per MSC for sync flips. This could
result in an unbounded flip queue and corresponding memory consumption.

With implicit sync, leave the mailbox handling to the compositor for
async flips though.

v2:
* Use present_vblank_rec::sync_flip.

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1664
Fixes: e1f16fb1ac ("xwayland: don't scrap pending present requests")
(cherry picked from commit 0d9a54aa97)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:50:04 +02:00
Erik Kurzinger
07470d2ca2 present: signal explicit sync release point in present_vblank_scrap
If a present request using explicit sync is scrapped, instead of sending
a PresentIdleNotify event we should signal the release point.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit 80f74b0e44)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:50:00 +02:00
Erik Kurzinger
f10354d16a xwayland: use write fence in xwl_glamor_dmabuf_import_sync_file
The functions xwl_glamor_dmabuf_import_sync_file and
xwl_glamor_dmabuf_export_sync_file are used to ensure proper
synchronization between clients using PresentPixmapSynced and
compositors that do not support the wp_linux_drm_syncobj_v1 protocol
when presenting by flipping. The acquire point's fence will be imported
as the DMA-BUF's implicit fence before handing it off to the compositor,
and then, after the DMA-BUF has been released, its new implicit fence
will be exported and become the release point's fence which the client
is expected to wait for before re-using the buffer.

Both functions currently set the flags arguments of their respective
ioctls to DMA_BUF_SYNC_READ. When importing a sync file, this means that
any subsequent implicitly synchronized reads from the buffer will not
wait for the fence, and when exporting a sync file it means that the
returned fence may be signaled before preceeding reads from the buffer
have completed.

While this is correct for xwl_glamor_dmabuf_export_sync_file since the
compositor will never write to the buffer, it is incorrect for
xwl_glamor_dmabuf_import_sync_file. To avoid corruption, we need any
reads from the buffer by the compositor to wait on the acquire point's
fence.

As a fix, instead of setting the DMA_BUF_SYNC_READ flag in
xwl_glamor_dmabuf_import_sync_file, we set the DMA_BUF_SYNC_WRITE flag.
This *does* provide the necessary guarantees.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
(cherry picked from commit d5192ba8eb)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:18:51 +02:00
Vlad Zahorodnii
de65e7df4d xwayland: Set wl_surface input region
Some applications that use client side decorations usually set custom
input shape in order to prevent drop shadows stealing pointer events
from windows below. Currently, the only way to get it is to use some
XFixes APIs.

On the other hand, plenty of wayland compositors use solely the
wl_surface input region to decide what view can receive pointer input,
which results in some pointer input issues around client side drop
shadows because Xwayland doesn't set wl_surface.input_region.

See-also: https://bugs.kde.org/show_bug.cgi?id=448119
Signed-off-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit a4ed100c0c)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:17:45 +02:00
Olivier Fourdan
eec66b819d xwayland: Do not remove output on withdraw if leased
On DRM lease connector withdrawn event, Xwayland would free the
corresponding xwl_output offered for lease.

However, the pointer is still referenced from the rrLease->outputs[],
meaning that trying to clean up the RANDR DRM leases as done with commit
ef181265 (xwayland: Clean up drm lease when terminating) would cause a
use after free and random crashes.

To avoid that issue, on the connector withdraw event, set the connector
withdrawn flag but do not to remove (i.e. free) the xwayland output if
its is offered for lease.

Then, once the lease is terminated, check for the xwl_outputs with a
withdrawn connector and remove them (once we have no use for them
anymore.

Note that we cannot do that cleanup from xwl_randr_terminate_lease() as
removing the xwl_output will free the RRcrtc resources, which checks for
leases in XRANDR, and calls RRTerminateLease(), which chains back to
xwl_randr_terminate_lease().

v2: Use a "withdrawn_connector" flag to mark outputs to remove (Xaver)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Xaver Hugl <xaver.hugl@kde.org>
fixes: ef181265 - xwayland: Clean up drm lease when terminating

See-also: https://gitlab.freedesktop.org/xorg/xserver/-/issues/946
See-also: https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1130
(cherry picked from commit 4053782443)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:17:42 +02:00
Olivier Fourdan
cb6c7256ab xwayland: Check for outputs before lease devices
In xwl_randr_request_lease(), the code checks first for leased device,
and then checks for existing output for lease.

The former assumes there are outputs for lease whereas the latter checks
for the output, connector and lease.

So if there is any existing rrLease->outputs[]->devPrivate unset, the
code would crash on a NULL pointer dereference on the first sanity check
before having a chance to reach the second check that would have caught
the problem.

Invert the sanity checks so that we would catch this first and return a
BadValue instead of possibly segfaulting.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Xaver Hugl <xaver.hugl@kde.org>
(cherry picked from commit 21916ae148)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:17:39 +02:00
Michel Dänzer
34832a182c xwayland/glamor: Handle depth 15 in gbm_format_for_depth
Prevents Xwayland with glamor from logging

 unexpected depth: 15

to stderr many times when running

 rendercheck -t blend -o clear

(cherry picked from commit 08113b8923)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:17:36 +02:00
Olivier Fourdan
74d02b98ab xwayland: Use the connector name for XRANDR leases
Use the connector name as basis for the Xwayland output name in XRANDR,
similar to what we do for regular outputs, instead of the generic
"XWAYLAND<n>" name which changes every time the output is leased.

Prefix the actual name with "lease-" to distinguish from duplicate names
from the regular outputs.

v2: avoid duplicate names (Simon)
v3: Move the check for duplicates to xwl_output_set_name() (Simon)

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 49b8f131f7)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:17:32 +02:00
Olivier Fourdan
aa17d7eba6 xwayland: Check for duplicate output names
Even though the name provided by either xdg-output or wl_output are
guaranteed to be unique, that might not be the case with output names
between different protocols, such as the one offered for DRM lease.

To avoid running into name conflicts, check that no other existing
output of the same name exists prior to changing the output name.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit d36f66f15d)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:16:44 +02:00
Olivier Fourdan
158246a0af xwayland: Make xwl_output_set_name() public
No functional change, this is preparation work for the next commit.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 0cb4ec4dbd)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:16:41 +02:00
Olivier Fourdan
80af615ea9 xwayland: Define MAX_OUTPUT_NAME in the header
So that other parts of the Xwayland code can use it.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 12265aaa1c)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-05-02 10:16:37 +02:00
Olivier Fourdan
4725674a23 xwayland: Use the path to Xwayland as installed
Otherwise the executable cannot be found where specified.

v2: Use 'xwayland_path' (Simon)

Fixes: fbf5e26b5 - xwayland: Use full path for Xwayland exec
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
(cherry picked from commit 8ff88ffec9)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1494>
2024-04-18 14:00:03 +02:00
Enrico Weigelt, metux IT consult
9f4d612e7e m4: drop autoconf leftovers
these m4 macros had been used for autotools-based build system. But since this
had been replaced by meson, these files are obsolete now.

Fixes: c97397dc47
Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
(cherry picked from commit 887fc7121b)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1487>
2024-04-18 07:17:07 +00:00
Olivier Fourdan
84b6d7e2c5 Bump version to 24.0.99.901
Xwayland 24.1.0 release candidate 1.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1489>
2024-04-17 08:56:13 +02:00
Olivier Fourdan
596db5424d Bump version to 24.0.99.1
In preparation for a 24.1 release.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
751af1243e meson: Change project name to xwayland
(cherry picked from commit 001f0c8938)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
3d5eb2df23 Don't install Xvfb
We're keeping it for unit tests, but we don't want to ship it from this
branch.

Also disable Xvfb in CI for ninja test. It's still built and used for
unit tests as part of ninja dist, but we don't want to run XTS on Xvfb.

(cherry picked from commit 0408fcb329)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
9cd94d3976 meson: Build Xwayland unconditionally
And simplify build_glamor logic, we don't need the separate
glamor_option variable anymore.

(cherry picked from commit fdc61c5a3c)
(cherry picked from commit 274d54d1c3)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
6b100681d6 Drop miext/shadow directory
Not used on this branch.

(cherry picked from commit be7257c5d1)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
7f3a9a4059 Drop EXA code
Not used on this branch.

(cherry picked from commit aa49cd5ab7)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
94228264a7 Drop config directory
Not used anymore on this branch.

(cherry picked from commit 23296633bb)
(cherry picked from commit d07af46a67bc8e68fa050c605bb556bc25886f16)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
1f80c795e0 Drop Xephyr / kdrive DDX
(cherry picked from commit 9335ee7994)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
dfea734656 Drop Xorg DDX
v2: Change the FDO_DISTRIBUTION_TAG (Michel)

(cherry picked from commit 4f4b8e00fc)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
34fac2d7df Drop Xwin DDX and x86 MinGW-w64 cross build
(cherry picked from commit 8f480147f6)

This partly reverts commit d3933a24d1.

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
735009cda3 Drop Xnest DDX
(cherry picked from commit 69cc6a6caa)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
Michel Dänzer
700cdeeee4 Drop Xquartz DDX
(cherry picked from commit 6cae4b397d)

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1483>
2024-04-12 10:40:05 +02:00
889 changed files with 1247 additions and 261921 deletions

View file

@ -73,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 -Dxephyr=true -Dxnest=true -Dxvfb=true -Dxwin=true -Dxorg=true -Dpciaccess=false -Dint10=false -Dglamor=false build"'
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true -Dglamor=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

@ -19,7 +19,7 @@ variables:
FDO_UPSTREAM_REPO: xorg/xserver
FDO_DISTRIBUTION_VERSION: bullseye-slim
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_TAG: "2024-03-26-explicit-sync-2"
FDO_DISTRIBUTION_TAG: "2024-09-24-no-xorg"
MESON_BUILDDIR: "build"
include:
@ -34,7 +34,6 @@ include:
stages:
- docker-image
- build-and-test
- drivers
- test
.ci-run-policy:
@ -46,54 +45,6 @@ stages:
# Cancel CI run if a newer commit is pushed to the same branch
interruptible: true
# This is everything but the DDXen
.dix_paths: &dix_paths
# Directories
- .gitlab-ci/**/*
- composite/**/*
- config/**/*
- damageext/**/*
- dbe/**/*
- dix/**/*
- doc/**/*
- dri3/**/*
- exa/**/*
- fb/**/*
- glamor/**/*
- glx/**/*
- include/**/*
- m4/**/*
- man/**/*
- mi/**/*
- miext/**/*
- os/**/*
- present/**/*
- pseudoramiX/**/*
- randr/**/*
- record/**/*
- render/**/*
- test/**/*
- Xext/**/*
- xfixes/**/*
- Xi/**/*
- xkb/**/*
# Files
- hw/meson.build
- .gitlab-ci.yml
- meson*
- xorg-server.m4
- xorg-server.pc.in
- xserver.ent.in
.xorg_paths: &xorg_paths
- hw/xfree86/**/*
.xwayland_paths: &xwayland_paths
- hw/xwayland/**/*
.all_ddx_paths:
- hw/**/*
debian-bullseye:
extends:
- .fdo.container-build@debian
@ -147,81 +98,21 @@ meson-nolibdecor:
MESON_EXTRA_ARGS: >
-Dlibdecor=false
mingw-cross-build:
extends: .common-build-and-test
script:
- .gitlab-ci/meson-build.sh --run-install
variables:
MESON_ARGS: --cross-file=.gitlab-ci/cross-i686-w64-mingw32.txt -Dglx=false -Dsecure-rpc=false -Dlisten_tcp=true
meson-dist:
extends: .common-build-and-test
artifacts:
when: always
paths:
- $MESON_BUILDDIR/meson-logs/
- $MESON_BUILDDIR/xserver-*/$MESON_BUILDDIR/meson-logs/
- $MESON_BUILDDIR/xwayland-*/$MESON_BUILDDIR/meson-logs/
script:
- .gitlab-ci/meson-build.sh --run-dist
- mkdir xserver-tarball
- tar xf $MESON_BUILDDIR/meson-dist/xserver-*.tar.xz -C xserver-tarball --strip-components=1
- .gitlab-ci/meson-build.sh -C xserver-tarball --skip-test --skip-dist --run-install
- mkdir xwayland-tarball
- tar xf $MESON_BUILDDIR/meson-dist/xwayland-*.tar.xz -C xwayland-tarball --strip-components=1
- .gitlab-ci/meson-build.sh -C xwayland-tarball --skip-test --skip-dist --run-install
variables:
MESON_DIST_ARGS: --no-tests
DESTDIR: xserver-tarball/install/
xf86-driver-build-test:
extends:
- .fdo.distribution-image@debian
- .ci-run-policy
stage: drivers
parallel:
matrix:
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-input-evdev
SHA: xf86-input-evdev-2.10.6
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-input-libinput
SHA: xf86-input-libinput-1.4.0
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-input-mouse
SHA: xf86-input-mouse-1.9.5
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-input-synaptics
SHA: xf86-input-synaptics-1.9.2
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-video-amdgpu
SHA: xf86-video-amdgpu-23.0.0
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-video-ati
SHA: xf86-video-ati-22.0.0
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-video-qxl
SHA: xf86-video-qxl-0.1.6
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-video-vesa
SHA: xf86-video-vesa-2.6.0
- REPO: https://gitlab.freedesktop.org/xorg/driver/xf86-video-vmware
SHA: xf86-video-vmware-13.4.0
script:
# Install the server first
- .gitlab-ci/meson-build.sh --skip-test --run-install
- unset MESON_EXTRA_ARGS
- DRIVER=$(basename $REPO)
- git clone "$REPO" "$DRIVER"
- GIT_DIR="$DRIVER/.git" git checkout -f "$SHA"
- |
if [[ -e "$DRIVER/meson.build" ]]; then
.gitlab-ci/meson-build.sh -C "$DRIVER" --skip-test
else
pushd "$DRIVER" || exit 1
./autogen.sh && make
fi
needs:
- "meson"
variables:
GIT_DEPTH: 1
MESON_ARGS: -Dprefix=/usr/
MESON_EXTRA_ARGS: -Dxwayland=false -Dxnest=false -Dxvfb=false -Dxquartz=false -Ddocs=false
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes:
*dix_paths
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
changes:
*xorg_paths
DESTDIR: xwayland-tarball/install/
#
# Verify that commit messages are as expected

View file

@ -1,20 +0,0 @@
[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

@ -1,81 +0,0 @@
#!/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-2024.1' '--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.1'
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
# Using -fcommon to address build failure when cross-compiling for windows.
# See discussion at https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/913
CFLAGS="-fcommon" 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

@ -6,8 +6,10 @@ set -o xtrace
# Packages which are needed by this script, but not for the xserver build
EPHEMERAL="
libcairo2-dev
libevdev-dev
libexpat-dev
libgles2-mesa-dev
libinput-dev
libxkbcommon-dev
x11-utils
x11-xserver-utils
@ -27,9 +29,7 @@ apt-get install -y \
build-essential \
ca-certificates \
ccache \
dpkg-dev \
flex \
gcc-mingw-w64-i686 \
git \
libaudit-dev \
libbsd-dev \
@ -48,14 +48,12 @@ apt-get install -y \
libgles2 \
libglx-mesa0 \
libinput10 \
libinput-dev \
libnvidia-egl-wayland-dev \
libpango1.0-0 \
libpango1.0-dev \
libpciaccess-dev \
libpixman-1-dev \
libselinux1-dev \
libspice-protocol-dev \
libsystemd-dev \
libtool \
libudev-dev \
@ -96,11 +94,9 @@ apt-get install -y \
libxt-dev \
libxtst-dev \
libxv-dev \
libz-mingw-w64-dev \
linux-libc-dev/bullseye-backports \
mesa-common-dev \
meson \
mingw-w64-tools \
nettle-dev \
pkg-config \
python3-attr \
@ -115,8 +111,6 @@ apt-get install -y \
xtrans-dev \
xutils-dev
.gitlab-ci/cross-prereqs-build.sh i686-w64-mingw32
cd /root
# Xwayland requires drm 2.4.116 for drmSyncobjEventfd
@ -160,7 +154,7 @@ cd ..
rm -rf wayland-protocols
# Install libdecor for Xwayland
git clone https://gitlab.gnome.org/jadahl/libdecor.git --depth 1 --branch=0.1.0
git clone https://gitlab.freedesktop.org/libdecor/libdecor.git --depth 1 --branch=0.1.1
cd libdecor
meson _build -D{demo,install_demo}=false
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install

View file

@ -1,27 +0,0 @@
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

View file

@ -73,7 +73,3 @@ 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

@ -200,8 +200,8 @@ SyncAddTriggerToSyncObject(SyncTrigger * pTrigger)
return Success;
}
if (!(pCur = malloc(sizeof(SyncTriggerList))))
return BadAlloc;
/* Failure is not an option, it's succeed or burst! */
pCur = XNFalloc(sizeof(SyncTriggerList));
pCur->pTrigger = pTrigger;
pCur->next = pTrigger->pSync->pTriglist;
@ -330,11 +330,6 @@ SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
client->errorValue = syncObject;
return rc;
}
if (pSync != pTrigger->pSync) { /* new counter for trigger */
SyncDeleteTriggerFromSyncObject(pTrigger);
pTrigger->pSync = pSync;
newSyncObject = TRUE;
}
}
/* if system counter, ask it what the current value is */
@ -356,6 +351,24 @@ SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
}
}
if (changes & (XSyncCAValueType | XSyncCAValue)) {
if (pTrigger->value_type == XSyncAbsolute)
pTrigger->test_value = pTrigger->wait_value;
else { /* relative */
Bool overflow;
if (pCounter == NULL)
return BadMatch;
overflow = checked_int64_add(&pTrigger->test_value,
pCounter->value, pTrigger->wait_value);
if (overflow) {
client->errorValue = pTrigger->wait_value >> 32;
return BadValue;
}
}
}
if (changes & XSyncCATestType) {
if (pSync && SYNC_FENCE == pSync->type) {
@ -384,21 +397,11 @@ SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
}
}
if (changes & (XSyncCAValueType | XSyncCAValue)) {
if (pTrigger->value_type == XSyncAbsolute)
pTrigger->test_value = pTrigger->wait_value;
else { /* relative */
Bool overflow;
if (pCounter == NULL)
return BadMatch;
overflow = checked_int64_add(&pTrigger->test_value,
pCounter->value, pTrigger->wait_value);
if (overflow) {
client->errorValue = pTrigger->wait_value >> 32;
return BadValue;
}
if (changes & XSyncCACounter) {
if (pSync != pTrigger->pSync) { /* new counter for trigger */
SyncDeleteTriggerFromSyncObject(pTrigger);
pTrigger->pSync = pSync;
newSyncObject = TRUE;
}
}
@ -406,8 +409,7 @@ SyncInitTrigger(ClientPtr client, SyncTrigger * pTrigger, XID syncObject,
* a new counter on a trigger
*/
if (newSyncObject) {
if ((rc = SyncAddTriggerToSyncObject(pTrigger)) != Success)
return rc;
SyncAddTriggerToSyncObject(pTrigger);
}
else if (pCounter && IsSystemCounter(pCounter)) {
SyncComputeBracketValues(pCounter);
@ -798,8 +800,14 @@ SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
int status;
XSyncCounter counter;
Mask origmask = mask;
SyncTrigger trigger;
Bool select_events_changed = FALSE;
Bool select_events_value = FALSE;
int64_t delta;
counter = pAlarm->trigger.pSync ? pAlarm->trigger.pSync->id : None;
trigger = pAlarm->trigger;
delta = pAlarm->delta;
counter = trigger.pSync ? trigger.pSync->id : None;
while (mask) {
int index2 = lowbit(mask);
@ -815,24 +823,24 @@ SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
case XSyncCAValueType:
mask &= ~XSyncCAValueType;
/* sanity check in SyncInitTrigger */
pAlarm->trigger.value_type = *values++;
trigger.value_type = *values++;
break;
case XSyncCAValue:
mask &= ~XSyncCAValue;
pAlarm->trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
trigger.wait_value = ((int64_t)values[0] << 32) | values[1];
values += 2;
break;
case XSyncCATestType:
mask &= ~XSyncCATestType;
/* sanity check in SyncInitTrigger */
pAlarm->trigger.test_type = *values++;
trigger.test_type = *values++;
break;
case XSyncCADelta:
mask &= ~XSyncCADelta;
pAlarm->delta = ((int64_t)values[0] << 32) | values[1];
delta = ((int64_t)values[0] << 32) | values[1];
values += 2;
break;
@ -842,10 +850,8 @@ SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
client->errorValue = *values;
return BadValue;
}
status = SyncEventSelectForAlarm(pAlarm, client,
(Bool) (*values++));
if (status != Success)
return status;
select_events_value = (Bool) (*values++);
select_events_changed = TRUE;
break;
default:
@ -854,25 +860,33 @@ SyncChangeAlarmAttributes(ClientPtr client, SyncAlarm * pAlarm, Mask mask,
}
}
if (select_events_changed) {
status = SyncEventSelectForAlarm(pAlarm, client, select_events_value);
if (status != Success)
return status;
}
/* "If the test-type is PositiveComparison or PositiveTransition
* and delta is less than zero, or if the test-type is
* NegativeComparison or NegativeTransition and delta is
* greater than zero, a Match error is generated."
*/
if (origmask & (XSyncCADelta | XSyncCATestType)) {
if ((((pAlarm->trigger.test_type == XSyncPositiveComparison) ||
(pAlarm->trigger.test_type == XSyncPositiveTransition))
&& pAlarm->delta < 0)
if ((((trigger.test_type == XSyncPositiveComparison) ||
(trigger.test_type == XSyncPositiveTransition))
&& delta < 0)
||
(((pAlarm->trigger.test_type == XSyncNegativeComparison) ||
(pAlarm->trigger.test_type == XSyncNegativeTransition))
&& pAlarm->delta > 0)
(((trigger.test_type == XSyncNegativeComparison) ||
(trigger.test_type == XSyncNegativeTransition))
&& delta > 0)
) {
return BadMatch;
}
}
/* postpone this until now, when we're sure nothing else can go wrong */
pAlarm->delta = delta;
pAlarm->trigger = trigger;
if ((status = SyncInitTrigger(client, &pAlarm->trigger, counter, RTCounter,
origmask & XSyncCAAllTrigger)) != Success)
return status;

View file

@ -350,7 +350,7 @@ ProcXListInputDevices(ClientPtr client)
};
/* allocate space for saving skip value */
skip = calloc(sizeof(Bool), inputInfo.numDevices);
skip = calloc(inputInfo.numDevices, sizeof(Bool));
if (!skip)
return BadAlloc;

View file

@ -129,14 +129,15 @@ static void FreePointerBarrierClient(struct PointerBarrierClient *c)
static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid)
{
struct PointerBarrierDevice *pbd = NULL;
struct PointerBarrierDevice *p, *pbd = NULL;
xorg_list_for_each_entry(pbd, &c->per_device, entry) {
if (pbd->deviceid == deviceid)
xorg_list_for_each_entry(p, &c->per_device, entry) {
if (p->deviceid == deviceid) {
pbd = p;
break;
}
}
BUG_WARN(!pbd);
return pbd;
}
@ -337,6 +338,9 @@ barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
double distance;
pbd = GetBarrierDevice(c, dev->id);
if (!pbd)
continue;
if (pbd->seen)
continue;
@ -445,6 +449,9 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
nearest = &c->barrier;
pbd = GetBarrierDevice(c, master->id);
if (!pbd)
continue;
new_sequence = !pbd->hit;
pbd->seen = TRUE;
@ -485,6 +492,9 @@ input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
int flags = 0;
pbd = GetBarrierDevice(c, master->id);
if (!pbd)
continue;
pbd->seen = FALSE;
if (!pbd->hit)
continue;
@ -679,6 +689,9 @@ BarrierFreeBarrier(void *data, XID id)
continue;
pbd = GetBarrierDevice(c, dev->id);
if (!pbd)
continue;
if (!pbd->hit)
continue;
@ -738,6 +751,8 @@ static void remove_master_func(void *res, XID id, void *devid)
barrier = container_of(b, struct PointerBarrierClient, barrier);
pbd = GetBarrierDevice(barrier, *deviceid);
if (!pbd)
return;
if (pbd->hit) {
BarrierEvent ev = {
@ -903,6 +918,10 @@ ProcXIBarrierReleasePointer(ClientPtr client)
barrier = container_of(b, struct PointerBarrierClient, barrier);
pbd = GetBarrierDevice(barrier, dev->id);
if (!pbd) {
client->errorValue = dev->id;
return BadDevice;
}
if (pbd->barrier_event_id == event_id)
pbd->release_event_id = event_id;

View file

@ -46,6 +46,7 @@
#include "exevents.h"
#include "exglobals.h"
#include "geext.h"
#include "misc.h"
#include "xace.h"
#include "xiquerydevice.h" /* for GetDeviceUse */
@ -215,46 +216,68 @@ disable_clientpointer(DeviceIntPtr dev)
}
}
static DeviceIntPtr
find_disabled_master(int type)
{
DeviceIntPtr dev;
/* Once a master device is disabled it loses the pairing, so returning the first
* match is good enough */
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
if (dev->type == type)
return dev;
}
return NULL;
}
static int
remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
{
DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
DeviceIntPtr dev, ptr, keybd, XTestptr, XTestkeybd;
int rc = Success;
if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
return BadValue;
rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
rc = dixLookupDevice(&dev, r->deviceid, client, DixDestroyAccess);
if (rc != Success)
goto unwind;
if (!IsMaster(ptr)) {
if (!IsMaster(dev)) {
client->errorValue = r->deviceid;
rc = BadDevice;
goto unwind;
}
/* XXX: For now, don't allow removal of VCP, VCK */
if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
if (dev == inputInfo.pointer || dev == inputInfo.keyboard) {
rc = BadDevice;
goto unwind;
}
ptr = GetMaster(ptr, MASTER_POINTER);
if ((ptr = GetMaster(dev, MASTER_POINTER)) == NULL)
ptr = find_disabled_master(MASTER_POINTER);
BUG_RETURN_VAL(ptr == NULL, BadDevice);
rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
if (rc != Success)
goto unwind;
keybd = GetMaster(ptr, MASTER_KEYBOARD);
if ((keybd = GetMaster(dev, MASTER_KEYBOARD)) == NULL)
keybd = find_disabled_master(MASTER_KEYBOARD);
BUG_RETURN_VAL(keybd == NULL, BadDevice);
rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
if (rc != Success)
goto unwind;
XTestptr = GetXTestDevice(ptr);
BUG_RETURN_VAL(XTestptr == NULL, BadDevice);
rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
if (rc != Success)
goto unwind;
XTestkeybd = GetXTestDevice(keybd);
BUG_RETURN_VAL(XTestkeybd == NULL, BadDevice);
rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
if (rc != Success)
goto unwind;

View file

@ -82,6 +82,9 @@ ProcXIGrabDevice(ClientPtr client)
if (ret != Success)
return ret;
if (!dev->enabled)
return AlreadyGrabbed;
if (!IsMaster(dev))
stuff->paired_device_mode = GrabModeAsync;

View file

@ -88,7 +88,7 @@ ProcXIQueryDevice(ClientPtr client)
len += SizeDeviceInfo(dev);
}
else {
skip = calloc(sizeof(Bool), inputInfo.numDevices);
skip = calloc(inputInfo.numDevices, sizeof(Bool));
if (!skip)
return BadAlloc;

View file

@ -140,6 +140,7 @@ compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
WindowPtr pLayerWin;
Bool anyMarked = FALSE;
int status = Success;
if (pWin == cs->pOverlayWin) {
return Success;
@ -218,13 +219,13 @@ compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
if (!compCheckRedirect(pWin)) {
FreeResource(ccw->id, RT_NONE);
return BadAlloc;
status = BadAlloc;
}
if (anyMarked)
compHandleMarkedWindows(pWin, pLayerWin);
return Success;
return status;
}
void
@ -605,9 +606,12 @@ compAllocPixmap(WindowPtr pWin)
int h = pWin->drawable.height + (bw << 1);
PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h);
CompWindowPtr cw = GetCompWindow(pWin);
Bool status;
if (!pPixmap)
return FALSE;
if (!pPixmap) {
status = FALSE;
goto out;
}
if (cw->update == CompositeRedirectAutomatic)
pWin->redirectDraw = RedirectDrawAutomatic;
else
@ -621,14 +625,16 @@ compAllocPixmap(WindowPtr pWin)
DamageRegister(&pWin->drawable, cw->damage);
cw->damageRegistered = TRUE;
}
status = TRUE;
out:
/* Make sure our borderClip is up to date */
RegionUninit(&cw->borderClip);
RegionCopy(&cw->borderClip, &pWin->borderClip);
cw->borderClipX = pWin->drawable.x;
cw->borderClipY = pWin->drawable.y;
return TRUE;
return status;
}
void

View file

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

View file

@ -1,48 +0,0 @@
# 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
# https://bugzilla.redhat.com/show_bug.cgi?id=2152414
# Xorg server does not correctly select the DCP for the display without
# a quirk on Apple Silicon
Section "OutputClass"
Identifier "appledrm"
MatchDriver "apple"
Driver "modesetting"
Option "PrimaryGPU" "true"
EndSection

View file

@ -1,46 +0,0 @@
/*
* 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

View file

@ -1,151 +0,0 @@
/*
* 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);
}

View file

@ -1,40 +0,0 @@
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].

View file

@ -1,238 +0,0 @@
/*
* 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();
}

View file

@ -1,199 +0,0 @@
#!/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 is 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'):
# 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))

View file

@ -1,675 +0,0 @@
/*
* 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);
}

View file

@ -1,35 +0,0 @@
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() == 'netbsd' or 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,
)

View file

@ -1,610 +0,0 @@
/*
* 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

View file

@ -1,271 +0,0 @@
/*
* 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 <sys/time.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsksymdef.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.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;
const char *name;
} kbdenc[] = {
KB_OVRENC,
KB_ENCTAB
#ifndef __NetBSD__
,
#endif
{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");
if (asprintf(&config_info, "wscons:%s", WSCONS_KBD_DEVICE) == -1)
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;
if (asprintf(&config_info, "wscons:%s", path) == -1)
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);
#ifdef HAVE_OPEN_DEVICE
fd = open_device(devname, O_RDWR | O_NONBLOCK | O_EXCL);
#else
fd = open(devname, O_RDWR | O_NONBLOCK | O_EXCL);
#endif
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) {
#ifdef WSMOUSE_TYPE_SYNAPTICS
case WSMOUSE_TYPE_SYNAPTICS:
wscons_add_pointer(devname, "synaptics", ATTR_TOUCHPAD);
break;
#endif
case WSMOUSE_TYPE_TPANEL:
wscons_add_pointer(devname, "ws", ATTR_TOUCHSCREEN);
break;
default:
break;
}
}
/* Add a default entry catching all other mux elements as pointers */
wscons_add_pointer(WSCONS_MOUSE_PREFIX, "ws", ATTR_POINTER);
}
int
config_wscons_init(void)
{
wscons_add_keyboard();
wscons_add_pointers();
return 1;
}
void
config_wscons_fini(void)
{
/* Not much to do ? */
}

View file

@ -1,93 +0,0 @@
<?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>

View file

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

View file

@ -1250,6 +1250,7 @@ FindBestPixel(EntryPtr pentFirst, int size, xrgb * prgb, int channel)
case PSEUDOMAP:
dg = (long) pent->co.local.green - prgb->green;
db = (long) pent->co.local.blue - prgb->blue;
/* fallthrough */
case REDMAP:
dr = (long) pent->co.local.red - prgb->red;
break;

View file

@ -981,6 +981,23 @@ FreeAllDeviceClasses(ClassesPtr classes)
}
static void
FreePendingFrozenDeviceEvents(DeviceIntPtr dev)
{
QdEventPtr qe, tmp;
if (!dev->deviceGrab.sync.frozen)
return;
/* Dequeue any frozen pending events */
xorg_list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) {
if (qe->device == dev) {
xorg_list_del(&qe->next);
free(qe);
}
}
}
/**
* Close down a device and free all resources.
* Once closed down, the driver will probably not expect you that you'll ever
@ -1045,6 +1062,7 @@ CloseDevice(DeviceIntPtr dev)
valuator_mask_free(&dev->last.touches[j].valuators);
free(dev->last.touches);
dev->config_info = NULL;
FreePendingFrozenDeviceEvents(dev);
dixFreePrivates(dev->devPrivates, PRIVATE_DEVICE);
free(dev);
}
@ -2699,11 +2717,14 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
dev->spriteInfo->paired = dev;
}
else {
DeviceIntPtr keyboard = GetMaster(dev, MASTER_KEYBOARD);
dev->spriteInfo->sprite = master->spriteInfo->sprite;
dev->spriteInfo->paired = master;
dev->spriteInfo->spriteOwner = FALSE;
XkbPushLockedStateToSlaves(GetMaster(dev, MASTER_KEYBOARD), 0, 0);
if (keyboard)
XkbPushLockedStateToSlaves(keyboard, 0, 0);
RecalculateMasterButtons(master);
}
@ -2728,7 +2749,7 @@ GetPairedDevice(DeviceIntPtr dev)
if (!IsMaster(dev) && !IsFloating(dev))
dev = GetMaster(dev, MASTER_ATTACHED);
return dev->spriteInfo? dev->spriteInfo->paired: NULL;
return (dev && dev->spriteInfo) ? dev->spriteInfo->paired: NULL;
}
/**

View file

@ -517,9 +517,10 @@ Dispatch(void)
/* now, finally, deal with client requests */
result = ReadRequestFromClient(client);
if (result <= 0) {
if (result < 0)
CloseDownClient(client);
if (result == 0)
break;
else if (result == -1) {
CloseDownClient(client);
break;
}
@ -540,7 +541,7 @@ Dispatch(void)
client->index,
client->requestBuffer);
#endif
if (result > (maxBigRequestSize << 2))
if (result < 0 || result > (maxBigRequestSize << 2))
result = BadLength;
else {
result = XaceHookDispatch(client, client->majorOp);
@ -3106,6 +3107,10 @@ ProcFreeCursor(ClientPtr client)
rc = dixLookupResourceByType((void **) &pCursor, stuff->id, RT_CURSOR,
client, DixDestroyAccess);
if (rc == Success) {
if (pCursor == rootCursor) {
client->errorValue = stuff->id;
return BadCursor;
}
FreeResource(stuff->id, RT_NONE);
return Success;
}

View file

@ -1352,18 +1352,18 @@ int
PolyText(ClientPtr client, DrawablePtr pDraw, GC * pGC, unsigned char *pElt,
unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
{
PTclosureRec local_closure;
local_closure.pElt = pElt;
local_closure.endReq = endReq;
local_closure.client = client;
local_closure.pDraw = pDraw;
local_closure.xorg = xorg;
local_closure.yorg = yorg;
local_closure.reqType = reqType;
local_closure.pGC = pGC;
local_closure.did = did;
local_closure.err = Success;
PTclosureRec local_closure = {
.client = client,
.pDraw = pDraw,
.pGC = pGC,
.pElt = pElt,
.endReq = endReq,
.xorg = xorg,
.yorg = yorg,
.reqType = reqType,
.did = did,
.err = Success
};
(void) doPolyText(client, &local_closure);
return Success;
@ -1687,7 +1687,8 @@ SetFontPath(ClientPtr client, int npaths, unsigned char *paths)
int bad;
err = SetFontPathElements(npaths, paths, &bad, FALSE);
client->errorValue = bad;
if (err != Success)
client->errorValue = bad;
}
return err;
}

View file

@ -622,14 +622,19 @@ FixDeviceValuator(DeviceIntPtr dev, deviceValuator * ev, ValuatorClassPtr v,
switch (ev->num_valuators) {
case 6:
ev->valuator5 = v->axisVal[first + 5];
/* fallthrough */
case 5:
ev->valuator4 = v->axisVal[first + 4];
/* fallthrough */
case 4:
ev->valuator3 = v->axisVal[first + 3];
/* fallthrough */
case 3:
ev->valuator2 = v->axisVal[first + 2];
/* fallthrough */
case 2:
ev->valuator1 = v->axisVal[first + 1];
/* fallthrough */
case 1:
ev->valuator0 = v->axisVal[first];
break;
@ -668,8 +673,10 @@ FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k,
switch (ev->num_valuators) {
case 3:
ev->valuator2 = v->axisVal[first + 2];
/* fallthrough */
case 2:
ev->valuator1 = v->axisVal[first + 1];
/* fallthrough */
case 1:
ev->valuator0 = v->axisVal[first];
break;
@ -724,7 +731,7 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
evcount += ((nval - 3) + 6)/6;
}
BUG_RETURN(evcount <= ARRAY_SIZE(sev));
BUG_RETURN(evcount > ARRAY_SIZE(sev));
FixDeviceStateNotify(dev, ev, k, b, v, first);
@ -733,7 +740,7 @@ DeliverStateNotifyEvent(DeviceIntPtr dev, WindowPtr win)
(ev - 1)->deviceid |= MORE_EVENTS;
bev->type = DeviceButtonStateNotify;
bev->deviceid = dev->id;
memcpy((char *) &bev->buttons[4], (char *) &b->down[4],
memcpy((char *) &bev->buttons[0], (char *) &b->down[4],
DOWN_LENGTH - 4);
}

View file

@ -684,6 +684,8 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
len += vallen * 4; /* valuators mask */
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
xde = (xXIDeviceEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
@ -734,7 +736,7 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
ptr += xde->buttons_len * 4;
axisval = (FP3232 *) (ptr + xde->valuators_len * 4);
for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
for (i = 0; i < MAX_VALUATORS; i++) {
if (BitIsOn(ev->valuators.mask, i)) {
SetBit(ptr, i);
*axisval = double_to_fp3232(ev->valuators.data[i]);
@ -752,6 +754,8 @@ eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi)
xXITouchOwnershipEvent *xtoe;
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
xtoe = (xXITouchOwnershipEvent *) * xi;
xtoe->type = GenericEvent;
xtoe->extension = IReqCode;
@ -782,6 +786,8 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
len += vallen * 4; /* valuators mask */
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
raw = (xXIRawEvent *) * xi;
raw->type = GenericEvent;
raw->extension = IReqCode;
@ -797,7 +803,7 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
ptr = (char *) &raw[1];
axisval = (FP3232 *) (ptr + raw->valuators_len * 4);
axisval_raw = axisval + nvals;
for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) {
for (i = 0; i < MAX_VALUATORS; i++) {
if (BitIsOn(ev->valuators.mask, i)) {
SetBit(ptr, i);
*axisval = double_to_fp3232(ev->valuators.data[i]);
@ -817,6 +823,8 @@ eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
int len = sizeof(xXIBarrierEvent);
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
barrier = (xXIBarrierEvent*) *xi;
barrier->type = GenericEvent;
barrier->extension = IReqCode;
@ -846,6 +854,8 @@ eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
xXIGesturePinchEvent *xpe;
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
xpe = (xXIGesturePinchEvent *) * xi;
xpe->type = GenericEvent;
xpe->extension = IReqCode;
@ -888,6 +898,8 @@ eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
xXIGestureSwipeEvent *xde;
*xi = calloc(1, len);
if (*xi == NULL)
return BadAlloc;
xde = (xXIGestureSwipeEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;

View file

@ -1486,6 +1486,30 @@ ReattachToOldMaster(DeviceIntPtr dev)
}
}
/**
* Return the current master keyboard or, if we're temporarily detached, the one
* we've been attached to previously.
*/
static DeviceIntPtr
CurrentOrOldMasterKeyboard(DeviceIntPtr dev)
{
DeviceIntPtr kbd = GetMaster(dev, MASTER_KEYBOARD);
if (kbd)
return kbd;
if (dev->saved_master_id) {
dixLookupDevice(&kbd, dev->saved_master_id, serverClient, DixUseAccess);
if (!kbd)
return NULL;
/* if dev is a pointer the saved master is a master pointer,
* we want the keybard */
return GetMaster(kbd, MASTER_KEYBOARD);
}
return NULL;
}
/**
* Update touch records when an explicit grab is activated. Any touches owned by
* the grabbing client are updated so the listener state reflects the new grab.
@ -1713,6 +1737,10 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
GrabInfoPtr grabinfo = &keybd->deviceGrab;
GrabPtr oldgrab = grabinfo->grab;
WindowPtr oldWin;
DeviceIntPtr master_keyboard = CurrentOrOldMasterKeyboard(keybd);
if (!master_keyboard)
master_keyboard = inputInfo.keyboard;
/* slave devices need to float for the duration of the grab. */
if (grab->grabtype == XI2 && keybd->enabled &&
@ -1728,7 +1756,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time,
else
oldWin = keybd->spriteInfo->sprite->win;
if (oldWin == FollowKeyboardWin)
oldWin = keybd->focus->win;
oldWin = master_keyboard->focus->win;
if (keybd->valuator)
keybd->valuator->motionHintWindow = NullWindow;
if (oldWin &&
@ -1759,6 +1787,10 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd)
WindowPtr focusWin;
Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab &&
keybd->deviceGrab.implicitGrab);
DeviceIntPtr master_keyboard = CurrentOrOldMasterKeyboard(keybd);
if (!master_keyboard)
master_keyboard = inputInfo.keyboard;
if (keybd->valuator)
keybd->valuator->motionHintWindow = NullWindow;
@ -1779,7 +1811,7 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd)
focusWin = NullWindow;
if (focusWin == FollowKeyboardWin)
focusWin = inputInfo.keyboard->focus->win;
focusWin = master_keyboard->focus->win;
DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);

View file

@ -89,7 +89,7 @@ AddExtension(const char *name, int NumEvents, int NumErrors,
return ((ExtensionEntry *) NULL);
}
ext = calloc(sizeof(ExtensionEntry), 1);
ext = calloc(1, sizeof(ExtensionEntry));
if (!ext)
return NULL;
if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {

View file

@ -813,7 +813,8 @@ CreateScratchGC(ScreenPtr pScreen, unsigned depth)
FreeGC(pGC, (XID) 0);
pGC = (GCPtr) NULL;
}
pGC->graphicsExposures = FALSE;
else
pGC->graphicsExposures = FALSE;
return pGC;
}

View file

@ -104,7 +104,6 @@ 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"
@ -157,7 +156,7 @@ dix_main(int argc, char *argv[], char *envp[])
CreateWellKnownSockets();
for (i = 1; i < LimitClients; i++)
clients[i] = NullClient;
serverClient = calloc(sizeof(ClientRec), 1);
serverClient = calloc(1, sizeof(ClientRec));
if (!serverClient)
FatalError("couldn't create server client");
InitClient(serverClient, 0, (void *) NULL);
@ -235,6 +234,8 @@ dix_main(int argc, char *argv[], char *envp[])
FatalError("could not open default cursor font");
}
rootCursor = RefCursor(rootCursor);
#ifdef PANORAMIX
/*
* Consolidate window and colourmap information for each screen
@ -275,6 +276,8 @@ dix_main(int argc, char *argv[], char *envp[])
Dispatch();
UnrefCursor(rootCursor);
UndisplayDevices();
DisableAllDevices();

View file

@ -413,7 +413,7 @@ dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen,
assert(key->type == type);
return TRUE;
}
key = calloc(sizeof(DevPrivateKeyRec), 1);
key = calloc(1, sizeof(DevPrivateKeyRec));
if (!key)
return FALSE;
if (!dixRegisterPrivateKey(key, type, size)) {

View file

@ -276,11 +276,13 @@ dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
if (!pProp)
return BadAlloc;
data = malloc(totalSize);
if (!data && len) {
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
return BadAlloc;
if (totalSize) {
if (!data) {
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
return BadAlloc;
}
memcpy(data, value, totalSize);
}
memcpy(data, value, totalSize);
pProp->propertyName = property;
pProp->type = type;
pProp->format = format;
@ -313,9 +315,11 @@ dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
if (mode == PropModeReplace) {
data = malloc(totalSize);
if (!data && len)
return BadAlloc;
memcpy(data, value, totalSize);
if (totalSize) {
if (!data)
return BadAlloc;
memcpy(data, value, totalSize);
}
pProp->data = data;
pProp->size = len;
pProp->type = type;
@ -585,17 +589,20 @@ ProcListProperties(ClientPtr client)
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
numProps++;
if (numProps && !(pAtoms = xallocarray(numProps, sizeof(Atom))))
return BadAlloc;
if (numProps) {
pAtoms = xallocarray(numProps, sizeof(Atom));
if (!pAtoms)
return BadAlloc;
numProps = 0;
temppAtoms = pAtoms;
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
realProp = pProp;
rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
if (rc == Success && realProp == pProp) {
*temppAtoms++ = pProp->propertyName;
numProps++;
numProps = 0;
temppAtoms = pAtoms;
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
realProp = pProp;
rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
if (rc == Success && realProp == pProp) {
*temppAtoms++ = pProp->propertyName;
numProps++;
}
}
}
@ -609,8 +616,8 @@ ProcListProperties(ClientPtr client)
if (numProps) {
client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
free(pAtoms);
}
free(pAtoms);
return Success;
}

View file

@ -146,6 +146,7 @@ InitPredictableAccelerationScheme(DeviceIntPtr dev,
schemeData->vel = vel;
scheme.accelData = schemeData;
if (!InitializePredictableAccelerationProperties(dev, vel, schemeData)) {
FreeVelocityData(vel);
free(vel);
free(schemeData);
return FALSE;

View file

@ -685,7 +685,7 @@ HashResourceID(XID id, unsigned int numBits)
id &= mask;
if (numBits < 9)
return (id ^ (id >> numBits) ^ (id >> (numBits<<1))) & ~((~0U) << numBits);
return (id ^ (id >> numBits)) & ~((~0) << numBits);
return (id ^ (id >> numBits)) & ~((~0U) << numBits);
}
static XID

View file

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

1144
exa/exa.c

File diff suppressed because it is too large Load diff

820
exa/exa.h
View file

@ -1,820 +0,0 @@
/*
*
* 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 */

File diff suppressed because it is too large Load diff

View file

@ -1,265 +0,0 @@
/*
* 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 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;
}

View file

@ -1,230 +0,0 @@
/*
* 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 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)
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;
}

View file

@ -1,839 +0,0 @@
/*
* 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 "glyphstr_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);
}
}

View file

@ -1,761 +0,0 @@
/*
* 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);
}

View file

@ -1,270 +0,0 @@
/*
* 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;
}
}

View file

@ -1,328 +0,0 @@
/*
* 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 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)
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;
}

View file

@ -1,677 +0,0 @@
/*
* 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);
}
}

View file

@ -1,735 +0,0 @@
/*
*
* 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 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 */

File diff suppressed because it is too large Load diff

View file

@ -1,733 +0,0 @@
/*
*
* 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);
}
}

View file

@ -1,24 +0,0 @@
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

View file

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

View file

@ -520,6 +520,31 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
return fd;
}
static bool
gbm_format_for_depth(CARD8 depth, uint32_t *format)
{
switch (depth) {
case 15:
*format = GBM_FORMAT_ARGB1555;
return true;
case 16:
*format = GBM_FORMAT_RGB565;
return true;
case 24:
*format = GBM_FORMAT_XRGB8888;
return true;
case 30:
*format = GBM_FORMAT_ARGB2101010;
return true;
case 32:
*format = GBM_FORMAT_ARGB8888;
return true;
default:
ErrorF("unexpected depth: %d\n", depth);
return false;
}
}
Bool
glamor_back_pixmap_from_fd(PixmapPtr pixmap,
int fd,
@ -536,17 +561,14 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap,
glamor_egl = glamor_egl_get_screen_private(scrn);
if (bpp != 32 || !(depth == 24 || depth == 32 || depth == 30) || width == 0 || height == 0)
if (!gbm_format_for_depth(depth, &import_data.format) ||
width == 0 || height == 0)
return FALSE;
import_data.fd = fd;
import_data.width = width;
import_data.height = height;
import_data.stride = stride;
if (depth == 30)
import_data.format = GBM_FORMAT_ARGB2101010;
else
import_data.format = GBM_FORMAT_ARGB8888;
bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD, &import_data, 0);
if (!bo)
return FALSE;
@ -558,23 +580,6 @@ glamor_back_pixmap_from_fd(PixmapPtr pixmap,
return ret;
}
static uint32_t
gbm_format_for_depth(CARD8 depth)
{
switch (depth) {
case 16:
return GBM_FORMAT_RGB565;
case 24:
return GBM_FORMAT_XRGB8888;
case 30:
return GBM_FORMAT_ARGB2101010;
default:
ErrorF("unexpected depth: %d\n", depth);
case 32:
return GBM_FORMAT_ARGB8888;
}
}
PixmapPtr
glamor_pixmap_from_fds(ScreenPtr screen,
CARD8 num_fds, const int *fds,
@ -597,6 +602,10 @@ glamor_pixmap_from_fds(ScreenPtr screen,
struct gbm_import_fd_modifier_data import_data = { 0 };
struct gbm_bo *bo;
if (!gbm_format_for_depth(depth, &import_data.format) ||
width == 0 || height == 0)
goto error;
import_data.width = width;
import_data.height = height;
import_data.num_fds = num_fds;
@ -606,7 +615,6 @@ glamor_pixmap_from_fds(ScreenPtr screen,
import_data.strides[i] = strides[i];
import_data.offsets[i] = offsets[i];
}
import_data.format = gbm_format_for_depth(depth);
bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_FD_MODIFIER, &import_data, 0);
if (bo) {
screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);
@ -622,6 +630,7 @@ glamor_pixmap_from_fds(ScreenPtr screen,
}
}
error:
if (ret == FALSE) {
screen->DestroyPixmap(pixmap);
return NULL;
@ -1087,7 +1096,7 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
Bool force_es = FALSE;
const char *glvnd_vendor = NULL;
glamor_egl = calloc(sizeof(*glamor_egl), 1);
glamor_egl = calloc(1, sizeof(*glamor_egl));
if (glamor_egl == NULL)
return FALSE;
if (xf86GlamorEGLPrivateIndex == -1)

View file

@ -140,12 +140,14 @@ egl_create_glx_drawable(ClientPtr client, __GLXscreen *screen,
* - drawable type masks is suspicious
*/
static struct egl_config *
translate_eglconfig(struct egl_screen *screen, EGLConfig hc,
translate_eglconfig(ScreenPtr pScreen, struct egl_screen *screen, EGLConfig hc,
struct egl_config *chain, Bool direct_color,
Bool double_buffer, Bool duplicate_for_composite,
Bool srgb_only)
{
EGLint value;
bool valid_depth;
int i;
struct egl_config *c = calloc(1, sizeof *c);
if (!c)
@ -218,6 +220,19 @@ translate_eglconfig(struct egl_screen *screen, EGLConfig hc,
}
#undef GET
/* Only expose this config if rgbBits matches a supported
* depth value.
*/
valid_depth = false;
for (i = 0; i < pScreen->numDepths && !valid_depth; i++) {
if (pScreen->allowedDepths[i].depth == c->base.rgbBits)
valid_depth = true;
}
if (!valid_depth) {
free(c);
return chain;
}
/* derived state: config caveats */
eglGetConfigAttrib(screen->display, hc, EGL_CONFIG_CAVEAT, &value);
if (value == EGL_NONE)
@ -340,13 +355,13 @@ egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen)
for (j = 0; j < 3; j++) /* direct_color */
for (k = 0; k < 2; k++) /* double_buffer */ {
if (can_srgb)
c = translate_eglconfig(screen, host_configs[i], c,
c = translate_eglconfig(pScreen, screen, host_configs[i], c,
/* direct_color */ j == 1,
/* double_buffer */ k > 0,
/* duplicate_for_composite */ j == 0,
/* srgb_only */ true);
c = translate_eglconfig(screen, host_configs[i], c,
c = translate_eglconfig(pScreen, screen, host_configs[i], c,
/* direct_color */ j == 1,
/* double_buffer */ k > 0,
/* duplicate_for_composite */ j == 0,

View file

@ -359,8 +359,6 @@ glamor_build_program(ScreenPtr screen,
vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
free(vs_prog_string);
free(fs_prog_string);
glAttachShader(prog->prog, vs_prog);
glDeleteShader(vs_prog);
glAttachShader(prog->prog, fs_prog);
@ -394,6 +392,8 @@ glamor_build_program(ScreenPtr screen,
prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
free(version_string);
free(vs_prog_string);
free(fs_prog_string);
free(fs_vars);
free(vs_vars);
return TRUE;

View file

@ -37,8 +37,8 @@ glamor_upload_boxes(DrawablePtr drawable, BoxPtr in_boxes, int in_nbox,
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
int box_index;
int bytes_per_pixel = drawable->bitsPerPixel >> 3;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
int bytes_per_pixel = PICT_FORMAT_BPP(f->render_format) >> 3;
char *tmp_bits = NULL;
if (glamor_drawable_effective_depth(drawable) == 24 && pixmap->drawable.depth == 32)
@ -145,8 +145,8 @@ glamor_download_boxes(DrawablePtr drawable, BoxPtr in_boxes, int in_nbox,
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
int box_index;
int bytes_per_pixel = drawable->bitsPerPixel >> 3;
const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
int bytes_per_pixel = PICT_FORMAT_BPP(f->render_format) >> 3;
glamor_make_current(glamor_priv);

View file

@ -141,24 +141,22 @@ static const glamor_facet glamor_facet_xv_uyvy = {
"in vec2 tcs;\n"
),
.fs_exec = (
" vec3 uyv;\n"
" vec4 frameOut = texture2D(sampler, tcs.st);\n"
"\n"
" vec4 prevPixel = texture2D(sampler, vec2(tcs.s - texelSize.x, tcs.t));\n"
" vec4 nextPixel = texture2D(sampler, vec2(tcs.s + texelSize.x, tcs.t));\n"
"\n"
" float delta = 0.50;\n"
"\n"
" int even = int(mod(tcs.x / texelSize.x, 2.0));\n"
"\n"
" uyv.rgb = float(even)*vec3(frameOut.rg, nextPixel.r) + (1.0-float(even))*vec3(prevPixel.r, frameOut.gr);\n"
"\n"
" frameOut.r = uyv.g + 1.403*(uyv.r - delta);\n"
" frameOut.g = uyv.g - 0.714*(uyv.r - delta) - 0.344*(uyv.b - delta);\n"
" frameOut.b = uyv.g + 1.773*(uyv.b - delta);\n"
" frameOut.a = 1.0;\n"
" frag_color = frameOut;\n"
),
" vec4 temp1;\n"
" vec2 xy = texture(sampler, tcs.st).xy;\n"
" vec2 prev_xy = texture(sampler, vec2(tcs.s - texelSize.x, tcs.t)).xy;\n"
" vec2 next_xy = texture(sampler, vec2(tcs.s + texelSize.x, tcs.t)).xy;\n"
"\n"
" vec3 sample_yuv;\n"
" int odd = int(mod(tcs.x / texelSize.x, 2.0));\n"
" int even = 1 - odd;\n"
" sample_yuv.yxz = float(even)*vec3(xy, next_xy.x) + float(odd)*vec3(prev_xy.x, xy.yx);\n"
"\n"
" temp1.xyz = offsetyco.www * vec3(sample_yuv.x) + offsetyco.xyz;\n"
" temp1.xyz = ucogamma.xyz * vec3(sample_yuv.y) + temp1.xyz;\n"
" temp1.xyz = clamp(vco.xyz * vec3(sample_yuv.z) + temp1.xyz, 0.0, 1.0);\n"
" temp1.w = 1.0;\n"
" frag_color = temp1;\n"
),
};
static const glamor_facet glamor_facet_xv_rgb_raw = {
@ -379,9 +377,16 @@ glamor_xv_query_image_attributes(int id,
offsets[0] = 0;
size *= *h;
break;
case FOURCC_RGB565:
case FOURCC_UYVY:
/* UYVU is single-plane really, all tranformation is processed inside a shader */
size = ALIGN(*w, 2) * 2;
if (pitches)
pitches[0] = size;
if (offsets)
offsets[0] = 0;
size *= *h;
break;
case FOURCC_RGB565:
size = *w * 2;
if (pitches)
pitches[0] = size;
@ -787,6 +792,15 @@ glamor_xv_put_image(glamor_port_private *port_priv,
buf + s2offset, srcPitch);
break;
case FOURCC_UYVY:
srcPitch = ALIGN(width, 2) * 2;
full_box.x1 = 0;
full_box.y1 = 0;
full_box.x2 = width;
full_box.y2 = height;
glamor_upload_boxes(&port_priv->src_pix[0]->drawable, &full_box, 1,
0, 0, 0, 0,
buf, srcPitch);
break;
case FOURCC_RGB565:
srcPitch = width * 2;
full_box.x1 = 0;

View file

@ -50,7 +50,3 @@ glamor = static_library('glamor',
epoxy_dep,
],
)
if build_xorg
install_data('glamor.h', install_dir: xorgsdkdir)
endif

View file

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

View file

@ -1,50 +0,0 @@
.\" $RCSId: xc/programs/Xserver/hw/kdrive/Xkdrive.man,v 1.3 2001/01/24 00:06:10 dawes Exp $
.\"
.TH Xkdrive 1 @vendorversion@
.SH NAME
Xkdrive \- tiny X server
.SH SYNOPSIS
.B Xfbdev
.RI [ :display ]
.RI [ option ...]
.SH DESCRIPTION
.B Xkdrive
is a family of X servers designed to be particularly small. This
manual page describes the common functionality of the
.B Xkdrive
servers; for information on a specific X server, please refer to the
relevant manual page.
.SH OPTIONS
In addition to the standard options accepted by all X servers (see
Xserver(1)), all the
.B Xkdrive
servers accept the following options:
.TP 8
.B -dumb
disable hardware acceleration.
.TP 8
.B -origin \fIX\fP,\fIY\fP
Locates the next screen in the Xinerama virtual screen.
.TP 8
.B -screen \fIwidth\fBx\fIheight\fR[\fBx\fIdepth\fR[\fBx\fIfreq\fR]]\fR[\fB@\fIrotation\fR]\fB
use a screen of the specified \fIwidth\fP, \fIheight\fP, screen \fIdepth\fP, \fIfrequency\fP, and \fIrotation\fP (0, 90, 180 and 270 are legal values).
.TP 8
.B -softCursor
disable the hardware cursor.
.TP 8
.B -videoTest
start the server, pause momentarily, and exit.
.TP 8
.B -zaphod
disable switching screens by moving the pointer across a screen boundary.
.TP 8
.B -2button
enable emulation of a middle mouse button by chording.
.TP 8
.B -3button
disable emulation of a middle mouse button by chording.
.SH SEE ALSO
X(@miscmansuffix@), Xserver(1), xdm(1), xinit(1), Xvesa(1), Xfbdev(1).
.SH AUTHORS
The Xkdrive common core was written by Keith Packard,
and is based on the Sample Implementation of X.

View file

@ -1 +0,0 @@
Xephyr

View file

@ -1,71 +0,0 @@
Xephyr README
=============
What Is It ?
============
Xephyr is a a kdrive server that outputs to a window on a pre-existing
'host' X display. Think Xnest but with support for modern extensions
like composite, damage and randr.
Unlike Xnest which is an X proxy, i.e. limited to the
capabilities of the host X server, Xephyr is a real X server which
uses the host X server window as "framebuffer" via fast SHM XImages.
It also has support for 'visually' debugging what the server is
painting.
How To Use
==========
You probably want to run like;
Xephyr :1 -ac -screen 800x600 &
Then set DISPLAY=:1 and run whatever X apps you like.
Use 'xrandr' to change to orientation/size.
There is a '-parent' switch which works just like Xnest's ( for use
with things like matchbox-nest - http://matchbox.handhelds.org ).
There is also a '-host-cursor' switch to set 'cursor acceleration' -
The host's cursor is reused. This is only really there to aid
debugging by avoiding server paints for the cursor. Performance
improvement is negligible.
Send a SIGUSR1 to the server ( eg kill -USR1 `pidof Xephyr` ) to
toggle the debugging mode. In this mode red rectangles are painted to
screen areas getting painted before painting the actual content. The
delay between this can be altered by setting a XEPHYR_PAUSE env var to
a value in microseconds.
Caveats
=======
- Depth is limited to being the same as the host.
*Update* As of 8/11/2004. Xephyr can now do 8bpp & 16bpp
on 24bpp host.
- Rotated displays are currently updated via full blits. This
is slower than a normal oprientated display. Debug mode will
therefore not be of much use rotated.
- The '-host-cursor' cursor is static in its appearance.
- The build gets a warning about 'nanosleep'. I think the various '-D'
build flags are causing this. I haven't figured as yet how to work
around it. It doesn't appear to break anything however.
- Keyboard handling is basic but works.
- Mouse button 5 probably won't work.
Matthew Allum <mallum@o-hand.com> 2004

File diff suppressed because it is too large Load diff

View file

@ -1,233 +0,0 @@
/*
* Xephyr - A kdrive X server that runs in a host X window.
* Authored by Matthew Allum <mallum@o-hand.com>
*
* Copyright © 2004 Nokia
*
* 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 Nokia not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Nokia makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL NOKIA 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 _EPHYR_H_
#define _EPHYR_H_
#include <stdio.h>
#include <unistd.h>
#include <libgen.h>
#include <xcb/xcb_image.h>
#include "os.h" /* for OsSignal() */
#include "kdrive.h"
#include "hostx.h"
#include "exa.h"
#ifdef RANDR
#include "randrstr.h"
#endif
#include "damage.h"
typedef struct _ephyrPriv {
CARD8 *base;
int bytes_per_line;
} EphyrPriv;
typedef struct _ephyrFakexaPriv {
ExaDriverPtr exa;
Bool is_synced;
/* The following are arguments and other information from Prepare* calls
* which are stored for use in the inner calls.
*/
int op;
PicturePtr pSrcPicture, pMaskPicture, pDstPicture;
void *saved_ptrs[3];
PixmapPtr pDst, pSrc, pMask;
GCPtr pGC;
} EphyrFakexaPriv;
typedef struct _ephyrScrPriv {
/* ephyr server info */
Rotation randr;
Bool shadow;
DamagePtr pDamage;
EphyrFakexaPriv *fakexa;
/* Host X window info */
xcb_window_t win;
xcb_window_t win_pre_existing; /* Set via -parent option like xnest */
xcb_window_t peer_win; /* Used for GL; should be at most one */
xcb_visualid_t vid;
xcb_image_t *ximg;
Bool win_explicit_position;
int win_x, win_y;
int win_width, win_height;
int server_depth;
const char *output; /* Set via -output option */
unsigned char *fb_data; /* only used when host bpp != server bpp */
xcb_shm_segment_info_t shminfo;
size_t shmsize;
KdScreenInfo *screen;
int mynum; /* Screen number */
unsigned long cmap[256];
ScreenBlockHandlerProcPtr BlockHandler;
struct ephyr_glamor *glamor;
} EphyrScrPriv;
extern KdCardFuncs ephyrFuncs;
extern KdKeyboardInfo *ephyrKbd;
extern KdPointerInfo *ephyrMouse;
extern miPointerScreenFuncRec ephyrPointerScreenFuncs;
Bool
ephyrInitialize(KdCardInfo * card, EphyrPriv * priv);
Bool
ephyrCardInit(KdCardInfo * card);
Bool
ephyrScreenInitialize(KdScreenInfo *screen);
Bool
ephyrInitScreen(ScreenPtr pScreen);
Bool
ephyrFinishInitScreen(ScreenPtr pScreen);
Bool
ephyrCreateResources(ScreenPtr pScreen);
void
ephyrPreserve(KdCardInfo * card);
Bool
ephyrEnable(ScreenPtr pScreen);
Bool
ephyrDPMS(ScreenPtr pScreen, int mode);
void
ephyrDisable(ScreenPtr pScreen);
void
ephyrRestore(KdCardInfo * card);
void
ephyrScreenFini(KdScreenInfo * screen);
void
ephyrCloseScreen(ScreenPtr pScreen);
void
ephyrCardFini(KdCardInfo * card);
void
ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs);
void
ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs);
Bool
ephyrMapFramebuffer(KdScreenInfo * screen);
void *ephyrWindowLinear(ScreenPtr pScreen,
CARD32 row,
CARD32 offset, int mode, CARD32 *size, void *closure);
void
ephyrSetScreenSizes(ScreenPtr pScreen);
Bool
ephyrUnmapFramebuffer(KdScreenInfo * screen);
void
ephyrUnsetInternalDamage(ScreenPtr pScreen);
Bool
ephyrSetInternalDamage(ScreenPtr pScreen);
Bool
ephyrCreateColormap(ColormapPtr pmap);
#ifdef RANDR
Bool
ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations);
Bool
ephyrRandRSetConfig(ScreenPtr pScreen,
Rotation randr, int rate, RRScreenSizePtr pSize);
Bool
ephyrRandRInit(ScreenPtr pScreen);
void
ephyrShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf);
#endif
void
ephyrUpdateModifierState(unsigned int state);
extern KdPointerDriver EphyrMouseDriver;
extern KdKeyboardDriver EphyrKeyboardDriver;
extern Bool ephyrCursorInit(ScreenPtr pScreen);
extern int ephyrBufferHeight(KdScreenInfo * screen);
/* ephyr_draw.c */
Bool
ephyrDrawInit(ScreenPtr pScreen);
void
ephyrDrawEnable(ScreenPtr pScreen);
void
ephyrDrawDisable(ScreenPtr pScreen);
void
ephyrDrawFini(ScreenPtr pScreen);
/* hostx.c glamor support */
Bool ephyr_glamor_init(ScreenPtr pScreen);
Bool ephyr_glamor_create_screen_resources(ScreenPtr pScreen);
void ephyr_glamor_enable(ScreenPtr pScreen);
void ephyr_glamor_disable(ScreenPtr pScreen);
void ephyr_glamor_fini(ScreenPtr pScreen);
void ephyr_glamor_host_paint_rect(ScreenPtr pScreen);
/*ephyvideo.c*/
Bool ephyrInitVideo(ScreenPtr pScreen);
/* ephyr_glamor_xv.c */
#ifdef GLAMOR
void ephyr_glamor_xv_init(ScreenPtr screen);
#else /* !GLAMOR */
static inline void
ephyr_glamor_xv_init(ScreenPtr screen)
{
}
#endif /* !GLAMOR */
#endif

View file

@ -1,533 +0,0 @@
/*
* 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>
*
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "ephyr.h"
#include "exa_priv.h"
#include "fbpict.h"
#define EPHYR_TRACE_DRAW 0
#if EPHYR_TRACE_DRAW
#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__);
#else
#define TRACE_DRAW() do { } while (0)
#endif
/* Use some oddball alignments, to expose issues in alignment handling in EXA. */
#define EPHYR_OFFSET_ALIGN 24
#define EPHYR_PITCH_ALIGN 24
#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024)
#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024)
/**
* Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
* fb functions.
*/
static void
ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
{
KdScreenPriv(pPix->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
assert(fakexa->saved_ptrs[index] == NULL);
fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
if (pPix->devPrivate.ptr != NULL)
return;
pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
}
/**
* Restores the original devPrivate.ptr of the pixmap from before we messed with
* it.
*/
static void
ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
{
KdScreenPriv(pPix->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
fakexa->saved_ptrs[index] = NULL;
}
/**
* Sets up a scratch GC for fbFill, and saves other parameters for the
* ephyrSolid implementation.
*/
static Bool
ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
{
ScreenPtr pScreen = pPix->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
ChangeGCVal tmpval[3];
ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
fakexa->pDst = pPix;
fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
tmpval[0].val = alu;
tmpval[1].val = pm;
tmpval[2].val = fg;
ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground,
tmpval);
ValidateGC(&pPix->drawable, fakexa->pGC);
TRACE_DRAW();
return TRUE;
}
/**
* Does an fbFill of the rectangle to be drawn.
*/
static void
ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
{
ScreenPtr pScreen = pPix->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1);
}
/**
* Cleans up the scratch GC created in ephyrPrepareSolid.
*/
static void
ephyrDoneSolid(PixmapPtr pPix)
{
ScreenPtr pScreen = pPix->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
FreeScratchGC(fakexa->pGC);
ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
}
/**
* Sets up a scratch GC for fbCopyArea, and saves other parameters for the
* ephyrCopy implementation.
*/
static Bool
ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
Pixel pm)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
ChangeGCVal tmpval[2];
ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
fakexa->pSrc = pSrc;
fakexa->pDst = pDst;
fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
tmpval[0].val = alu;
tmpval[1].val = pm;
ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval);
ValidateGC(&pDst->drawable, fakexa->pGC);
TRACE_DRAW();
return TRUE;
}
/**
* Does an fbCopyArea to take care of the requested copy.
*/
static void
ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC,
srcX, srcY, w, h, dstX, dstY);
}
/**
* Cleans up the scratch GC created in ephyrPrepareCopy.
*/
static void
ephyrDoneCopy(PixmapPtr pDst)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
FreeScratchGC(fakexa->pGC);
ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
}
/**
* Reports that we can always accelerate the given operation. This may not be
* desirable from an EXA testing standpoint -- testing the fallback paths would
* be useful, too.
*/
static Bool
ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture)
{
/* Exercise the component alpha helper, so fail on this case like a normal
* driver
*/
if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver)
return FALSE;
return TRUE;
}
/**
* Saves off the parameters for ephyrComposite.
*/
static Bool
ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
if (pSrc != NULL)
ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
if (pMask != NULL)
ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
fakexa->op = op;
fakexa->pSrcPicture = pSrcPicture;
fakexa->pMaskPicture = pMaskPicture;
fakexa->pDstPicture = pDstPicture;
fakexa->pSrc = pSrc;
fakexa->pMask = pMask;
fakexa->pDst = pDst;
TRACE_DRAW();
return TRUE;
}
/**
* Does an fbComposite to complete the requested drawing operation.
*/
static void
ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
int dstX, int dstY, int w, int h)
{
KdScreenPriv(pDst->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
w, h);
}
static void
ephyrDoneComposite(PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
if (fakexa->pMask != NULL)
ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
if (fakexa->pSrc != NULL)
ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
}
/**
* Does fake acceleration of DownloadFromScren using memcpy.
*/
static Bool
ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
int dst_pitch)
{
KdScreenPriv(pSrc->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
unsigned char *src;
int src_pitch, cpp;
if (pSrc->drawable.bitsPerPixel < 8)
return FALSE;
ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
cpp = pSrc->drawable.bitsPerPixel / 8;
src_pitch = exaGetPixmapPitch(pSrc);
src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
src += y * src_pitch + x * cpp;
for (; h > 0; h--) {
memcpy(dst, src, w * cpp);
dst += dst_pitch;
src += src_pitch;
}
exaMarkSync(pSrc->drawable.pScreen);
ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
return TRUE;
}
/**
* Does fake acceleration of UploadToScreen using memcpy.
*/
static Bool
ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
int src_pitch)
{
KdScreenPriv(pDst->drawable.pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
unsigned char *dst;
int dst_pitch, cpp;
if (pDst->drawable.bitsPerPixel < 8)
return FALSE;
ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
cpp = pDst->drawable.bitsPerPixel / 8;
dst_pitch = exaGetPixmapPitch(pDst);
dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
dst += y * dst_pitch + x * cpp;
for (; h > 0; h--) {
memcpy(dst, src, w * cpp);
dst += dst_pitch;
src += src_pitch;
}
exaMarkSync(pDst->drawable.pScreen);
ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
return TRUE;
}
static Bool
ephyrPrepareAccess(PixmapPtr pPix, int index)
{
/* Make sure we don't somehow end up with a pointer that is in framebuffer
* and hasn't been readied for us.
*/
assert(pPix->devPrivate.ptr != NULL);
return TRUE;
}
/**
* In fakexa, we currently only track whether we have synced to the latest
* "accelerated" drawing that has happened or not. It's not used for anything
* yet.
*/
static int
ephyrMarkSync(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
fakexa->is_synced = FALSE;
return 0;
}
/**
* Assumes that we're waiting on the latest marker. When EXA gets smarter and
* starts using markers in a fine-grained way (for example, waiting on drawing
* to required pixmaps to complete, rather than waiting for all drawing to
* complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
* implementation fine-grained as well.
*/
static void
ephyrWaitMarker(ScreenPtr pScreen, int marker)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrFakexaPriv *fakexa = scrpriv->fakexa;
fakexa->is_synced = TRUE;
}
/**
* This function initializes EXA to use the fake acceleration implementation
* which just falls through to software. The purpose is to have a reliable,
* correct driver with which to test changes to the EXA core.
*/
Bool
ephyrDrawInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = screen->driver;
EphyrPriv *priv = screen->card->driver;
EphyrFakexaPriv *fakexa;
Bool success;
fakexa = calloc(1, sizeof(*fakexa));
if (fakexa == NULL)
return FALSE;
fakexa->exa = exaDriverAlloc();
if (fakexa->exa == NULL) {
free(fakexa);
return FALSE;
}
fakexa->exa->memoryBase = (CARD8 *) (priv->base);
fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen);
fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height;
/* Since we statically link against EXA, we shouldn't have to be smart about
* versioning.
*/
fakexa->exa->exa_major = 2;
fakexa->exa->exa_minor = 0;
fakexa->exa->PrepareSolid = ephyrPrepareSolid;
fakexa->exa->Solid = ephyrSolid;
fakexa->exa->DoneSolid = ephyrDoneSolid;
fakexa->exa->PrepareCopy = ephyrPrepareCopy;
fakexa->exa->Copy = ephyrCopy;
fakexa->exa->DoneCopy = ephyrDoneCopy;
fakexa->exa->CheckComposite = ephyrCheckComposite;
fakexa->exa->PrepareComposite = ephyrPrepareComposite;
fakexa->exa->Composite = ephyrComposite;
fakexa->exa->DoneComposite = ephyrDoneComposite;
fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
fakexa->exa->UploadToScreen = ephyrUploadToScreen;
fakexa->exa->MarkSync = ephyrMarkSync;
fakexa->exa->WaitMarker = ephyrWaitMarker;
fakexa->exa->PrepareAccess = ephyrPrepareAccess;
fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
fakexa->exa->maxX = 1023;
fakexa->exa->maxY = 1023;
fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
success = exaDriverInit(pScreen, fakexa->exa);
if (success) {
ErrorF("Initialized fake EXA acceleration\n");
scrpriv->fakexa = fakexa;
}
else {
ErrorF("Failed to initialize EXA\n");
free(fakexa->exa);
free(fakexa);
}
return success;
}
void
ephyrDrawEnable(ScreenPtr pScreen)
{
}
void
ephyrDrawDisable(ScreenPtr pScreen)
{
}
void
ephyrDrawFini(ScreenPtr pScreen)
{
}
/**
* exaDDXDriverInit is required by the top-level EXA module, and is used by
* the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since
* we won't be enabling/disabling the FB.
*/
void
exaDDXDriverInit(ScreenPtr pScreen)
{
ExaScreenPriv(pScreen);
pExaScr->migration = ExaMigrationSmart;
pExaScr->checkDirtyCorrectness = TRUE;
}

View file

@ -1,440 +0,0 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/** @file ephyr_glamor.c
*
* Glamor support and EGL setup.
*/
#define MESA_EGL_NO_X11_HEADERS
#define EGL_NO_X11
#include <stdlib.h>
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <pixman.h>
#include "glamor_context.h"
#include "glamor_egl.h"
#include "glamor_priv.h"
#include "ephyr.h"
#include "ephyr_glamor.h"
#include "os.h"
/* until we need geometry shaders GL3.1 should suffice. */
/* Xephyr has its own copy of this for build reasons */
#define GLAMOR_GL_CORE_VER_MAJOR 3
#define GLAMOR_GL_CORE_VER_MINOR 1
/** @{
*
* global state for Xephyr with glamor, all of which is arguably a bug.
*/
Bool ephyr_glamor_gles2;
Bool ephyr_glamor_skip_present;
/** @} */
/**
* Per-screen state for Xephyr with glamor.
*/
struct ephyr_glamor {
EGLDisplay dpy;
EGLContext ctx;
xcb_window_t win;
EGLSurface egl_win;
GLuint tex;
GLuint texture_shader;
GLuint texture_shader_position_loc;
GLuint texture_shader_texcoord_loc;
/* Size of the window that we're rendering to. */
unsigned width, height;
GLuint vao, vbo;
};
static void
glamor_egl_make_current(struct glamor_context *glamor_ctx)
{
/* There's only a single global dispatch table in Mesa. EGL, GLX,
* and AIGLX's direct dispatch table manipulation don't talk to
* each other. We need to set the context to NULL first to avoid
* EGL's no-op context change fast path when switching back to
* EGL.
*/
eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE,
EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (!eglMakeCurrent(glamor_ctx->display,
glamor_ctx->surface, glamor_ctx->surface,
glamor_ctx->ctx)) {
FatalError("Failed to make EGL context current\n");
}
}
void
glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
{
KdScreenPriv(screen);
KdScreenInfo *kd_screen = pScreenPriv->screen;
EphyrScrPriv *scrpriv = kd_screen->driver;
struct ephyr_glamor *ephyr_glamor = scrpriv->glamor;
glamor_enable_dri3(screen);
glamor_ctx->display = ephyr_glamor->dpy;
glamor_ctx->ctx = ephyr_glamor->ctx;
glamor_ctx->surface = ephyr_glamor->egl_win;
glamor_ctx->make_current = glamor_egl_make_current;
}
int
glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride, CARD32 *size)
{
return -1;
}
int
glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
uint32_t *offsets, uint32_t *strides,
uint64_t *modifier)
{
return 0;
}
int
glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
CARD16 *stride, CARD32 *size)
{
return -1;
}
static GLuint
ephyr_glamor_build_glsl_prog(GLuint vs, GLuint fs)
{
GLint ok;
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
glGetProgramInfoLog(prog, size, NULL, info);
ErrorF("Failed to link: %s\n", info);
FatalError("GLSL link failure\n");
}
return prog;
}
static void
ephyr_glamor_setup_texturing_shader(struct ephyr_glamor *glamor)
{
const char *vs_source =
"attribute vec2 texcoord;\n"
"attribute vec2 position;\n"
"varying vec2 t;\n"
"\n"
"void main()\n"
"{\n"
" t = texcoord;\n"
" gl_Position = vec4(position, 0, 1);\n"
"}\n";
const char *fs_source =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"\n"
"varying vec2 t;\n"
"uniform sampler2D s; /* initially 0 */\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(s, t);\n"
"}\n";
GLuint fs, vs, prog;
vs = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
fs = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_source);
prog = ephyr_glamor_build_glsl_prog(vs, fs);
glamor->texture_shader = prog;
glamor->texture_shader_position_loc = glGetAttribLocation(prog, "position");
assert(glamor->texture_shader_position_loc != -1);
glamor->texture_shader_texcoord_loc = glGetAttribLocation(prog, "texcoord");
assert(glamor->texture_shader_texcoord_loc != -1);
}
#ifndef EGL_PLATFORM_XCB_EXT
#define EGL_PLATFORM_XCB_EXT 0x31DC
#endif
#include <dlfcn.h>
#ifndef RTLD_DEFAULT
#define RTLD_DEFAULT NULL
#endif
/* (loud booing)
*
* keeping this as a static variable is bad form, we _could_ have zaphod heads
* on different displays (for example). but other bits of Xephyr are already
* broken for that case, and fixing that would entail fixing the rest of the
* contortions with hostx.c anyway, so this works for now.
*/
static EGLDisplay edpy = EGL_NO_DISPLAY;
xcb_connection_t *
ephyr_glamor_connect(void)
{
int major = 0, minor = 0;
/*
* Try pure xcb first. If that doesn't work but we can find XOpenDisplay,
* fall back to xlib. This lets us potentially not load libX11 at all, if
* the EGL is also pure xcb.
*/
if (epoxy_has_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_xcb")) {
xcb_connection_t *conn = xcb_connect(NULL, NULL);
EGLDisplay dpy = glamor_egl_get_display(EGL_PLATFORM_XCB_EXT, conn);
if (dpy == EGL_NO_DISPLAY) {
xcb_disconnect(conn);
return NULL;
}
edpy = dpy;
eglInitialize(dpy, &major, &minor);
return conn;
}
if (epoxy_has_egl_extension(EGL_NO_DISPLAY, "EGL_EXT_platform_x11") ||
epoxy_has_egl_extension(EGL_NO_DISPLAY, "EGL_KHR_platform_x11)")) {
void *lib = NULL;
xcb_connection_t *ret = NULL;
void *(*x_open_display)(void *) =
(void *) dlsym(RTLD_DEFAULT, "XOpenDisplay");
xcb_connection_t *(*x_get_xcb_connection)(void *) =
(void *) dlsym(RTLD_DEFAULT, "XGetXCBConnection");
if (x_open_display == NULL)
return NULL;
if (x_get_xcb_connection == NULL) {
lib = dlopen("libX11-xcb.so.1", RTLD_LOCAL | RTLD_LAZY);
x_get_xcb_connection =
(void *) dlsym(lib, "XGetXCBConnection");
}
if (x_get_xcb_connection == NULL)
goto out;
void *xdpy = x_open_display(NULL);
EGLDisplay dpy = glamor_egl_get_display(EGL_PLATFORM_X11_KHR, xdpy);
if (dpy == EGL_NO_DISPLAY)
goto out;
edpy = dpy;
eglInitialize(dpy, &major, &minor);
ret = x_get_xcb_connection(xdpy);
out:
if (lib)
dlclose(lib);
return ret;
}
return NULL;
}
void
ephyr_glamor_set_texture(struct ephyr_glamor *glamor, uint32_t tex)
{
glamor->tex = tex;
}
static void
ephyr_glamor_set_vertices(struct ephyr_glamor *glamor)
{
glVertexAttribPointer(glamor->texture_shader_position_loc,
2, GL_FLOAT, FALSE, 0, (void *) 0);
glVertexAttribPointer(glamor->texture_shader_texcoord_loc,
2, GL_FLOAT, FALSE, 0, (void *) (sizeof (float) * 8));
glEnableVertexAttribArray(glamor->texture_shader_position_loc);
glEnableVertexAttribArray(glamor->texture_shader_texcoord_loc);
}
void
ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
struct pixman_region16 *damage)
{
GLint old_vao;
/* Skip presenting the output in this mode. Presentation is
* expensive, and if we're just running the X Test suite headless,
* nobody's watching.
*/
if (ephyr_glamor_skip_present)
return;
eglMakeCurrent(glamor->dpy, glamor->egl_win, glamor->egl_win, glamor->ctx);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
glBindVertexArray(glamor->vao);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(glamor->texture_shader);
glViewport(0, 0, glamor->width, glamor->height);
if (!ephyr_glamor_gles2)
glDisable(GL_COLOR_LOGIC_OP);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, glamor->tex);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindVertexArray(old_vao);
eglSwapBuffers(glamor->dpy, glamor->egl_win);
}
struct ephyr_glamor *
ephyr_glamor_screen_init(xcb_window_t win, xcb_visualid_t vid)
{
static const float position[] = {
-1, -1,
1, -1,
1, 1,
-1, 1,
0, 1,
1, 1,
1, 0,
0, 0,
};
GLint old_vao;
EGLContext ctx;
struct ephyr_glamor *glamor;
EGLSurface egl_win;
glamor = calloc(1, sizeof(struct ephyr_glamor));
if (!glamor) {
FatalError("malloc");
return NULL;
}
const EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NATIVE_VISUAL_ID, vid,
EGL_NONE,
};
EGLConfig config = EGL_NO_CONFIG_KHR;
int num_configs = 0;
/* (loud booing (see above)) */
glamor->dpy = edpy;
eglChooseConfig(glamor->dpy, config_attribs, &config, 1, &num_configs);
if (num_configs != 1)
FatalError("Unable to find an EGLConfig for vid %#x\n", vid);
egl_win = eglCreatePlatformWindowSurfaceEXT(glamor->dpy, config,
&win, NULL);
if (ephyr_glamor_gles2)
eglBindAPI(EGL_OPENGL_ES_API);
else
eglBindAPI(EGL_OPENGL_API);
EGLint context_attribs[5];
int i = 0;
context_attribs[i++] = EGL_CONTEXT_MAJOR_VERSION;
context_attribs[i++] = ephyr_glamor_gles2 ? 2 : 3;
context_attribs[i++] = EGL_CONTEXT_MINOR_VERSION;
context_attribs[i++] = ephyr_glamor_gles2 ? 0 : 1;
context_attribs[i++] = EGL_NONE;
ctx = eglCreateContext(glamor->dpy, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
context_attribs);
if (ctx == NULL)
FatalError("eglCreateContext failed\n");
if (!eglMakeCurrent(glamor->dpy, egl_win, egl_win, ctx))
FatalError("eglMakeCurrent failed\n");
glamor->ctx = ctx;
glamor->win = win;
glamor->egl_win = egl_win;
ephyr_glamor_setup_texturing_shader(glamor);
glGenVertexArrays(1, &glamor->vao);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
glBindVertexArray(glamor->vao);
glGenBuffers(1, &glamor->vbo);
glBindBuffer(GL_ARRAY_BUFFER, glamor->vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
ephyr_glamor_set_vertices(glamor);
glBindVertexArray(old_vao);
return glamor;
}
void
ephyr_glamor_screen_fini(struct ephyr_glamor *glamor)
{
eglMakeCurrent(glamor->dpy,
EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
eglDestroyContext(glamor->dpy, glamor->ctx);
eglDestroySurface(glamor->dpy, glamor->egl_win);
free(glamor);
}
void
ephyr_glamor_set_window_size(struct ephyr_glamor *glamor,
unsigned width, unsigned height)
{
if (!glamor)
return;
glamor->width = width;
glamor->height = height;
}

View file

@ -1,65 +0,0 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <xcb/xcb.h>
#include "dix-config.h"
struct ephyr_glamor;
struct pixman_region16;
xcb_connection_t *
ephyr_glamor_connect(void);
void
ephyr_glamor_set_texture(struct ephyr_glamor *ephyr_glamor, uint32_t tex);
struct ephyr_glamor *
ephyr_glamor_screen_init(xcb_window_t win, xcb_visualid_t vid);
void
ephyr_glamor_screen_fini(struct ephyr_glamor *glamor);
#ifdef GLAMOR
void
ephyr_glamor_set_window_size(struct ephyr_glamor *glamor,
unsigned width, unsigned height);
void
ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
struct pixman_region16 *damage);
#else /* !GLAMOR */
static inline void
ephyr_glamor_set_window_size(struct ephyr_glamor *glamor,
unsigned width, unsigned height)
{
}
static inline void
ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
struct pixman_region16 *damage)
{
}
#endif /* !GLAMOR */

View file

@ -1,161 +0,0 @@
/*
* Copyright © 2014 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "kdrive.h"
#include "kxv.h"
#include "ephyr.h"
#include "glamor_priv.h"
#include <X11/extensions/Xv.h>
#include "fourcc.h"
#define NUM_FORMATS 3
static KdVideoFormatRec Formats[NUM_FORMATS] = {
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
};
static void
ephyr_glamor_xv_stop_video(KdScreenInfo *screen, void *data, Bool cleanup)
{
if (!cleanup)
return;
glamor_xv_stop_video(data);
}
static int
ephyr_glamor_xv_set_port_attribute(KdScreenInfo *screen,
Atom attribute, int value, void *data)
{
return glamor_xv_set_port_attribute(data, attribute, (INT32)value);
}
static int
ephyr_glamor_xv_get_port_attribute(KdScreenInfo *screen,
Atom attribute, int *value, void *data)
{
return glamor_xv_get_port_attribute(data, attribute, (INT32 *)value);
}
static void
ephyr_glamor_xv_query_best_size(KdScreenInfo *screen,
Bool motion,
short vid_w, short vid_h,
short drw_w, short drw_h,
unsigned int *p_w, unsigned int *p_h,
void *data)
{
*p_w = drw_w;
*p_h = drw_h;
}
static int
ephyr_glamor_xv_query_image_attributes(KdScreenInfo *screen,
int id,
unsigned short *w, unsigned short *h,
int *pitches, int *offsets)
{
return glamor_xv_query_image_attributes(id, w, h, pitches, offsets);
}
static int
ephyr_glamor_xv_put_image(KdScreenInfo *screen,
DrawablePtr pDrawable,
short src_x, short src_y,
short drw_x, short drw_y,
short src_w, short src_h,
short drw_w, short drw_h,
int id,
unsigned char *buf,
short width,
short height,
Bool sync,
RegionPtr clipBoxes, void *data)
{
return glamor_xv_put_image(data, pDrawable,
src_x, src_y,
drw_x, drw_y,
src_w, src_h,
drw_w, drw_h,
id, buf, width, height, sync, clipBoxes);
}
void
ephyr_glamor_xv_init(ScreenPtr screen)
{
KdVideoAdaptorRec *adaptor;
glamor_port_private *port_privates;
KdVideoEncodingRec encoding = {
0,
"XV_IMAGE",
/* These sizes should probably be GL_MAX_TEXTURE_SIZE instead
* of 2048, but our context isn't set up yet.
*/
2048, 2048,
{1, 1}
};
int i;
glamor_xv_core_init(screen);
adaptor = xnfcalloc(1, sizeof(*adaptor));
adaptor->name = "glamor textured video";
adaptor->type = XvWindowMask | XvInputMask | XvImageMask;
adaptor->flags = 0;
adaptor->nEncodings = 1;
adaptor->pEncodings = &encoding;
adaptor->pFormats = Formats;
adaptor->nFormats = NUM_FORMATS;
adaptor->nPorts = 16; /* Some absurd number */
port_privates = xnfcalloc(adaptor->nPorts,
sizeof(glamor_port_private));
adaptor->pPortPrivates = xnfcalloc(adaptor->nPorts,
sizeof(glamor_port_private *));
for (i = 0; i < adaptor->nPorts; i++) {
adaptor->pPortPrivates[i].ptr = &port_privates[i];
glamor_xv_init_port(&port_privates[i]);
}
adaptor->pAttributes = glamor_xv_attributes;
adaptor->nAttributes = glamor_xv_num_attributes;
adaptor->pImages = glamor_xv_images;
adaptor->nImages = glamor_xv_num_images;
adaptor->StopVideo = ephyr_glamor_xv_stop_video;
adaptor->SetPortAttribute = ephyr_glamor_xv_set_port_attribute;
adaptor->GetPortAttribute = ephyr_glamor_xv_get_port_attribute;
adaptor->QueryBestSize = ephyr_glamor_xv_query_best_size;
adaptor->PutImage = ephyr_glamor_xv_put_image;
adaptor->QueryImageAttributes = ephyr_glamor_xv_query_image_attributes;
KdXVScreenInit(screen, adaptor, 1);
}

View file

@ -1,258 +0,0 @@
/*
* Copyright © 2014 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:
* Adam Jackson <ajax@redhat.com>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "ephyr.h"
#include "ephyrlog.h"
#include "hostx.h"
#include "cursorstr.h"
#include <xcb/render.h>
#include <xcb/xcb_renderutil.h>
static DevPrivateKeyRec ephyrCursorPrivateKey;
typedef struct _ephyrCursor {
xcb_cursor_t cursor;
} ephyrCursorRec, *ephyrCursorPtr;
static ephyrCursorPtr
ephyrGetCursor(CursorPtr cursor)
{
return dixGetPrivateAddr(&cursor->devPrivates, &ephyrCursorPrivateKey);
}
static void
ephyrRealizeCoreCursor(EphyrScrPriv *scr, CursorPtr cursor)
{
ephyrCursorPtr hw = ephyrGetCursor(cursor);
xcb_connection_t *conn = hostx_get_xcbconn();
xcb_pixmap_t source, mask;
xcb_image_t *image;
xcb_gcontext_t gc;
int w = cursor->bits->width, h = cursor->bits->height;
uint32_t gcmask = XCB_GC_FUNCTION |
XCB_GC_PLANE_MASK |
XCB_GC_FOREGROUND |
XCB_GC_BACKGROUND |
XCB_GC_CLIP_MASK;
uint32_t val[] = {
XCB_GX_COPY, /* function */
~0, /* planemask */
1L, /* foreground */
0L, /* background */
None, /* clipmask */
};
source = xcb_generate_id(conn);
mask = xcb_generate_id(conn);
xcb_create_pixmap(conn, 1, source, scr->win, w, h);
xcb_create_pixmap(conn, 1, mask, scr->win, w, h);
gc = xcb_generate_id(conn);
xcb_create_gc(conn, gc, source, gcmask, val);
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
1, NULL, ~0, NULL);
image->data = cursor->bits->source;
xcb_image_put(conn, source, gc, image, 0, 0, 0);
xcb_image_destroy(image);
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_XY_BITMAP,
1, NULL, ~0, NULL);
image->data = cursor->bits->mask;
xcb_image_put(conn, mask, gc, image, 0, 0, 0);
xcb_image_destroy(image);
xcb_free_gc(conn, gc);
hw->cursor = xcb_generate_id(conn);
xcb_create_cursor(conn, hw->cursor, source, mask,
cursor->foreRed, cursor->foreGreen, cursor->foreBlue,
cursor->backRed, cursor->backGreen, cursor->backBlue,
cursor->bits->xhot, cursor->bits->yhot);
xcb_free_pixmap(conn, source);
xcb_free_pixmap(conn, mask);
}
static xcb_render_pictformat_t
get_argb_format(void)
{
static xcb_render_pictformat_t format;
if (format == None) {
xcb_connection_t *conn = hostx_get_xcbconn();
xcb_render_query_pict_formats_cookie_t cookie;
xcb_render_query_pict_formats_reply_t *formats;
cookie = xcb_render_query_pict_formats(conn);
formats =
xcb_render_query_pict_formats_reply(conn, cookie, NULL);
format =
xcb_render_util_find_standard_format(formats,
XCB_PICT_STANDARD_ARGB_32)->id;
free(formats);
}
return format;
}
static void
ephyrRealizeARGBCursor(EphyrScrPriv *scr, CursorPtr cursor)
{
ephyrCursorPtr hw = ephyrGetCursor(cursor);
xcb_connection_t *conn = hostx_get_xcbconn();
xcb_gcontext_t gc;
xcb_pixmap_t source;
xcb_render_picture_t picture;
xcb_image_t *image;
int w = cursor->bits->width, h = cursor->bits->height;
/* dix' storage is PICT_a8r8g8b8 */
source = xcb_generate_id(conn);
xcb_create_pixmap(conn, 32, source, scr->win, w, h);
gc = xcb_generate_id(conn);
xcb_create_gc(conn, gc, source, 0, NULL);
image = xcb_image_create_native(conn, w, h, XCB_IMAGE_FORMAT_Z_PIXMAP,
32, NULL, ~0, NULL);
image->data = (void *)cursor->bits->argb;
xcb_image_put(conn, source, gc, image, 0, 0, 0);
xcb_free_gc(conn, gc);
xcb_image_destroy(image);
picture = xcb_generate_id(conn);
xcb_render_create_picture(conn, picture, source, get_argb_format(),
0, NULL);
xcb_free_pixmap(conn, source);
hw->cursor = xcb_generate_id(conn);
xcb_render_create_cursor(conn, hw->cursor, picture,
cursor->bits->xhot, cursor->bits->yhot);
xcb_render_free_picture(conn, picture);
}
static Bool
can_argb_cursor(void)
{
static const xcb_render_query_version_reply_t *v;
if (!v)
v = xcb_render_util_query_version(hostx_get_xcbconn());
return v->major_version == 0 && v->minor_version >= 5;
}
static Bool
ephyrRealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
{
KdScreenPriv(screen);
KdScreenInfo *kscr = pScreenPriv->screen;
EphyrScrPriv *scr = kscr->driver;
if (cursor->bits->argb && can_argb_cursor())
ephyrRealizeARGBCursor(scr, cursor);
else
{
ephyrRealizeCoreCursor(scr, cursor);
}
return TRUE;
}
static Bool
ephyrUnrealizeCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor)
{
ephyrCursorPtr hw = ephyrGetCursor(cursor);
if (hw->cursor) {
xcb_free_cursor(hostx_get_xcbconn(), hw->cursor);
hw->cursor = None;
}
return TRUE;
}
static void
ephyrSetCursor(DeviceIntPtr dev, ScreenPtr screen, CursorPtr cursor, int x,
int y)
{
KdScreenPriv(screen);
KdScreenInfo *kscr = pScreenPriv->screen;
EphyrScrPriv *scr = kscr->driver;
uint32_t attr = None;
if (cursor)
attr = ephyrGetCursor(cursor)->cursor;
else
attr = hostx_get_empty_cursor();
xcb_change_window_attributes(hostx_get_xcbconn(), scr->win,
XCB_CW_CURSOR, &attr);
xcb_flush(hostx_get_xcbconn());
}
static void
ephyrMoveCursor(DeviceIntPtr dev, ScreenPtr screen, int x, int y)
{
}
static Bool
ephyrDeviceCursorInitialize(DeviceIntPtr dev, ScreenPtr screen)
{
return TRUE;
}
static void
ephyrDeviceCursorCleanup(DeviceIntPtr dev, ScreenPtr screen)
{
}
miPointerSpriteFuncRec EphyrPointerSpriteFuncs = {
ephyrRealizeCursor,
ephyrUnrealizeCursor,
ephyrSetCursor,
ephyrMoveCursor,
ephyrDeviceCursorInitialize,
ephyrDeviceCursorCleanup
};
Bool
ephyrCursorInit(ScreenPtr screen)
{
if (!dixRegisterPrivateKey(&ephyrCursorPrivateKey, PRIVATE_CURSOR,
sizeof(ephyrCursorRec)))
return FALSE;
miPointerInitialize(screen,
&EphyrPointerSpriteFuncs,
&ephyrPointerScreenFuncs, FALSE);
return TRUE;
}

View file

@ -1,396 +0,0 @@
/*
* Xephyr - A kdrive X server that runs in a host X window.
* Authored by Matthew Allum <mallum@o-hand.com>
*
* Copyright © 2004 Nokia
*
* 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 Nokia not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Nokia makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL NOKIA 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "ephyr.h"
#include "ephyrlog.h"
#include "glx_extinit.h"
extern Window EphyrPreExistingHostWin;
extern Bool EphyrWantGrayScale;
extern Bool EphyrWantResize;
extern Bool EphyrWantNoHostGrab;
extern Bool kdHasPointer;
extern Bool kdHasKbd;
extern Bool ephyr_glamor, ephyr_glamor_gles2, ephyr_glamor_skip_present;
extern Bool ephyrNoXV;
void processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id);
void processOutputArg(const char *output, char *parent_id);
void processScreenArg(const char *screen_size, char *parent_id);
int
main(int argc, char *argv[], char *envp[])
{
hostx_use_resname(basename(argv[0]), 0);
return dix_main(argc, argv, envp);
}
void
InitCard(char *name)
{
EPHYR_DBG("mark");
KdCardInfoAdd(&ephyrFuncs, 0);
}
void
InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
{
KdInitOutput(pScreenInfo, argc, argv);
}
void
InitInput(int argc, char **argv)
{
KdKeyboardInfo *ki;
KdPointerInfo *pi;
KdAddKeyboardDriver(&EphyrKeyboardDriver);
KdAddPointerDriver(&EphyrMouseDriver);
if (!kdHasKbd) {
ki = KdNewKeyboard();
if (!ki)
FatalError("Couldn't create Xephyr keyboard\n");
ki->driver = &EphyrKeyboardDriver;
KdAddKeyboard(ki);
}
if (!kdHasPointer) {
pi = KdNewPointer();
if (!pi)
FatalError("Couldn't create Xephyr pointer\n");
pi->driver = &EphyrMouseDriver;
KdAddPointer(pi);
}
KdInitInput();
}
void
CloseInput(void)
{
KdCloseInput();
}
#if INPUTTHREAD
/** This function is called in Xserver/os/inputthread.c when starting
the input thread. */
void
ddxInputThreadInit(void)
{
}
#endif
#ifdef DDXBEFORERESET
void
ddxBeforeReset(void)
{
}
#endif
void
ddxUseMsg(void)
{
KdUseMsg();
ErrorF("\nXephyr Option Usage:\n");
ErrorF("-parent <XID> Use existing window as Xephyr root win\n");
ErrorF("-sw-cursor Render cursors in software in Xephyr\n");
ErrorF("-fullscreen Attempt to run Xephyr fullscreen\n");
ErrorF("-output <NAME> Attempt to run Xephyr fullscreen (restricted to given output geometry)\n");
ErrorF("-grayscale Simulate 8bit grayscale\n");
ErrorF("-resizeable Make Xephyr windows resizeable\n");
#ifdef GLAMOR
ErrorF("-glamor Enable 2D acceleration using glamor\n");
ErrorF("-glamor_gles2 Enable 2D acceleration using glamor (with GLES2 only)\n");
ErrorF("-glamor-skip-present Skip presenting the output when using glamor (for internal testing optimization)\n");
#endif
ErrorF
("-fakexa Simulate acceleration using software rendering\n");
ErrorF("-verbosity <level> Set log verbosity level\n");
ErrorF("-noxv do not use XV\n");
ErrorF("-name [name] define the name in the WM_CLASS property\n");
ErrorF
("-title [title] set the window title in the WM_NAME property\n");
ErrorF("-no-host-grab Disable grabbing the keyboard and mouse.\n");
ErrorF("\n");
}
void
processScreenOrOutputArg(const char *screen_size, const char *output, char *parent_id)
{
KdCardInfo *card;
InitCard(0); /*Put each screen on a separate card */
card = KdCardInfoLast();
if (card) {
KdScreenInfo *screen;
unsigned long p_id = 0;
Bool use_geometry;
screen = KdScreenInfoAdd(card);
KdParseScreen(screen, screen_size);
screen->driver = calloc(1, sizeof(EphyrScrPriv));
if (!screen->driver)
FatalError("Couldn't alloc screen private\n");
if (parent_id) {
p_id = strtol(parent_id, NULL, 0);
}
use_geometry = (strchr(screen_size, '+') != NULL);
EPHYR_DBG("screen number:%d\n", screen->mynum);
hostx_add_screen(screen, p_id, screen->mynum, use_geometry, output);
}
else {
ErrorF("No matching card found!\n");
}
}
void
processScreenArg(const char *screen_size, char *parent_id)
{
processScreenOrOutputArg(screen_size, NULL, parent_id);
}
void
processOutputArg(const char *output, char *parent_id)
{
processScreenOrOutputArg("100x100+0+0", output, parent_id);
}
int
ddxProcessArgument(int argc, char **argv, int i)
{
static char *parent = NULL;
EPHYR_DBG("mark argv[%d]='%s'", i, argv[i]);
if (!strcmp(argv[i], "-parent")) {
if (i + 1 < argc) {
int j;
/* If parent is specified and a screen argument follows, don't do
* anything, let the -screen handling init the rest */
for (j = i; j < argc; j++) {
if (!strcmp(argv[j], "-screen")) {
parent = argv[i + 1];
return 2;
}
}
processScreenArg("100x100", argv[i + 1]);
return 2;
}
UseMsg();
exit(1);
}
else if (!strcmp(argv[i], "-screen")) {
if ((i + 1) < argc) {
processScreenArg(argv[i + 1], parent);
parent = NULL;
return 2;
}
UseMsg();
exit(1);
}
else if (!strcmp(argv[i], "-output")) {
if (i + 1 < argc) {
processOutputArg(argv[i + 1], NULL);
return 2;
}
UseMsg();
exit(1);
}
else if (!strcmp(argv[i], "-sw-cursor")) {
hostx_use_sw_cursor();
return 1;
}
else if (!strcmp(argv[i], "-host-cursor")) {
/* Compatibility with the old command line argument, now the default. */
return 1;
}
else if (!strcmp(argv[i], "-fullscreen")) {
hostx_use_fullscreen();
return 1;
}
else if (!strcmp(argv[i], "-grayscale")) {
EphyrWantGrayScale = 1;
return 1;
}
else if (!strcmp(argv[i], "-resizeable")) {
EphyrWantResize = 1;
return 1;
}
#ifdef GLAMOR
else if (!strcmp (argv[i], "-glamor")) {
ephyr_glamor = TRUE;
ephyrFuncs.initAccel = ephyr_glamor_init;
ephyrFuncs.enableAccel = ephyr_glamor_enable;
ephyrFuncs.disableAccel = ephyr_glamor_disable;
ephyrFuncs.finiAccel = ephyr_glamor_fini;
return 1;
}
else if (!strcmp (argv[i], "-glamor_gles2")) {
ephyr_glamor = TRUE;
ephyr_glamor_gles2 = TRUE;
ephyrFuncs.initAccel = ephyr_glamor_init;
ephyrFuncs.enableAccel = ephyr_glamor_enable;
ephyrFuncs.disableAccel = ephyr_glamor_disable;
ephyrFuncs.finiAccel = ephyr_glamor_fini;
return 1;
}
else if (!strcmp (argv[i], "-glamor-skip-present")) {
ephyr_glamor_skip_present = TRUE;
return 1;
}
#endif
else if (!strcmp(argv[i], "-fakexa")) {
ephyrFuncs.initAccel = ephyrDrawInit;
ephyrFuncs.enableAccel = ephyrDrawEnable;
ephyrFuncs.disableAccel = ephyrDrawDisable;
ephyrFuncs.finiAccel = ephyrDrawFini;
return 1;
}
else if (!strcmp(argv[i], "-verbosity")) {
if (i + 1 < argc && argv[i + 1][0] != '-') {
int verbosity = atoi(argv[i + 1]);
LogSetParameter(XLOG_VERBOSITY, verbosity);
EPHYR_LOG("set verbosiry to %d\n", verbosity);
return 2;
}
else {
UseMsg();
exit(1);
}
}
else if (!strcmp(argv[i], "-noxv")) {
ephyrNoXV = TRUE;
EPHYR_LOG("no XVideo enabled\n");
return 1;
}
else if (!strcmp(argv[i], "-name")) {
if (i + 1 < argc && argv[i + 1][0] != '-') {
hostx_use_resname(argv[i + 1], 1);
return 2;
}
else {
UseMsg();
return 0;
}
}
else if (!strcmp(argv[i], "-title")) {
if (i + 1 < argc && argv[i + 1][0] != '-') {
hostx_set_title(argv[i + 1]);
return 2;
}
else {
UseMsg();
return 0;
}
}
else if (argv[i][0] == ':') {
hostx_set_display_name(argv[i]);
}
/* Xnest compatibility */
else if (!strcmp(argv[i], "-display")) {
hostx_set_display_name(argv[i + 1]);
return 2;
}
else if (!strcmp(argv[i], "-sync") ||
!strcmp(argv[i], "-full") ||
!strcmp(argv[i], "-sss") || !strcmp(argv[i], "-install")) {
return 1;
}
else if (!strcmp(argv[i], "-bw") ||
!strcmp(argv[i], "-class") ||
!strcmp(argv[i], "-geometry") || !strcmp(argv[i], "-scrns")) {
return 2;
}
/* end Xnest compat */
else if (!strcmp(argv[i], "-no-host-grab")) {
EphyrWantNoHostGrab = 1;
return 1;
}
else if (!strcmp(argv[i], "-sharevts") ||
!strcmp(argv[i], "-novtswitch")) {
return 1;
}
else if (!strcmp(argv[i], "-layout")) {
return 2;
}
return KdProcessArgument(argc, argv, i);
}
void
OsVendorInit(void)
{
EPHYR_DBG("mark");
if (SeatId)
hostx_use_sw_cursor();
if (hostx_want_host_cursor())
ephyrFuncs.initCursor = &ephyrCursorInit;
if (serverGeneration == 1) {
if (!KdCardInfoLast()) {
processScreenArg("640x480", NULL);
}
hostx_init();
}
}
KdCardFuncs ephyrFuncs = {
ephyrCardInit, /* cardinit */
ephyrScreenInitialize, /* scrinit */
ephyrInitScreen, /* initScreen */
ephyrFinishInitScreen, /* finishInitScreen */
ephyrCreateResources, /* createRes */
ephyrScreenFini, /* scrfini */
ephyrCardFini, /* cardfini */
0, /* initCursor */
0, /* initAccel */
0, /* enableAccel */
0, /* disableAccel */
0, /* finiAccel */
ephyrGetColors, /* getColors */
ephyrPutColors, /* putColors */
ephyrCloseScreen, /* closeScreen */
};

View file

@ -1,67 +0,0 @@
/*
* Xephyr - A kdrive X server that runs in a host X window.
* Authored by Matthew Allum <mallum@openedhand.com>
*
* Copyright © 2007 OpenedHand Ltd
*
* 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 OpenedHand Ltd not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. OpenedHand Ltd makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL OpenedHand Ltd 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.
*
* Authors:
* Dodji Seketeli <dodji@openedhand.com>
*/
#ifndef __EPHYRLOG_H__
#define __EPHYRLOG_H__
#include <assert.h>
#include "os.h"
#ifndef DEBUG
/*we are not in debug mode*/
#define EPHYR_LOG(...)
#define EPHYR_LOG_ERROR(...)
#endif /*!DEBUG */
#define ERROR_LOG_LEVEL 3
#define INFO_LOG_LEVEL 4
#ifndef EPHYR_LOG
#define EPHYR_LOG(...) \
LogMessageVerb(X_NOTICE, INFO_LOG_LEVEL, "in %s:%d:%s: ",\
__FILE__, __LINE__, __func__) ; \
LogMessageVerb(X_NOTICE, INFO_LOG_LEVEL, __VA_ARGS__)
#endif /*nomadik_log */
#ifndef EPHYR_LOG_ERROR
#define EPHYR_LOG_ERROR(...) \
LogMessageVerb(X_NOTICE, ERROR_LOG_LEVEL, "Error:in %s:%d:%s: ",\
__FILE__, __LINE__, __func__) ; \
LogMessageVerb(X_NOTICE, ERROR_LOG_LEVEL, __VA_ARGS__)
#endif /*EPHYR_LOG_ERROR */
#ifndef EPHYR_RETURN_IF_FAIL
#define EPHYR_RETURN_IF_FAIL(cond) \
if (!(cond)) {EPHYR_LOG_ERROR("condition %s failed\n", #cond);return;}
#endif /*nomadik_return_if_fail */
#ifndef EPHYR_RETURN_VAL_IF_FAIL
#define EPHYR_RETURN_VAL_IF_FAIL(cond,val) \
if (!(cond)) {EPHYR_LOG_ERROR("condition %s failed\n", #cond);return val;}
#endif /*nomadik_return_val_if_fail */
#endif /*__EPHYRLOG_H__*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,194 +0,0 @@
/*
* Xephyr - A kdrive X server that runs in a host X window.
* Authored by Matthew Allum <mallum@o-hand.com>
*
* Copyright © 2004 Nokia
*
* 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 Nokia not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Nokia makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL NOKIA 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 _XLIBS_STUFF_H_
#define _XLIBS_STUFF_H_
#include <X11/X.h>
#include <X11/Xmd.h>
#include <xcb/xcb.h>
#include <xcb/render.h>
#include "ephyr.h"
#define EPHYR_WANT_DEBUG 0
#if (EPHYR_WANT_DEBUG)
#define EPHYR_DBG(x, a...) \
fprintf(stderr, __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
#else
#define EPHYR_DBG(x, a...) do {} while (0)
#endif
typedef struct EphyrHostXVars EphyrHostXVars;
typedef struct {
VisualID visualid;
int screen;
int depth;
int class;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
int colormap_size;
int bits_per_rgb;
} EphyrHostVisualInfo;
typedef struct {
int x, y;
int width, height;
int visualid;
} EphyrHostWindowAttributes;
typedef struct {
int x, y, width, height;
} EphyrBox;
typedef struct {
short x1, y1, x2, y2;
} EphyrRect;
int
hostx_want_screen_geometry(KdScreenInfo *screen, int *width, int *height, int *x, int *y);
int
hostx_want_host_cursor(void);
void
hostx_use_sw_cursor(void);
xcb_cursor_t
hostx_get_empty_cursor(void);
void
hostx_get_output_geometry(const char *output,
int *x, int *y,
int *width, int *height);
void
hostx_use_fullscreen(void);
int
hostx_want_fullscreen(void);
int
hostx_want_preexisting_window(KdScreenInfo *screen);
void
hostx_use_preexisting_window(unsigned long win_id);
void
hostx_use_resname(char *name, int fromcmd);
void
hostx_set_title(char *name);
void
hostx_handle_signal(int signum);
int
hostx_init(void);
void
hostx_add_screen(KdScreenInfo *screen, unsigned long win_id, int screen_num, Bool use_geometry, const char *output);
void
hostx_set_display_name(char *name);
void
hostx_set_screen_number(KdScreenInfo *screen, int number);
void
hostx_set_win_title(KdScreenInfo *screen, const char *extra_text);
int
hostx_get_depth(void);
int
hostx_get_server_depth(KdScreenInfo *screen);
int
hostx_get_bpp(KdScreenInfo *screen);
void
hostx_get_visual_masks(KdScreenInfo *screen,
CARD32 *rmsk, CARD32 *gmsk, CARD32 *bmsk);
void
hostx_set_cmap_entry(ScreenPtr pScreen, unsigned char idx,
unsigned char r, unsigned char g, unsigned char b);
void *hostx_screen_init(KdScreenInfo *screen,
int x, int y,
int width, int height, int buffer_height,
int *bytes_per_line, int *bits_per_pixel);
void
hostx_paint_rect(KdScreenInfo *screen,
int sx, int sy, int dx, int dy, int width, int height,
Bool sync);
Bool
hostx_load_keymap(KeySymsPtr keySyms, CARD8 *modmap, XkbControlsPtr controls);
void
hostx_size_set_from_configure(Bool);
xcb_connection_t *
hostx_get_xcbconn(void);
xcb_generic_event_t *
hostx_get_event(Bool queued_only);
Bool
hostx_has_queued_event(void);
int
hostx_get_screen(void);
int
hostx_get_window(int a_screen_number);
int
hostx_get_window_attributes(int a_window, EphyrHostWindowAttributes * a_attr);
int
hostx_get_visuals_info(EphyrHostVisualInfo ** a_visuals, int *a_num_entries);
int hostx_create_window(int a_screen_number,
EphyrBox * a_geometry,
int a_visual_id, int *a_host_win /*out parameter */ );
int hostx_destroy_window(int a_win);
int hostx_set_window_geometry(int a_win, EphyrBox * a_geo);
int hostx_set_window_bounding_rectangles(int a_window,
EphyrRect * a_rects, int a_num_rects);
int hostx_has_extension(xcb_extension_t *extension);
int hostx_get_fd(void);
#endif /*_XLIBS_STUFF_H_*/

View file

@ -1,96 +0,0 @@
.\"
.\" Copyright (c) Matthieu Herrb <matthieu@herrb.eu>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, 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.
.\"
.TH Xephyr @appmansuffix@ @vendorversion@
.SH NAME
Xephyr - X server outputting to a window on a pre-existing X display
.SH SYNOPSIS
.B Xephyr
.RI [\fB:\fP display ]
.RI [ option
.IR ... ]
.SH DESCRIPTION
.B Xephyr
is a kdrive server that outputs to a window on a pre-existing "host"
X display.
Think
.I Xnest
but with support for modern extensions like composite, damage and randr.
.PP
Unlike
.I Xnest
which is an X proxy, i.e. limited to the capabilities of the host X server,
.B Xephyr
is a real X server which
uses the host X server window as "framebuffer" via fast SHM XImages.
.PP
It also has support for "visually" debugging what the server is
painting.
.SH OPTIONS
The server accepts all the standard options of Xserver(@appmansuffix@)
and the following additional options:
.TP 8
.BI -screen " width" x height
sets the screen size.
.TP 8
.BI -parent " id"
uses existing window
.I id .
If a
.BI -screen
argument follows a
.BI -parent
argument, this screen is embedded into the given window.
.TP 8
.B -host-cursor
set 'cursor acceleration':
The host's cursor is reused. This is only really there to aid
debugging by avoiding server paints for the cursor. Performance
improvement is negligible.
.TP 8
.B -resizeable
Allow the Xephyr window to be resized, even if not embedded into a parent
window. By default, the Xephyr window has a fixed size.
.TP 8
.B -no-host-grab
Disable grabbing the keyboard and mouse.
.SH "SIGNALS"
Send a SIGUSR1 to the server (e.g. pkill -USR1 Xephyr) to
toggle the debugging mode.
In this mode red rectangles are painted to
screen areas getting painted before painting the actual content.
The
delay between this can be altered by setting a XEPHYR_PAUSE env var to
a value in micro seconds.
.SH CAVEATS
.PP
.IP \(bu 2
Rotated displays are currently updated via full blits. This
is slower than a normal orientated display. Debug mode will
therefore not be of much use rotated.
.IP \(bu 2
The '-host-cursor' cursor is static in its appearance.
.IP \(bu 2
The build gets a warning about 'nanosleep'. I think the various '-D'
build flags are causing this. I haven't figured as yet how to work
round it. It doesn't appear to break anything however.
.IP \(bu 2
Keyboard handling is basic but works.
.IP \(bu 2
Mouse button 5 probably won't work.
.SH "SEE ALSO"
X(@miscmansuffix@), Xserver(@appmansuffix@)
.SH AUTHOR
Matthew Allum <mallum@o-hand.com> 2004

View file

@ -1,69 +0,0 @@
srcs = [
'ephyr.c',
'ephyrinit.c',
'ephyrcursor.c',
'ephyr_draw.c',
'hostx.c',
]
xephyr_dep = [
common_dep,
dependency('xcb'),
dependency('xcb-shape'),
dependency('xcb-render'),
dependency('xcb-renderutil'),
dependency('xcb-aux'),
dependency('xcb-image'),
dependency('xcb-icccm'),
dependency('xcb-shm', version : '>=1.9.3'),
dependency('xcb-keysyms'),
dependency('xcb-randr'),
dependency('xcb-xkb'),
]
xephyr_glamor = []
if build_glamor
srcs += 'ephyr_glamor.c'
if build_xv
srcs += 'ephyr_glamor_xv.c'
endif
xephyr_glamor += glamor
xephyr_dep += epoxy_dep
xephyr_dep += dependency('xcb-glx')
endif
if build_xv
srcs += 'ephyrvideo.c'
xephyr_dep += dependency('xcb-xv')
endif
xephyr_server = executable(
'Xephyr',
srcs,
include_directories: [
inc,
include_directories('../src')
],
dependencies: xephyr_dep,
link_with: [
libxserver_main,
libxserver_exa,
xephyr_glamor,
kdrive,
libxserver_fb,
libxserver,
libxserver_config,
libxserver_xkb_stubs,
libxserver_xi_stubs,
libxserver_glx,
libglxvnd,
],
install: true,
)
xephyr_man = configure_file(
input: 'man/Xephyr.man',
output: 'Xephyr.1',
configuration: manpage_config,
)
install_man(xephyr_man)

View file

@ -1,2 +0,0 @@
subdir('src')
subdir('ephyr')

View file

@ -1,234 +0,0 @@
/*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "kdrive.h"
/*
* Put the entire colormap into the DAC
*/
static void
KdSetColormap(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ColormapPtr pCmap = pScreenPriv->pInstalledmap;
Pixel pixels[KD_MAX_PSEUDO_SIZE];
xrgb colors[KD_MAX_PSEUDO_SIZE];
xColorItem defs[KD_MAX_PSEUDO_SIZE];
int i;
if (!pScreenPriv->card->cfuncs->putColors)
return;
if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH)
return;
if (!pScreenPriv->enabled)
return;
if (!pCmap)
return;
/*
* Make DIX convert pixels into RGB values -- this handles
* true/direct as well as pseudo/static visuals
*/
for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++)
pixels[i] = i;
QueryColors(pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors,
serverClient);
for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) {
defs[i].pixel = i;
defs[i].red = colors[i].red;
defs[i].green = colors[i].green;
defs[i].blue = colors[i].blue;
defs[i].flags = DoRed | DoGreen | DoBlue;
}
(*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen,
(1 << pScreenPriv->screen->fb.
depth), defs);
}
/*
* When the hardware is enabled, save the hardware colors and store
* the current colormap
*/
void
KdEnableColormap(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
int i;
if (!pScreenPriv->card->cfuncs->putColors)
return;
if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) {
for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++)
pScreenPriv->systemPalette[i].pixel = i;
(*pScreenPriv->card->cfuncs->getColors) (pScreen,
(1 << pScreenPriv->screen->fb.
depth),
pScreenPriv->systemPalette);
}
KdSetColormap(pScreen);
}
void
KdDisableColormap(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
if (!pScreenPriv->card->cfuncs->putColors)
return;
if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) {
(*pScreenPriv->card->cfuncs->putColors) (pScreen,
(1 << pScreenPriv->screen->fb.
depth),
pScreenPriv->systemPalette);
}
}
/*
* KdInstallColormap
*
* This function is called when the server receives a request to install a
* colormap or when the server needs to install one on its own, like when
* there's no window manager running and the user has moved the pointer over
* an X client window. It needs to build an identity Windows palette for the
* colormap and realize it into the Windows system palette.
*/
void
KdInstallColormap(ColormapPtr pCmap)
{
KdScreenPriv(pCmap->pScreen);
if (pCmap == pScreenPriv->pInstalledmap)
return;
/* Tell X clients that the installed colormap is going away. */
if (pScreenPriv->pInstalledmap)
WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap,
(void *) &(pScreenPriv->pInstalledmap->mid));
/* Take note of the new installed colorscreen-> */
pScreenPriv->pInstalledmap = pCmap;
KdSetColormap(pCmap->pScreen);
/* Tell X clients of the new colormap */
WalkTree(pCmap->pScreen, TellGainedMap, (void *) &(pCmap->mid));
}
/*
* KdUninstallColormap
*
* This function uninstalls a colormap by either installing
* the default X colormap or erasing the installed colormap pointer.
* The default X colormap itself cannot be uninstalled.
*/
void
KdUninstallColormap(ColormapPtr pCmap)
{
KdScreenPriv(pCmap->pScreen);
Colormap defMapID;
ColormapPtr defMap;
/* ignore if not installed */
if (pCmap != pScreenPriv->pInstalledmap)
return;
/* ignore attempts to uninstall default colormap */
defMapID = pCmap->pScreen->defColormap;
if ((Colormap) pCmap->mid == defMapID)
return;
/* install default */
dixLookupResourceByType((void **) &defMap, defMapID, RT_COLORMAP,
serverClient, DixInstallAccess);
if (defMap)
(*pCmap->pScreen->InstallColormap) (defMap);
else {
/* uninstall and clear colormap pointer */
WalkTree(pCmap->pScreen, TellLostMap, (void *) &(pCmap->mid));
pScreenPriv->pInstalledmap = 0;
}
}
int
KdListInstalledColormaps(ScreenPtr pScreen, Colormap * pCmaps)
{
KdScreenPriv(pScreen);
int n = 0;
if (pScreenPriv->pInstalledmap) {
*pCmaps++ = pScreenPriv->pInstalledmap->mid;
n++;
}
return n;
}
/*
* KdStoreColors
*
* This function is called whenever the server receives a request to store
* color values into one or more entries in the currently installed X
* colormap; it can be either the default colormap or a private colorscreen->
*/
void
KdStoreColors(ColormapPtr pCmap, int ndef, xColorItem * pdefs)
{
KdScreenPriv(pCmap->pScreen);
VisualPtr pVisual;
xColorItem expanddefs[KD_MAX_PSEUDO_SIZE];
if (pCmap != pScreenPriv->pInstalledmap)
return;
if (!pScreenPriv->card->cfuncs->putColors)
return;
if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH)
return;
if (!pScreenPriv->enabled)
return;
/* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */
pVisual = pCmap->pVisual;
if ((pVisual->class | DynamicClass) == DirectColor) {
/*
* Expand DirectColor or TrueColor color values into a PseudoColor
* format. Defer to the Color Framebuffer (CFB) code to do that.
*/
ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs);
pdefs = expanddefs;
}
(*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs);
}

File diff suppressed because it is too large Load diff

View file

@ -1,438 +0,0 @@
/*
* 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.
*/
#ifndef _KDRIVE_H_
#define _KDRIVE_H_
#include <stdio.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include <X11/Xos.h>
#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 "shadow.h"
#include "randrstr.h"
#include "globals.h"
#include "xkbstr.h"
#define KD_DPMS_NORMAL 0
#define KD_DPMS_STANDBY 1
#define KD_DPMS_SUSPEND 2
#define KD_DPMS_POWERDOWN 3
#define KD_DPMS_MAX KD_DPMS_POWERDOWN
#define Status int
typedef struct _KdCardInfo {
struct _KdCardFuncs *cfuncs;
void *closure;
void *driver;
struct _KdScreenInfo *screenList;
int selected;
struct _KdCardInfo *next;
} KdCardInfo;
extern KdCardInfo *kdCardInfo;
/*
* Configuration information per X screen
*/
typedef struct _KdFrameBuffer {
CARD8 *frameBuffer;
int depth;
int bitsPerPixel;
int pixelStride;
int byteStride;
Bool shadow;
unsigned long visuals;
Pixel redMask, greenMask, blueMask;
void *closure;
} KdFrameBuffer;
#define RR_Rotate_All (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270)
#define RR_Reflect_All (RR_Reflect_X|RR_Reflect_Y)
typedef struct _KdScreenInfo {
struct _KdScreenInfo *next;
KdCardInfo *card;
ScreenPtr pScreen;
void *driver;
Rotation randr; /* rotation and reflection */
int x;
int y;
int width;
int height;
int rate;
int width_mm;
int height_mm;
int subpixel_order;
Bool dumb;
Bool softCursor;
int mynum;
DDXPointRec origin;
KdFrameBuffer fb;
} KdScreenInfo;
typedef struct _KdCardFuncs {
Bool (*cardinit) (KdCardInfo *); /* detect and map device */
Bool (*scrinit) (KdScreenInfo *); /* initialize screen information */
Bool (*initScreen) (ScreenPtr); /* initialize ScreenRec */
Bool (*finishInitScreen) (ScreenPtr pScreen);
Bool (*createRes) (ScreenPtr); /* create screen resources */
void (*scrfini) (KdScreenInfo *); /* close down screen */
void (*cardfini) (KdCardInfo *); /* close down */
Bool (*initCursor) (ScreenPtr); /* detect and map cursor */
Bool (*initAccel) (ScreenPtr);
void (*enableAccel) (ScreenPtr);
void (*disableAccel) (ScreenPtr);
void (*finiAccel) (ScreenPtr);
void (*getColors) (ScreenPtr, int, xColorItem *);
void (*putColors) (ScreenPtr, int, xColorItem *);
void (*closeScreen) (ScreenPtr); /* close ScreenRec */
} KdCardFuncs;
#define KD_MAX_PSEUDO_DEPTH 8
#define KD_MAX_PSEUDO_SIZE (1 << KD_MAX_PSEUDO_DEPTH)
typedef struct {
KdScreenInfo *screen;
KdCardInfo *card;
Bool enabled;
Bool closed;
int bytesPerPixel;
int dpmsState;
ColormapPtr pInstalledmap; /* current colormap */
xColorItem systemPalette[KD_MAX_PSEUDO_SIZE]; /* saved windows colors */
CreateScreenResourcesProcPtr CreateScreenResources;
CloseScreenProcPtr CloseScreen;
} KdPrivScreenRec, *KdPrivScreenPtr;
typedef enum _kdPointerState {
start,
button_1_pend,
button_1_down,
button_2_down,
button_3_pend,
button_3_down,
synth_2_down_13,
synth_2_down_3,
synth_2_down_1,
num_input_states
} KdPointerState;
#define KD_MAX_BUTTON 32
#define KD_KEYBOARD 1
#define KD_MOUSE 2
#define KD_TOUCHSCREEN 3
typedef struct _KdPointerInfo KdPointerInfo;
typedef struct _KdPointerDriver {
const char *name;
Status(*Init) (KdPointerInfo *);
Status(*Enable) (KdPointerInfo *);
void (*Disable) (KdPointerInfo *);
void (*Fini) (KdPointerInfo *);
struct _KdPointerDriver *next;
} KdPointerDriver;
struct _KdPointerInfo {
DeviceIntPtr dixdev;
char *name;
char *path;
char *protocol;
InputOption *options;
int inputClass;
CARD8 map[KD_MAX_BUTTON + 1];
int nButtons;
int nAxes;
Bool emulateMiddleButton;
unsigned long emulationTimeout;
int emulationDx, emulationDy;
Bool timeoutPending;
KdPointerState mouseState;
Bool eventHeld;
struct {
int type;
int x;
int y;
int z;
int flags;
int absrel;
} heldEvent;
unsigned char buttonState;
Bool transformCoordinates;
int pressureThreshold;
KdPointerDriver *driver;
void *driverPrivate;
struct _KdPointerInfo *next;
};
void KdAddPointerDriver(KdPointerDriver * driver);
void KdRemovePointerDriver(KdPointerDriver * driver);
KdPointerInfo *KdNewPointer(void);
void KdFreePointer(KdPointerInfo *);
int KdAddPointer(KdPointerInfo * ki);
int KdAddConfigPointer(char *pointer);
void KdRemovePointer(KdPointerInfo * ki);
#define KD_KEY_COUNT 248
#define KD_MIN_KEYCODE 8
#define KD_MAX_KEYCODE 255
#define KD_MAX_WIDTH 4
#define KD_MAX_LENGTH (KD_MAX_KEYCODE - KD_MIN_KEYCODE + 1)
typedef struct {
KeySym modsym;
int modbit;
} KdKeySymModsRec;
typedef struct _KdKeyboardInfo KdKeyboardInfo;
typedef struct _KdKeyboardDriver {
const char *name;
Bool (*Init) (KdKeyboardInfo *);
Bool (*Enable) (KdKeyboardInfo *);
void (*Leds) (KdKeyboardInfo *, int);
void (*Bell) (KdKeyboardInfo *, int, int, int);
void (*Disable) (KdKeyboardInfo *);
void (*Fini) (KdKeyboardInfo *);
struct _KdKeyboardDriver *next;
} KdKeyboardDriver;
struct _KdKeyboardInfo {
struct _KdKeyboardInfo *next;
DeviceIntPtr dixdev;
void *closure;
char *name;
char *path;
int inputClass;
char *xkbRules;
char *xkbModel;
char *xkbLayout;
char *xkbVariant;
char *xkbOptions;
int LockLed;
int minScanCode;
int maxScanCode;
int leds;
int bellPitch;
int bellDuration;
InputOption *options;
KdKeyboardDriver *driver;
void *driverPrivate;
};
void KdAddKeyboardDriver(KdKeyboardDriver * driver);
void KdRemoveKeyboardDriver(KdKeyboardDriver * driver);
KdKeyboardInfo *KdNewKeyboard(void);
void KdFreeKeyboard(KdKeyboardInfo * ki);
int KdAddConfigKeyboard(char *pointer);
int KdAddKeyboard(KdKeyboardInfo * ki);
void KdRemoveKeyboard(KdKeyboardInfo * ki);
typedef struct _KdPointerMatrix {
int matrix[2][3];
} KdPointerMatrix;
extern DevPrivateKeyRec kdScreenPrivateKeyRec;
#define kdScreenPrivateKey (&kdScreenPrivateKeyRec)
extern Bool kdEmulateMiddleButton;
extern Bool kdDisableZaphod;
#define KdGetScreenPriv(pScreen) ((KdPrivScreenPtr) \
dixLookupPrivate(&(pScreen)->devPrivates, kdScreenPrivateKey))
#define KdSetScreenPriv(pScreen,v) \
dixSetPrivate(&(pScreen)->devPrivates, kdScreenPrivateKey, v)
#define KdScreenPriv(pScreen) KdPrivScreenPtr pScreenPriv = KdGetScreenPriv(pScreen)
/* kcmap.c */
void
KdEnableColormap(ScreenPtr pScreen);
void
KdDisableColormap(ScreenPtr pScreen);
void
KdInstallColormap(ColormapPtr pCmap);
void
KdUninstallColormap(ColormapPtr pCmap);
int
KdListInstalledColormaps(ScreenPtr pScreen, Colormap * pCmaps);
void
KdStoreColors(ColormapPtr pCmap, int ndef, xColorItem * pdefs);
/* kdrive.c */
extern miPointerScreenFuncRec kdPointerScreenFuncs;
void
KdDisableScreen(ScreenPtr pScreen);
Bool
KdEnableScreen(ScreenPtr pScreen);
void
KdEnableScreens(void);
void
KdProcessSwitch(void);
Rotation KdAddRotation(Rotation a, Rotation b);
Rotation KdSubRotation(Rotation a, Rotation b);
void
KdParseScreen(KdScreenInfo * screen, const char *arg);
const char *
KdParseFindNext(const char *cur, const char *delim, char *save, char *last);
void
KdUseMsg(void);
int
KdProcessArgument(int argc, char **argv, int i);
void
KdOsAddInputDrivers(void);
void
KdInitCard(ScreenInfo * pScreenInfo, KdCardInfo * card, int argc, char **argv);
void
KdInitOutput(ScreenInfo * pScreenInfo, int argc, char **argv);
void
KdSetSubpixelOrder(ScreenPtr pScreen, Rotation randr);
void
KdBacktrace(int signum);
/* kinfo.c */
KdCardInfo *KdCardInfoAdd(KdCardFuncs * funcs, void *closure);
KdCardInfo *KdCardInfoLast(void);
void
KdCardInfoDispose(KdCardInfo * ci);
KdScreenInfo *KdScreenInfoAdd(KdCardInfo * ci);
void
KdScreenInfoDispose(KdScreenInfo * si);
/* kinput.c */
void
KdInitInput(void);
void
KdCloseInput(void);
void
KdEnqueueKeyboardEvent(KdKeyboardInfo * ki, unsigned char scan_code,
unsigned char is_up);
#define KD_BUTTON_1 0x01
#define KD_BUTTON_2 0x02
#define KD_BUTTON_3 0x04
#define KD_BUTTON_4 0x08
#define KD_BUTTON_5 0x10
#define KD_BUTTON_8 0x80
#define KD_POINTER_DESKTOP 0x40000000
#define KD_MOUSE_DELTA 0x80000000
void
KdEnqueuePointerEvent(KdPointerInfo * pi, unsigned long flags, int rx, int ry,
int rz);
void
KdSetPointerMatrix(KdPointerMatrix *pointer);
void
KdComputePointerMatrix(KdPointerMatrix *pointer, Rotation randr, int width,
int height);
void
KdBlockHandler(ScreenPtr pScreen, void *timeout);
void
KdWakeupHandler(ScreenPtr pScreen, int result);
void
KdDisableInput(void);
void
KdEnableInput(void);
/* kshadow.c */
Bool
KdShadowFbAlloc(KdScreenInfo * screen, Bool rotate);
void
KdShadowFbFree(KdScreenInfo * screen);
Bool
KdShadowSet(ScreenPtr pScreen, int randr, ShadowUpdateProc update,
ShadowWindowProc window);
void
KdShadowUnset(ScreenPtr pScreen);
/* function prototypes to be implemented by the drivers */
void
InitCard(char *name);
#endif /* _KDRIVE_H_ */

View file

@ -1,154 +0,0 @@
/*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "kdrive.h"
KdCardInfo *kdCardInfo;
KdCardInfo *
KdCardInfoAdd(KdCardFuncs * funcs, void *closure)
{
KdCardInfo *ci, **prev;
ci = calloc(1, sizeof(KdCardInfo));
if (!ci)
return 0;
for (prev = &kdCardInfo; *prev; prev = &(*prev)->next);
*prev = ci;
ci->cfuncs = funcs;
ci->closure = closure;
ci->screenList = 0;
ci->selected = 0;
ci->next = 0;
return ci;
}
KdCardInfo *
KdCardInfoLast(void)
{
KdCardInfo *ci;
if (!kdCardInfo)
return 0;
for (ci = kdCardInfo; ci->next; ci = ci->next);
return ci;
}
void
KdCardInfoDispose(KdCardInfo * ci)
{
KdCardInfo **prev;
for (prev = &kdCardInfo; *prev; prev = &(*prev)->next)
if (*prev == ci) {
*prev = ci->next;
free(ci);
break;
}
}
KdScreenInfo *
KdScreenInfoAdd(KdCardInfo * ci)
{
KdScreenInfo *si, **prev;
int n;
si = calloc(1, sizeof(KdScreenInfo));
if (!si)
return 0;
for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++);
*prev = si;
si->next = 0;
si->card = ci;
si->mynum = n;
return si;
}
void
KdScreenInfoDispose(KdScreenInfo * si)
{
KdCardInfo *ci = si->card;
KdScreenInfo **prev;
for (prev = &ci->screenList; *prev; prev = &(*prev)->next) {
if (*prev == si) {
*prev = si->next;
free(si);
if (!ci->screenList)
KdCardInfoDispose(ci);
break;
}
}
}
KdPointerInfo *
KdNewPointer(void)
{
KdPointerInfo *pi;
int i;
pi = (KdPointerInfo *) calloc(1, sizeof(KdPointerInfo));
if (!pi)
return NULL;
pi->name = strdup("Generic Pointer");
pi->path = NULL;
pi->inputClass = KD_MOUSE;
pi->driver = NULL;
pi->driverPrivate = NULL;
pi->next = NULL;
pi->options = NULL;
pi->nAxes = 3;
pi->nButtons = KD_MAX_BUTTON;
for (i = 1; i < KD_MAX_BUTTON; i++)
pi->map[i] = i;
return pi;
}
void
KdFreePointer(KdPointerInfo * pi)
{
free(pi->name);
free(pi->path);
input_option_free_list(&pi->options);
pi->next = NULL;
free(pi);
}
void
KdFreeKeyboard(KdKeyboardInfo * ki)
{
free(ki->name);
free(ki->path);
free(ki->xkbRules);
free(ki->xkbModel);
free(ki->xkbLayout);
free(ki->xkbVariant);
free(ki->xkbOptions);
input_option_free_list(&ki->options);
ki->next = NULL;
free(ki);
}

File diff suppressed because it is too large Load diff

View file

@ -1,80 +0,0 @@
/*
* 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "kdrive.h"
Bool
KdShadowFbAlloc(KdScreenInfo * screen, Bool rotate)
{
int paddedWidth;
void *buf;
int width = rotate ? screen->height : screen->width;
int height = rotate ? screen->width : screen->height;
int bpp = screen->fb.bitsPerPixel;
/* use fb computation for width */
paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
buf = xallocarray(paddedWidth, height);
if (!buf)
return FALSE;
if (screen->fb.shadow)
free(screen->fb.frameBuffer);
screen->fb.shadow = TRUE;
screen->fb.frameBuffer = buf;
screen->fb.byteStride = paddedWidth;
screen->fb.pixelStride = paddedWidth * 8 / bpp;
return TRUE;
}
void
KdShadowFbFree(KdScreenInfo * screen)
{
if (screen->fb.shadow) {
free(screen->fb.frameBuffer);
screen->fb.frameBuffer = 0;
screen->fb.shadow = FALSE;
}
}
Bool
KdShadowSet(ScreenPtr pScreen, int randr, ShadowUpdateProc update,
ShadowWindowProc window)
{
KdScreenPriv(pScreen);
KdScreenInfo *screen = pScreenPriv->screen;
shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
if (screen->fb.shadow) {
return shadowAdd(pScreen, pScreen->GetScreenPixmap(pScreen),
update, window, randr, 0);
}
return TRUE;
}
void
KdShadowUnset(ScreenPtr pScreen)
{
shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
}

File diff suppressed because it is too large Load diff

View file

@ -1,197 +0,0 @@
/*
XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com)
Adapted for KDrive by Pontus Lidman <pontus.lidman@nokia.com>
Copyright (C) 2000, 2001 - Nokia Home Communications
Copyright (C) 1998, 1999 - The XFree86 Project Inc.
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 the rights to use, copy, modify, merge, publish,
distribute, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.
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
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.
*/
#ifndef _XVDIX_H_
#define _XVDIX_H_
#include "scrnintstr.h"
#include "regionstr.h"
#include "windowstr.h"
#include "pixmapstr.h"
#include "mivalidate.h"
#include "validate.h"
#include "resource.h"
#include "gcstruct.h"
#include "dixstruct.h"
#include "../../Xext/xvdix.h"
#define VIDEO_OVERLAID_IMAGES 0x00000004
#define VIDEO_OVERLAID_STILLS 0x00000008
#define VIDEO_CLIP_TO_VIEWPORT 0x00000010
typedef int (*PutVideoFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short vid_x, short vid_y, short drw_x,
short drw_y, short vid_w, short vid_h,
short drw_w, short drw_h, RegionPtr clipBoxes,
void *data);
typedef int (*PutStillFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short vid_x, short vid_y, short drw_x,
short drw_y, short vid_w, short vid_h,
short drw_w, short drw_h, RegionPtr clipBoxes,
void *data);
typedef int (*GetVideoFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short vid_x, short vid_y, short drw_x,
short drw_y, short vid_w, short vid_h,
short drw_w, short drw_h, RegionPtr clipBoxes,
void *data);
typedef int (*GetStillFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short vid_x, short vid_y, short drw_x,
short drw_y, short vid_w, short vid_h,
short drw_w, short drw_h, RegionPtr clipBoxes,
void *data);
typedef void (*StopVideoFuncPtr) (KdScreenInfo * screen, void *data,
Bool Exit);
typedef int (*SetPortAttributeFuncPtr) (KdScreenInfo * screen, Atom attribute,
int value, void *data);
typedef int (*GetPortAttributeFuncPtr) (KdScreenInfo * screen, Atom attribute,
int *value, void *data);
typedef void (*QueryBestSizeFuncPtr) (KdScreenInfo * screen, Bool motion,
short vid_w, short vid_h, short drw_w,
short drw_h, unsigned int *p_w,
unsigned int *p_h, void *data);
typedef int (*PutImageFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int image,
unsigned char *buf, short width, short height,
Bool Sync, RegionPtr clipBoxes, void *data);
typedef int (*ReputImageFuncPtr) (KdScreenInfo * screen, DrawablePtr pDraw,
short drw_x, short drw_y, RegionPtr clipBoxes,
void *data);
typedef int (*QueryImageAttributesFuncPtr) (KdScreenInfo * screen, int image,
unsigned short *width,
unsigned short *height,
int *pitches, int *offsets);
typedef enum {
XV_OFF,
XV_PENDING,
XV_ON
} XvStatus;
/*** this is what the driver needs to fill out ***/
typedef struct {
int id;
const char *name;
unsigned short width, height;
XvRationalRec rate;
} KdVideoEncodingRec, *KdVideoEncodingPtr;
typedef struct {
char depth;
short class;
} KdVideoFormatRec, *KdVideoFormatPtr;
typedef struct {
unsigned int type;
int flags;
const char *name;
int nEncodings;
KdVideoEncodingPtr pEncodings;
int nFormats;
KdVideoFormatPtr pFormats;
int nPorts;
DevUnion *pPortPrivates;
int nAttributes;
XvAttributePtr pAttributes;
int nImages;
XvImagePtr pImages;
PutVideoFuncPtr PutVideo;
PutStillFuncPtr PutStill;
GetVideoFuncPtr GetVideo;
GetStillFuncPtr GetStill;
StopVideoFuncPtr StopVideo;
SetPortAttributeFuncPtr SetPortAttribute;
GetPortAttributeFuncPtr GetPortAttribute;
QueryBestSizeFuncPtr QueryBestSize;
PutImageFuncPtr PutImage;
ReputImageFuncPtr ReputImage;
QueryImageAttributesFuncPtr QueryImageAttributes;
} KdVideoAdaptorRec, *KdVideoAdaptorPtr;
Bool
KdXVScreenInit(ScreenPtr pScreen, KdVideoAdaptorPtr Adaptors, int num);
/*** These are DDX layer privates ***/
typedef struct {
DestroyWindowProcPtr DestroyWindow;
ClipNotifyProcPtr ClipNotify;
WindowExposuresProcPtr WindowExposures;
CloseScreenProcPtr CloseScreen;
} KdXVScreenRec, *KdXVScreenPtr;
typedef struct {
int flags;
PutVideoFuncPtr PutVideo;
PutStillFuncPtr PutStill;
GetVideoFuncPtr GetVideo;
GetStillFuncPtr GetStill;
StopVideoFuncPtr StopVideo;
SetPortAttributeFuncPtr SetPortAttribute;
GetPortAttributeFuncPtr GetPortAttribute;
QueryBestSizeFuncPtr QueryBestSize;
PutImageFuncPtr PutImage;
ReputImageFuncPtr ReputImage;
QueryImageAttributesFuncPtr QueryImageAttributes;
} XvAdaptorRecPrivate, *XvAdaptorRecPrivatePtr;
typedef struct {
KdScreenInfo *screen;
DrawablePtr pDraw;
unsigned char type;
unsigned int subWindowMode;
DDXPointRec clipOrg;
RegionPtr clientClip;
RegionPtr pCompositeClip;
Bool FreeCompositeClip;
XvAdaptorRecPrivatePtr AdaptorRec;
XvStatus isOn;
Bool moved;
int vid_x, vid_y, vid_w, vid_h;
int drw_x, drw_y, drw_w, drw_h;
DevUnion DevPriv;
} XvPortRecPrivate, *XvPortRecPrivatePtr;
typedef struct _KdXVWindowRec {
XvPortRecPrivatePtr PortRec;
struct _KdXVWindowRec *next;
} KdXVWindowRec, *KdXVWindowPtr;
#endif /* _XVDIX_H_ */

View file

@ -1,20 +0,0 @@
srcs_kdrive = [
'kcmap.c',
'kdrive.c',
'kinfo.c',
'kinput.c',
'kshadow.c',
'../../../mi/miinitext.c',
'../../../mi/miinitext.h',
]
if build_xv
srcs_kdrive += 'kxv.c'
endif
kdrive = static_library('kdrive',
srcs_kdrive,
include_directories: inc,
dependencies: common_dep,
link_with: libxserver_miext_shadow,
)

View file

@ -1,27 +1,7 @@
if get_option('xephyr')
subdir('kdrive')
endif
if get_option('xvfb')
subdir('vfb')
endif
if build_xnest
subdir('xnest')
endif
if build_xorg
subdir('xfree86')
endif
if build_xquartz
subdir('xquartz')
endif
if build_xwayland
subdir('xwayland')
endif
if build_xwin
subdir('xwin')
endif

View file

@ -1,124 +0,0 @@
.\" $XdotOrg: xc/programs/Xserver/hw/vfb/Xvfb.man,v 1.3 2005/03/23 20:49:52 gisburn Exp $
.\" $Xorg: Xvfb.man,v 1.4 2001/02/09 02:04:45 xorgcvs Exp $
.\" Copyright 1993, 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.
.\"
.\" $XFree86: xc/programs/Xserver/hw/vfb/Xvfb.man,v 1.9 2001/12/14 19:59:45 dawes Exp $
.\"
.TH XVFB 1 @xorgversion@
.SH NAME
Xvfb \- virtual framebuffer X server for X Version 11
.SH SYNOPSIS
.B Xvfb
[ option ] ...
.SH DESCRIPTION
.I Xvfb
is an X server that can run on machines with no display hardware
and no physical input devices. It emulates a dumb framebuffer using
virtual memory.
.PP
The primary use of this server was intended to be server testing. The
fb code for any depth can be exercised with this server
without the need for real hardware that supports the desired depths.
The X community has found many other novel uses for \fIXvfb\fP,
including testing clients against unusual depths and screen
configurations, doing batch processing with \fIXvfb\fP as a background
rendering engine, load testing, as an aid to porting the X server to a
new platform, and providing an unobtrusive way to run applications
that don't really need an X server but insist on having one anyway.
.SH OPTIONS
.PP
In addition to the normal server options described in the \fIXserver(1)\fP
manual page, \fIXvfb\fP accepts the following command line switches:
.TP 4
.B "\-screen \fIscreennum\fP \fIWxHxD\fP"
This option creates screen \fIscreennum\fP and sets its width, height,
and depth to W, H, and D respectively. By default, only screen 0 exists
and has the dimensions 1280x1024x24.
.TP 4
.B "\-pixdepths \fIlist-of-depths\fP"
This option specifies a list of pixmap depths that the server should
support in addition to the depths implied by the supported screens.
\fIlist-of-depths\fP is a space-separated list of integers that can
have values from 1 to 32.
.TP 4
.B "\-fbdir \fIframebuffer-directory\fP"
This option specifies the directory in which the memory mapped files
containing the framebuffer memory should be created.
See FILES.
This option only exists on machines that have the mmap and msync system
calls.
.TP 4
.B "\-shmem"
This option specifies that the framebuffer should be put in shared memory.
The shared memory ID for each screen will be printed by the server.
The shared memory is in xwd format.
This option only exists on machines that support the System V shared memory
interface.
.PP
If neither \fB\-shmem\fP nor \fB\-fbdir\fP is specified,
the framebuffer memory will be allocated with malloc().
.TP 4
.B "\-linebias \fIn\fP"
This option specifies how to adjust the pixelization of thin lines.
The value \fIn\fP is a bitmask of octants in which to prefer an axial
step when the Bresenham error term is exactly zero. See the file
Xserver/mi/miline.h for more information. This option is probably only useful
to server developers to experiment with the range of line pixelization
possible with the fb code.
.TP 4
.B "\-blackpixel \fIpixel-value\fP, \-whitepixel \fIpixel-value\fP"
These options specify the black and white pixel values the server should use.
.SH FILES
The following files are created if the \-fbdir option is given.
.TP 4
\fIframebuffer-directory\fP/Xvfb_screen<n>
Memory mapped file containing screen n's framebuffer memory, one file
per screen. The file is in xwd format. Thus, taking a full-screen
snapshot can be done with a file copy command, and the resulting
snapshot will even contain the cursor image.
.SH EXAMPLES
.TP 8
Xvfb :1 -screen 0 1600x1200x24
The server will listen for connections as server number 1, and screen 0
will be depth 24 1600x1200.
.TP 8
Xvfb :1 -screen 1 1600x1200x16
The server will listen for connections as server number 1, screen 0 will have the
default screen configuration (1280x1024x24), and screen 1 will be depth 16 1600x1200.
.TP 8
Xvfb -pixdepths 3 27 -fbdir /var/tmp
The server will listen for connections as server number 0, will have the
default screen configuration (one screen, 1280x1024x24),
will also support pixmap
depths of 3 and 27,
and will use memory mapped files in /var/tmp for the framebuffer.
.TP 8
xwud -in /var/tmp/Xvfb_screen0
Displays screen 0 of the server started by the preceding example.
.SH "SEE ALSO"
.PP
X(@miscmansuffix@), Xserver(1), xwd(1), xwud(1), XWDFile.h
.SH AUTHORS
David P. Wiggins, The Open Group, Inc.

View file

@ -19,11 +19,5 @@ xvfb_server = executable(
libxserver_glx,
libglxvnd,
],
install: true,
install: false,
)
install_man(configure_file(
input: 'man/Xvfb.man',
output: 'Xvfb.1',
configuration: manpage_config,
))

View file

@ -1,6 +0,0 @@
Xorg
Xorg.wrap
Xorg.sh
xorg.conf.example
sdksyms.c
sdksyms.dep

View file

@ -1,11 +0,0 @@
#!/bin/sh
#
# Execute Xorg.wrap if it exists otherwise execute Xorg directly.
# This allows distros to put the suid wrapper in a separate package.
basedir=@SUID_WRAPPER_DIR@
if [ -x "$basedir"/Xorg.wrap ]; then
exec "$basedir"/Xorg.wrap "$@"
else
exec "$basedir"/Xorg "$@"
fi

View file

@ -1,3 +0,0 @@
# Add & Override for this directory and its subdirectories
xf86Build.h
xf86DefModeSet.c

File diff suppressed because it is too large Load diff

View file

@ -1,55 +0,0 @@
#ifndef __DGAPROC_H
#define __DGAPROC_H
#include <X11/Xproto.h>
#include "pixmap.h"
#define DGA_CONCURRENT_ACCESS 0x00000001
#define DGA_FILL_RECT 0x00000002
#define DGA_BLIT_RECT 0x00000004
#define DGA_BLIT_RECT_TRANS 0x00000008
#define DGA_PIXMAP_AVAILABLE 0x00000010
#define DGA_INTERLACED 0x00010000
#define DGA_DOUBLESCAN 0x00020000
#define DGA_FLIP_IMMEDIATE 0x00000001
#define DGA_FLIP_RETRACE 0x00000002
#define DGA_COMPLETED 0x00000000
#define DGA_PENDING 0x00000001
#define DGA_NEED_ROOT 0x00000001
typedef struct {
int num; /* A unique identifier for the mode (num > 0) */
const char *name; /* name of mode given in the XF86Config */
int VSync_num;
int VSync_den;
int flags; /* DGA_CONCURRENT_ACCESS, etc... */
int imageWidth; /* linear accessible portion (pixels) */
int imageHeight;
int pixmapWidth; /* Xlib accessible portion (pixels) */
int pixmapHeight; /* both fields ignored if no concurrent access */
int bytesPerScanline;
int byteOrder; /* MSBFirst, LSBFirst */
int depth;
int bitsPerPixel;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
short visualClass;
int viewportWidth;
int viewportHeight;
int xViewportStep; /* viewport position granularity */
int yViewportStep;
int maxViewportX; /* max viewport origin */
int maxViewportY;
int viewportFlags; /* types of page flipping possible */
int offset;
int reserved1;
int reserved2;
} XDGAModeRec, *XDGAModePtr;
#endif /* __DGAPROC_H */

View file

@ -1,168 +0,0 @@
//
// Extra modes to include as default modes in the X server.
//
// $XFree86: xc/programs/Xserver/hw/xfree86/etc/extramodes,v 1.5 2002/06/05 19:43:05 dawes Exp $
//
# 832x624 @ 75Hz (74.55Hz) (fix if the official/Apple spec is different) hsync: 49.725kHz
ModeLine "832x624" 57.284 832 864 928 1152 624 625 628 667 -Hsync -Vsync
# 1400x1050 @ 60Hz (VESA GTF) hsync: 65.5kHz
ModeLine "1400x1050" 122.0 1400 1488 1640 1880 1050 1052 1064 1082 +hsync +vsync
# 1400x1050 @ 75Hz (VESA GTF) hsync: 82.2kHz
ModeLine "1400x1050" 155.8 1400 1464 1784 1912 1050 1052 1064 1090 +hsync +vsync
# 1920x1440 @ 85Hz (VESA GTF) hsync: 128.5kHz
Modeline "1920x1440" 341.35 1920 2072 2288 2656 1440 1441 1444 1512 -hsync +vsync
# 2048x1536 @ 60Hz (VESA GTF) hsync: 95.3kHz
Modeline "2048x1536" 266.95 2048 2200 2424 2800 1536 1537 1540 1589 -hsync +vsync
# 2048x1536 @ 75Hz (VESA GTF) hsync: 120.2kHz
Modeline "2048x1536" 340.48 2048 2216 2440 2832 1536 1537 1540 1603 -hsync +vsync
# 2048x1536 @ 85Hz (VESA GTF) hsync: 137.0kHz
Modeline "2048x1536" 388.04 2048 2216 2440 2832 1536 1537 1540 1612 -hsync +vsync
### 16:9 modelines generated by cvt
# 640x360 59.32 Hz (CVT 0.23M9-R) hsync: 22.19 kHz; pclk: 17.75 MHz
Modeline "640x360R" 17.75 640 688 720 800 360 363 368 374 +hsync -vsync
# 640x360 59.84 Hz (CVT 0.23M9) hsync: 22.50 kHz; pclk: 18.00 MHz
Modeline "640x360" 18.00 640 664 720 800 360 363 368 376 -hsync +vsync
# 720x405 58.99 Hz (CVT 0.29M9-R) hsync: 24.72 kHz; pclk: 21.75 MHz
Modeline "720x405R" 21.75 720 768 800 880 405 408 413 419 +hsync -vsync
# 720x405 59.51 Hz (CVT 0.29M9) hsync: 25.11 kHz; pclk: 22.50 MHz
Modeline "720x405" 22.50 720 744 808 896 405 408 413 422 -hsync +vsync
# 864x486 59.57 Hz (CVT 0.42M9-R) hsync: 29.79 kHz; pclk: 30.50 MHz
Modeline "864x486R" 30.50 864 912 944 1024 486 489 494 500 +hsync -vsync
# 864x486 59.92 Hz (CVT 0.42M9) hsync: 30.32 kHz; pclk: 32.50 MHz
Modeline "864x486" 32.50 864 888 968 1072 486 489 494 506 -hsync +vsync
# 960x540 59.82 Hz (CVT 0.52M9-R) hsync: 33.26 kHz; pclk: 37.25 MHz
Modeline "960x540R" 37.25 960 1008 1040 1120 540 543 548 556 +hsync -vsync
# 960x540 59.63 Hz (CVT 0.52M9) hsync: 33.51 kHz; pclk: 40.75 MHz
Modeline "960x540" 40.75 960 992 1088 1216 540 543 548 562 -hsync +vsync
# 1024x576 59.82 Hz (CVT 0.59M9-R) hsync: 35.47 kHz; pclk: 42.00 MHz
Modeline "1024x576R" 42.00 1024 1072 1104 1184 576 579 584 593 +hsync -vsync
# 1024x576 59.90 Hz (CVT 0.59M9) hsync: 35.88 kHz; pclk: 46.50 MHz
Modeline "1024x576" 46.50 1024 1064 1160 1296 576 579 584 599 -hsync +vsync
# 1280x720 59.74 Hz (CVT 0.92M9-R) hsync: 44.27 kHz; pclk: 63.75 MHz
Modeline "1280x720R" 63.75 1280 1328 1360 1440 720 723 728 741 +hsync -vsync
# 1280x720 59.86 Hz (CVT 0.92M9) hsync: 44.77 kHz; pclk: 74.50 MHz
Modeline "1280x720" 74.50 1280 1344 1472 1664 720 723 728 748 -hsync +vsync
# 1368x768 59.85 Hz (CVT) hsync: 47.28 kHz; pclk: 72.25 MHz
Modeline "1368x768R" 72.25 1368 1416 1448 1528 768 771 781 790 +hsync -vsync
# 1368x768 59.88 Hz (CVT) hsync: 47.79 kHz; pclk: 85.25 MHz
Modeline "1368x768" 85.25 1368 1440 1576 1784 768 771 781 798 -hsync +vsync
# 1600x900 59.82 Hz (CVT 1.44M9-R) hsync: 55.40 kHz; pclk: 97.50 MHz
Modeline "1600x900R" 97.50 1600 1648 1680 1760 900 903 908 926 +hsync -vsync
# 1600x900 59.95 Hz (CVT 1.44M9) hsync: 55.99 kHz; pclk: 118.25 MHz
Modeline "1600x900" 118.25 1600 1696 1856 2112 900 903 908 934 -hsync +vsync
# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz
Modeline "1920x1080R" 138.50 1920 1968 2000 2080 1080 1083 1088 1111 +hsync -vsync
# 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz
Modeline "1920x1080" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
# 2048x1152 59.91 Hz (CVT 2.36M9-R) hsync: 70.99 kHz; pclk: 156.75 MHz
Modeline "2048x1152R" 156.75 2048 2096 2128 2208 1152 1155 1160 1185 +hsync -vsync
# 2048x1152 59.90 Hz (CVT 2.36M9) hsync: 71.58 kHz; pclk: 197.00 MHz
Modeline "2048x1152" 197.00 2048 2184 2400 2752 1152 1155 1160 1195 -hsync +vsync
# 2560x1440 59.95 Hz (CVT 3.69M9-R) hsync: 88.79 kHz; pclk: 241.50 MHz
Modeline "2560x1440R" 241.50 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync
# 2560x1440 59.96 Hz (CVT 3.69M9) hsync: 89.52 kHz; pclk: 312.25 MHz
Modeline "2560x1440" 312.25 2560 2752 3024 3488 1440 1443 1448 1493 -hsync +vsync
# 2880x1620 59.97 Hz (CVT 4.67M9-R) hsync: 99.92 kHz; pclk: 303.75 MHz
Modeline "2880x1620R" 303.75 2880 2928 2960 3040 1620 1623 1628 1666 +hsync -vsync
# 2880x1620 59.96 Hz (CVT 4.67M9) hsync: 100.67 kHz; pclk: 396.25 MHz
Modeline "2880x1620" 396.25 2880 3096 3408 3936 1620 1623 1628 1679 -hsync +vsync
# 3200x1800 59.94 Hz (CVT 5.76M9-R) hsync: 111.01 kHz; pclk: 373.00 MHz
Modeline "3200x1800R" 373.00 3200 3248 3280 3360 1800 1803 1808 1852 +hsync -vsync
# 3200x1800 59.96 Hz (CVT 5.76M9) hsync: 111.82 kHz; pclk: 492.00 MHz
Modeline "3200x1800" 492.00 3200 3456 3800 4400 1800 1803 1808 1865 -hsync +vsync
# 3840x2160 59.97 Hz (CVT 8.29M9-R) hsync: 133.25 kHz; pclk: 533.00 MHz
Modeline "3840x2160R" 533.00 3840 3888 3920 4000 2160 2163 2168 2222 +hsync -vsync
# 3840x2160 59.98 Hz (CVT 8.29M9) hsync: 134.18 kHz; pclk: 712.75 MHz
Modeline "3840x2160" 712.75 3840 4160 4576 5312 2160 2163 2168 2237 -hsync +vsync
# 4096x2304 59.98 Hz (CVT 9.44M9-R) hsync: 142.15 kHz; pclk: 605.00 MHz
Modeline "4096x2304R" 605.00 4096 4144 4176 4256 2304 2307 2312 2370 +hsync -vsync
# 4096x2304 59.99 Hz (CVT 9.44M9) hsync: 143.13 kHz; pclk: 813.00 MHz
Modeline "4096x2304" 813.00 4096 4440 4888 5680 2304 2307 2312 2386 -hsync +vsync
# 5120x2880 59.99 Hz (CVT 14.75M9-R) hsync: 177.70 kHz; pclk: 938.25 MHz
Modeline "5120x2880R" 938.25 5120 5168 5200 5280 2880 2883 2888 2962 +hsync -vsync
# 5120x2880 59.99 Hz (CVT 14.75M9) hsync: 178.88 kHz; pclk: 1276.50 MHz
Modeline "5120x2880" 1276.50 5120 5560 6128 7136 2880 2883 2888 2982 -hsync +vsync
# 7680x4320 59.99 Hz (CVT 33.18M9-R) hsync: 266.55 kHz; pclk: 2089.75 MHz
Modeline "7680x4320R" 2089.75 7680 7728 7760 7840 4320 4323 4328 4443 +hsync -vsync
# 7680x4320 59.99 Hz (CVT 33.18M9) hsync: 268.22 kHz; pclk: 2892.50 MHz
Modeline "7680x4320" 2892.50 7680 8376 9232 10784 4320 4323 4328 4471 -hsync +vsync
# 15360x8640 59.99 Hz (CVT 132.71M9-R) hsync: 533.10 kHz; pclk: 8273.75 MHz
Modeline "15360x8640R" 8273.75 15360 15408 15440 15520 8640 8643 8648 8886 +hsync -vsync
# 15360x8640 60.00 Hz (CVT 132.71M9) hsync: 536.27 kHz; pclk: 11669.25 MHz
Modeline "15360x8640" 11669.25 15360 16824 18560 21760 8640 8643 8648 8938 -hsync +vsync
## 16:10 modelines generated by cvt
# 1280x800 59.91 Hz (CVT 1.02MA-R) hsync: 49.31 kHz; pclk: 71.00 MHz
Modeline "1280x800R" 71.00 1280 1328 1360 1440 800 803 809 823 +hsync -vsync
# 1280x800 59.81 Hz (CVT 1.02MA) hsync: 49.70 kHz; pclk: 83.50 MHz
Modeline "1280x800" 83.50 1280 1352 1480 1680 800 803 809 831 -hsync +vsync
# 1400x900 59.88 Hz (CVT) hsync: 55.45 kHz; pclk: 86.50 MHz
Modeline "1400x900R" 86.50 1400 1448 1480 1560 900 903 913 926 +hsync -vsync
# 1400x900 59.96 Hz (CVT) hsync: 56.01 kHz; pclk: 103.50 MHz
Modeline "1400x900" 103.50 1400 1480 1624 1848 900 903 913 934 -hsync +vsync
# 1680x1050 59.88 Hz (CVT 1.76MA-R) hsync: 64.67 kHz; pclk: 119.00 MHz
Modeline "1680x1050R" 119.00 1680 1728 1760 1840 1050 1053 1059 1080 +hsync -vsync
# 1680x1050 59.95 Hz (CVT 1.76MA) hsync: 65.29 kHz; pclk: 146.25 MHz
Modeline "1680x1050" 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync
# 1920x1200 59.95 Hz (CVT 2.30MA-R) hsync: 74.04 kHz; pclk: 154.00 MHz
Modeline "1920x1200R" 154.00 1920 1968 2000 2080 1200 1203 1209 1235 +hsync -vsync
# 1920x1200 59.88 Hz (CVT 2.30MA) hsync: 74.56 kHz; pclk: 193.25 MHz
Modeline "1920x1200" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync
# 2560x1600 59.97 Hz (CVT 4.10MA-R) hsync: 98.71 kHz; pclk: 268.50 MHz
Modeline "2560x1600R" 268.50 2560 2608 2640 2720 1600 1603 1609 1646 +hsync -vsync
# 2560x1600 59.99 Hz (CVT 4.10MA) hsync: 99.46 kHz; pclk: 348.50 MHz
Modeline "2560x1600" 348.50 2560 2760 3032 3504 1600 1603 1609 1658 -hsync +vsync

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