Discussion:
[PATCH xorgproto v8 01/14] dri3: Add modifier/multi-plane requests, bump to v1.2
Daniel Stone
2018-02-28 01:16:27 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

DRI3 version 1.2 adds support for explicit format modifiers,
including multi-planar buffers.

Signed-off-by: Daniel Stone <***@collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
---
dri3proto.pc.in | 2 +-
dri3proto.txt | 319 +++++++++++++++++++++++++++++++++++--
include/X11/extensions/dri3proto.h | 86 +++++++++-
meson.build | 2 +-
4 files changed, 396 insertions(+), 13 deletions(-)

diff --git a/dri3proto.pc.in b/dri3proto.pc.in
index 6d81d07..e42d60e 100644
--- a/dri3proto.pc.in
+++ b/dri3proto.pc.in
@@ -5,5 +5,5 @@ includedir=@includedir@

Name: DRI3Proto
Description: DRI3 extension headers
-Version: 1.0
+Version: 1.2
Cflags: -I${includedir}
diff --git a/dri3proto.txt b/dri3proto.txt
index dac11d3..94322e7 100644
--- a/dri3proto.txt
+++ b/dri3proto.txt
@@ -1,16 +1,22 @@
The DRI3 Extension
- Version 1.0
- 2013-6-4
-
+ Version 1.2
+ 2018-02-28
+
Keith Packard
***@keithp.com
Intel Corporation

+ Daniel Stone
+ ***@collabora.com
+ Collabora
+
+
1. Introduction

The DRI3 extension provides mechanisms to translate between direct
rendered buffers and X pixmaps. When combined with the Present extension,
-a complete direct rendering solution for OpenGL is provided.
+a complete direct rendering solution for hardware-accelerated devices
+such as GPUs is provided.

The direct rendered buffers are passed across the protocol via
standard POSIX file descriptor passing mechanisms. On Linux, these
@@ -25,8 +31,9 @@ which can be used to serialize access to shared render buffers.
Eric Anholt <***@anholt.net>
Dave Airlie <***@redhat.com>
Kristian Høgsberg <***@bitplanet.net>
-James Jones <***@nvidia.com>
+James Jones <***@nvidia.com>
Arthur Huillet <***@free.fr>
+Louis-Francis Ratté-Boulianne <***@collabora.com>

❄ ❄ ❄ ❄ ❄ ❄ ❄

@@ -117,9 +124,10 @@ The name of this extension is "DRI3"
Errors: Alloc, Drawable, IDChoice, Value, Match

Creates a pixmap for the direct rendering object associated
- with 'buffer'. Changes to pixmap will be visible in that
- direct rendered object and changes to the direct rendered
- object will be visible in the pixmap.
+ with 'buffer' and the screen associated with 'drawable'.
+ Changes to pixmap will be visible in that direct rendered
+ object and changes to the direct rendered object will be
+ visible in the pixmap.

'size' specifies the total size of the buffer bytes. 'width',
'height' describe the geometry (in pixels) of the underlying
@@ -137,6 +145,9 @@ The name of this extension is "DRI3"
If depth or bpp are not supported by the screen, a Value error
is returned.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3BufferFromPixmap
pixmap: PIXMAP
@@ -167,6 +178,9 @@ The name of this extension is "DRI3"
If buffer cannot be used with the screen associated with
drawable, a Match error is returned.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3FenceFromFD
drawable: DRAWABLE
@@ -182,6 +196,9 @@ The name of this extension is "DRI3"
Details about the mechanism used with this file descriptor are
outside the scope of the DRI3 extension.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3FDFromFence
drawable: DRAWABLE
@@ -199,8 +216,163 @@ The name of this extension is "DRI3"
associated with a direct rendering device that 'fence' can
work with, otherwise a Match error results.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.

- ❄ ❄ ❄ ❄ ❄ ❄ ❄
+┌───
+ DRI3GetSupportedModifiers
+ window: WINDOW
+ depth: CARD8
+ bpp: CARD8
+ ▶
+ num_window_modifiers: CARD32
+ num_screen_modifiers: CARD32
+ window_modifiers: ListOfCARD64
+ screen_modifiers: ListOfCARD64
+└───
+ Errors: Window, Match
+
+ Return supported DRM FourCC modifiers for the specified
+ 'window'.
+
+ The first list of 'window_modifiers' contains a set of
+ modifiers which the server considers optimal for the window's
+ current configuration. Using these modifiers to allocate, even
+ if locally suboptimal to the client driver, may result in a
+ more optimal display pipeline, e.g. by avoiding composition.
+
+ The second list of 'screen_modifiers', is the total set of
+ modifiers which are acceptable for use on the Screen associated
+ with 'window'. This set of modifiers will not change over the
+ lifetime of the client. Using this set of modifiers to allocate
+ may not result in a globally optimal pipeline, if separate
+ 'window_modifiers' are available.
+
+ It is expected that a client calling this request will obtain
+ the modifiers for a particular window, allocate buffers using
+ the preferred modifier set as described above, create a Pixmap
+ referring to the storage of those buffers using the
+ DRI3BuffersFromPixmap request, then make the content visible
+ in the storage of those buffers visible with a request such as
+ the Present extension's PresentPixmap.
+
+ The meaning of any modifier is canonically defined in
+ drm_fourcc.h.
+
+┌───
+ DRI3PixmapFromBuffers
+ pixmap: PIXMAP
+ window: WINDOW
+ num_buffers: CARD8
+ width, height: CARD16
+ stride0, offset0: CARD32
+ stride1, offset1: CARD32
+ stride2, offset2: CARD32
+ stride3, offset3: CARD32
+ depth, bpp: CARD8
+ modifier: CARD64
+ buffers: ListOfFD
+└───
+ Errors: Alloc, Window, IDChoice, Value, Match
+
+ Creates a pixmap for the direct rendering object associated
+ with 'buffers' and the screen associated with 'window'.
+ Changes to pixmap will be visible in that direct rendered
+ object and changes to the direct rendered object will be
+ visible in the pixmap. The pixmap will be available for
+ presentation to the window.
+
+ In contrast to PixmapFromBuffer, multiple buffers may be
+ combined to specify a single logical source for pixel
+ sampling: 'num_buffers' may be set from 1 (single buffer,
+ akin to PixmapFromBuffer) to 4. This is the number of file
+ descriptors which will be sent with this request; one per
+ buffer.
+
+ Modifiers allow explicit specification of non-linear sources,
+ such as tiled or compressed buffers. The combination of bpp,
+ depth, and modifier allows unambiguous declaration of the
+ buffer layout in a manner defined by the DRM tokens.
+
+ If 'modifier' is DRM_FORMAT_MOD_INVALID, the client does
+ not have information on the buffer layout. In this case, the
+ buffer may only have a single plane. The driver may make its
+ own inference through unspecified means to determine the exact
+ buffer layout, however this is neither required nor defined
+ by the specification, and is considered an implementation
+ detail of the particular driver.
+
+ 'width' and 'height' describe the geometry (in pixels) of the
+ logical pixel-sample source.
+
+ 'strideN' and 'offsetN' define the number of bytes per logical
+ scanline, and the distance in bytes from the beginning of the
+ buffer passed for that plane until the start of the sample
+ source for that plane, respectively for plane N. If the plane
+ is not used according to the format and modifier specification,
+ both values for that plane must be zero.
+
+ Precisely how any additional information about the buffer (such
+ as memory placement) is shared is outside the scope of this
+ extension.
+
+ If the buffer(s) cannot be used with the screen associated with
+ 'window', a Match error is returned.
+
+ If the bpp, depth, and modifier combination is not supported by
+ the screen, a Value error is returned.
+
+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
+┌───
+ DRI3BuffersFromPixmap
+ pixmap: PIXMAP
+ ▶
+ nfd: CARD8
+ width, height: CARD16
+ depth, bpp: CARD8
+ modifier: CARD64
+ strides: ListOfCARD32
+ offsets: ListOfCARD32
+ buffers: ListOfFD
+└───
+ Errors: Pixmap, Match
+
+ Returns direct rendering objects associated with 'pixmap'.
+ Changes to 'pixmap' will be visible in the direct rendered
+ objects and changes to the direct rendered objects will be
+ visible in 'pixmap' after flushing and synchronization.
+
+ 'width' and 'height' describe the geometry (in pixels) of the
+ logical pixel-sample source from combining the direct rendering
+ objects.
+
+ See PixmapFromBuffers for more details on DRM modifiers usage.
+
+ 'nfd' describes the number of buffers returned for the pixmap,
+ which must be combined together according to 'depth', 'bpp', and
+ 'modifier'.
+
+ For each buffer, there is an entry in the 'strides',
+ 'offsets', and 'buffers' list. 'buffer' contains a single file
+ descriptor referring to the buffer. 'stride' specifies the
+ number of bytes per logical scanline for this plane, and
+ 'offset' specifies the distance in bytes from the beginning
+ of 'buffer' until the start of the sample source for that
+ plane.
+
+ Precisely how any additional information about the buffer is
+ shared is outside the scope of this extension.
+
+ If buffers cannot be exported from the the screen associated
+ with 'pixmap', a Match error is returned.
+
+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
+
+ ❄ ❄ ❄ ❄ ❄ ❄ ❄

9. Extension Events

@@ -214,6 +386,11 @@ The DRI3 extension is adapted from the DRI2 extension.

1.0: First published version

+ 1.1: Cosmetic changes
+
+ 1.2: Add GetSupportedModifiers,
+ PixmapFromBuffers, and BuffersFromPixmap requests.
+
❄ ❄ ❄ ❄ ❄ ❄ ❄


@@ -249,6 +426,57 @@ objects from the X server.

❄ ❄ ❄ ❄ ❄ ❄ ❄

+12. Synchronization
+
+Synchronization of access to buffers shared between processes is not
+currently explicitly controlled by this protocol.
+
+Without the use of additional extensions not defined by the DRI3
+protocol as of version 1.2, synchronization between multiple
+processes and contexts is considered to follow the implicit model.
+
+In this model, the driver is required to have a global view of
+access requests issued by all processes with a reference to the
+buffer, and control scheduling of all operations on that buffer,
+whether performed by the CPU or auxiliary hardware.
+
+The driver is responsible for enforcing a strict ordering to protect
+against write-after-read or read-after-write hazards, such that any
+reads requested by one process or context, are fulfilled before any
+writes requested by another process or context, as long as that read
+was definitively submitted before the write.
+
+A similar dependency exists for reads submitted after writes: the
+driver must ensure that the write is fully visible and coherent to
+the read request.
+
+As a purely illustrative example, if two processes share a buffer,
+where one process reads from a buffer using an OpenGL texture
+sampler and submits this work by calling 'glFlush', and the other
+process submits work to the driver to write to that buffer, the
+driver is responsible for ensuring that the results of the latter
+write are not visible to the texture sampler.
+
+The Sync fences provided by DRI3 control only this submission of
+work and ensuing global visibility of the requests, rather than the
+completion of the work within any hardware. To further the example
+above, a fence used to prevent any writes to the buffer before the
+sampler had completed access, the fence would be signaled when
+'glFlush' had been called, at which point the request has become
+globally visible to the driver's request-scheduling and
+synchronization mechanisms. The logical ordering of requests made
+by software has been preserved, and the driver then takes care
+to ensure that these requests are scheduled such they do not
+observe effects from requests made later in time.
+
+This presents a fully coherent in-order FIFO-like model across
+processes, where synchronzation is handled externally to the DRI3
+client with no explicit intervention.
+
+This restriction also applies for cross-device usage.
+
+ ❄ ❄ ❄ ❄ ❄ ❄ ❄
+
Appendix A. Protocol Encoding

Syntactic Conventions
@@ -367,6 +595,79 @@ A.2 Protocol Requests
0 FD fence fd
└───

+┌───
+ DRI3GetSupportedModifiers
+ 1 CARD8 major opcode
+ 1 7 DRI3 opcode
+ 2 3 length
+ 4 Window window
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 2 unused
+ ▶
+ 1 1 Reply
+ 1 0 unused
+ 2 CARD16 sequence number
+ 4 CARD32 reply length
+ 4 CARD32 num_window_modifiers
+ 4 CARD32 num_screen_modifiers
+ 16 unused
+
+ 4 ListOfCARD64 window_modifiers[num_window_modifiers]
+ 4 ListOfCARD64 screen_modifiers[num_screen_modifiers]
+└───
+
+┌───
+ DRI3PixmapFromBuffers
+ 1 CARD8 major opcode
+ 1 8 DRI3 opcode
+ 2 8 length
+ 4 Pixmap pixmap
+ 4 Window window
+ 1 CARD8 num_buffers
+ 3 unused
+ 2 CARD16 width
+ 2 CARD16 height
+ 4 CARD32 stride0
+ 4 CARD32 offset0
+ 4 CARD32 stride1
+ 4 CARD32 offset1
+ 4 CARD32 stride2
+ 4 CARD32 offset2
+ 4 CARD32 stride3
+ 4 CARD32 offset3
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 2 unused
+ 8 CARD64 modifier
+
+ 0 ListOfFD buffers[num_buffers]
+└───
+
+┌───
+ DRI3BuffersFromPixmap
+ 1 CARD8 major opcode
+ 1 9 DRI3 opcode
+ 2 2 length
+ 4 Pixmap pixmap
+ ▶
+ 1 1 Reply
+ 1 CARD8 nfd
+ 2 CARD16 sequence number
+ 4 CARD32 reply length
+ 2 CARD16 width
+ 2 CARD16 height
+ 4 CARD8 unused
+ 8 CARD64 modifier
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 6 unused
+
+ 0 ListOfFD buffer[nfd]
+ 4 ListOfCARD32 strides[nfd]
+ 4 ListOfCARD32 offsets[nfd]
+└───
+
A.3 Protocol Events

The DRI3 extension defines no events.
diff --git a/include/X11/extensions/dri3proto.h b/include/X11/extensions/dri3proto.h
index ceddee8..51b825d 100644
--- a/include/X11/extensions/dri3proto.h
+++ b/include/X11/extensions/dri3proto.h
@@ -25,7 +25,7 @@

#define DRI3_NAME "DRI3"
#define DRI3_MAJOR 1
-#define DRI3_MINOR 0
+#define DRI3_MINOR 2

#define DRI3NumberErrors 0
#define DRI3NumberEvents 0
@@ -37,7 +37,12 @@
#define X_DRI3FenceFromFD 4
#define X_DRI3FDFromFence 5

-#define DRI3NumberRequests 6
+/* v1.2 */
+#define xDRI3GetSupportedModifiers 6
+#define xDRI3PixmapFromBuffers 7
+#define xDRI3BuffersFromPixmap 8
+
+#define DRI3NumberRequests 9

typedef struct {
CARD8 reqType;
@@ -164,4 +169,81 @@ typedef struct {

#define sz_xDRI3FDFromFenceReply 32

+/* v1.2 */
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 window B32;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad10 B16;
+} xDRI3GetSupportedModifiersReq;
+#define sz_xDRI3GetSupportedModifiersReq 12
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ CARD8 pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 numWindowModifiers B32;
+ CARD32 numScreenModifiers B32;
+ CARD32 pad16 B32;
+ CARD32 pad20 B32;
+ CARD32 pad24 B32;
+ CARD32 pad28 B32;
+} xDRI3GetSupportedModifiersReply;
+#define sz_xDRI3GetSupportedModifiersReply 32
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 pixmap B32;
+ CARD32 window B32;
+ CARD8 num_buffers; /* Number of file descriptors passed */
+ CARD8 pad13;
+ CARD16 pad14 B16;
+ CARD16 width B16;
+ CARD16 height B16;
+ CARD32 stride0 B32;
+ CARD32 offset0 B32;
+ CARD32 stride1 B32;
+ CARD32 offset1 B32;
+ CARD32 stride2 B32;
+ CARD32 offset2 B32;
+ CARD32 stride3 B32;
+ CARD32 offset3 B32;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad54 B16;
+ CARD64 modifier;
+} xDRI3PixmapFromBuffersReq;
+#define sz_xDRI3PixmapFromBuffersReq 64
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 pixmap B32;
+} xDRI3BuffersFromPixmapReq;
+#define sz_xDRI3BuffersFromPixmapReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ CARD8 nfd; /* Number of file descriptors returned */
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD16 width B16;
+ CARD16 height B16;
+ CARD32 pad12 B32;
+ CARD64 modifier;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad26 B16;
+ CARD32 pad28 B32;
+} xDRI3BuffersFromPixmapReply;
+#define sz_xDRI3BuffersFromPixmapReply 32
+
#endif
diff --git a/meson.build b/meson.build
index 9511029..cb92280 100644
--- a/meson.build
+++ b/meson.build
@@ -30,7 +30,7 @@ pcs = [
['damageproto', '1.2.1'],
['dmxproto', '2.3.1'],
['dri2proto', '2.8'],
- ['dri3proto', '1.0'],
+ ['dri3proto', '1.2'],
['fixesproto', '5.0'],
['fontsproto', '2.1.3'],
['glproto', '1.4.17'],
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http
Daniel Stone
2018-02-28 01:16:28 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

If the Complete event has this mode, the client is not using
the more optimal format/modifier for the buffer allocation. The
client must explicitely inform the server that it understands
this mode by adding the PresentOptionSuboptimal flag when calling
PresentPixmap.

Its main usage as of now is to allow clients to re-fetch DRI3
format modifiers as some modifiers might allow direct scanout.

Bump presentproto version to 1.2.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
include/X11/extensions/presenttokens.h | 13 +++++++-----
meson.build | 2 +-
presentproto.pc.in | 2 +-
presentproto.txt | 36 ++++++++++++++++++++++++----------
4 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/include/X11/extensions/presenttokens.h b/include/X11/extensions/presenttokens.h
index acb7576..9211207 100644
--- a/include/X11/extensions/presenttokens.h
+++ b/include/X11/extensions/presenttokens.h
@@ -25,7 +25,7 @@

#define PRESENT_NAME "Present"
#define PRESENT_MAJOR 1
-#define PRESENT_MINOR 0
+#define PRESENT_MINOR 2

#define PresentNumberErrors 0
#define PresentNumberEvents 0
@@ -44,10 +44,12 @@
#define PresentOptionAsync (1 << 0)
#define PresentOptionCopy (1 << 1)
#define PresentOptionUST (1 << 2)
+#define PresentOptionSuboptimal (1 << 3)

#define PresentAllOptions (PresentOptionAsync | \
PresentOptionCopy | \
- PresentOptionUST)
+ PresentOptionUST | \
+ PresentOptionSuboptimal)

/* Present capabilities */

@@ -94,8 +96,9 @@

/* Complete Modes */

-#define PresentCompleteModeCopy 0
-#define PresentCompleteModeFlip 1
-#define PresentCompleteModeSkip 2
+#define PresentCompleteModeCopy 0
+#define PresentCompleteModeFlip 1
+#define PresentCompleteModeSkip 2
+#define PresentCompleteModeSuboptimalCopy 3

#endif
diff --git a/meson.build b/meson.build
index cb92280..6fb1541 100644
--- a/meson.build
+++ b/meson.build
@@ -36,7 +36,7 @@ pcs = [
['glproto', '1.4.17'],
['inputproto', '2.3.2'],
['kbproto', '1.0.7'],
- ['presentproto', '1.1'],
+ ['presentproto', '1.2'],
['randrproto', '1.6.0'],
['recordproto', '1.14.2'],
['renderproto', '0.11.1'],
diff --git a/presentproto.pc.in b/presentproto.pc.in
index 9a32fa8..6ec4b7d 100644
--- a/presentproto.pc.in
+++ b/presentproto.pc.in
@@ -5,5 +5,5 @@ includedir=@includedir@

Name: PresentProto
Description: Present extension headers
-Version: 1.1
+Version: 1.2
Cflags: -I${includedir}
diff --git a/presentproto.txt b/presentproto.txt
index fdaf658..6ba55ae 100644
--- a/presentproto.txt
+++ b/presentproto.txt
@@ -1,6 +1,6 @@
The Present Extension
- Version 1.0
- 2013-6-6
+ Version 1.2
+ 2018-02-26

Keith Packard
***@keithp.com
@@ -24,6 +24,7 @@ change and is provided only as an aid to further Present development.
Eric Anholt <***@anholt.net>
Owen Taylor <***@redhat.com>
James Jones <***@nvidia.com>
+Louis-Francis Ratté-Boulianne <***@collabora.com>

❄ ❄ ❄ ❄ ❄ ❄ ❄

@@ -55,7 +56,8 @@ PRESENTEVENTMASK { PresentConfigureNotifyMask,

PRESENTOPTION { PresentOptionAsync,
PresentOptionCopy,
- PresentOptionUST }
+ PresentOptionUST,
+ PresentOptionSuboptimal }

PRESENTCAPABILITY { PresentCapabilityAsync,
PresentCapabilityFence,
@@ -66,7 +68,8 @@ PRESENTCOMPLETEKIND { PresentCompleteKindPixmap,

PRESENTCOMPLETEMODE { PresentCompleteModeCopy,
PresentCompleteModeFlip,
- PresentCompleteModeSkip }
+ PresentCompleteModeSkip,
+ PresentCompleteModeSuboptimalCopy }

The Present extension also uses the Sync extension Fence data type to
provide synchronization for pixmaps.
@@ -226,6 +229,10 @@ The name of this extension is "Present"
server will take the target UST time and convert it to a
suitable target MSC value.

+ If 'options' contains PresentOptionSuboptimal, then the
+ PresentCompleteNotify event can have mode
+ PresentCompleteModeSuboptimalCopy as the client supports it.
+
After the presentation occurs, a PresentCompleteNotify event
with kind PresentCompleteKindPixmap will be generated, both to
'window' as well as all members of 'notifies'.
@@ -408,12 +415,16 @@ The name of this extension is "Present"
'mode' is PresentCompleteModeCopy when the source pixmap
contents are taken from the pixmap and the pixmap is idle
immediately after the presentation completes. 'mode' is
- PresentCompleteModeFlip when the pixmap remains in-use even
- after the presentation completes. It will become idle no later
- than when the next PresentPixmap operation targeting the same
- window by any client completes. If the presentation operation
- was skipped because some later operation made it irrelevant,
- then 'mode' will be PresentCompleteModeSkip.
+ PresentCompleteModeSuboptimalCopy when the source pixmap
+ contents are copied but it would be possible to flip the
+ pixmap if the buffer format/modifier was different (options
+ given to PresentPixmap must contain PresentOptionSuboptimal).
+ 'mode' is PresentCompleteModeFlip when the pixmap remains in-use
+ even after the presentation completes. It will become idle no
+ later than when the next PresentPixmap operation targeting the
+ same window by any client completes. If the presentation
+ operation was skipped because some later operation made it
+ irrelevant, then 'mode' will be PresentCompleteModeSkip.

'serial' is the value provided in the generating PresentPixmap
request.
@@ -505,6 +516,9 @@ The name of this extension is "Present"

1.0: First published version

+ 1.2: Added PresentCompleteModeSuboptimalCopy flag and
+ PresentOptionSuboptimal option
+
❄ ❄ ❄ ❄ ❄ ❄ ❄


@@ -569,6 +583,7 @@ A.1 Common Types
1 PresentOptionAsync
2 PresentOptionCopy;
4 PresentOptionUST
+ 8 PresentOptionSuboptimal
└───

┌───
@@ -589,6 +604,7 @@ A.1 Common Types
0 PresentCompleteModeCopy
1 PresentCompleteModeFlip
2 PresentCompleteModeSkip
+ 3 PresentCompleteModeSuboptimalCopy
└───

┌───
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/m
Daniel Stone
2018-02-28 01:16:30 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Add 'check_flip2' hook for driver to let know the core
about why flipping is not possible ('reason').
If it is because of unsupported buffer format/modifier,
a PresentCompleteNotify event is sent to the client with
the PresentCompleteModeSuboptimalCopy mode.

v2: Check for PresentOptionSuboptimal and check driver version
before using 'check_flip2'.

v3: Only require one of 'check_flip' or 'check_flip2' to be
implemented by the driver.
Refactor reasons list to enum

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 2 +-
include/protocol-versions.h | 2 +-
present/meson.build | 2 +-
present/present.c | 50 ++++++++++++++++++++++++++++++---------------
present/present.h | 12 ++++++++++-
present/present_priv.h | 2 ++
6 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/configure.ac b/configure.ac
index 47469d864..cef9503d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -753,7 +753,7 @@ DAMAGEPROTO="damageproto >= 1.1"
XCMISCPROTO="xcmiscproto >= 1.2.0"
BIGREQSPROTO="bigreqsproto >= 1.1.0"
XTRANS="xtrans >= 1.3.5"
-PRESENTPROTO="presentproto >= 1.0"
+PRESENTPROTO="presentproto >= 1.1"

dnl List of libraries that require a specific version
LIBAPPLEWM="applewm >= 1.4"
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 938b9caa4..39cd2e909 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -69,7 +69,7 @@

/* Present */
#define SERVER_PRESENT_MAJOR_VERSION 1
-#define SERVER_PRESENT_MINOR_VERSION 0
+#define SERVER_PRESENT_MINOR_VERSION 1

/* RandR */
#define SERVER_RANDR_MAJOR_VERSION 1
diff --git a/present/meson.build b/present/meson.build
index a4296ca7a..cf725302a 100644
--- a/present/meson.build
+++ b/present/meson.build
@@ -13,7 +13,7 @@ libxserver_present = static_library('libxserver_present',
include_directories: inc,
dependencies: [
common_dep,
- dependency('presentproto', version: '>= 1.0')
+ dependency('presentproto', version: '>= 1.1')
],
c_args: '-DHAVE_XORG_CONFIG_H'
)
diff --git a/present/present.c b/present/present.c
index 176e89c0b..42e5fb4fc 100644
--- a/present/present.c
+++ b/present/present.c
@@ -118,19 +118,23 @@ present_flip_pending_pixmap(ScreenPtr screen)
}

static Bool
-present_check_flip(RRCrtcPtr crtc,
- WindowPtr window,
- PixmapPtr pixmap,
- Bool sync_flip,
- RegionPtr valid,
- int16_t x_off,
- int16_t y_off)
+present_check_flip(RRCrtcPtr crtc,
+ WindowPtr window,
+ PixmapPtr pixmap,
+ Bool sync_flip,
+ RegionPtr valid,
+ int16_t x_off,
+ int16_t y_off,
+ PresentFlipReason *reason)
{
ScreenPtr screen = window->drawable.pScreen;
PixmapPtr window_pixmap;
WindowPtr root = screen->root;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);

+ if (reason)
+ *reason = PRESENT_FLIP_REASON_UNKNOWN;
+
if (!screen_priv)
return FALSE;

@@ -177,7 +181,12 @@ present_check_flip(RRCrtcPtr crtc,
}

/* Ask the driver for permission */
- if (screen_priv->info->check_flip) {
+ if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
+ if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
+ DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
+ return FALSE;
+ }
+ } else if (screen_priv->info->check_flip) {
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
return FALSE;
@@ -564,6 +573,7 @@ present_check_flip_window (WindowPtr window)
present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr flip_pending = screen_priv->flip_pending;
present_vblank_ptr vblank;
+ PresentFlipReason reason;

/* If this window hasn't ever been used with Present, it can't be
* flipping
@@ -580,7 +590,7 @@ present_check_flip_window (WindowPtr window)
*/
if (flip_pending->window == window) {
if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
- flip_pending->sync_flip, NULL, 0, 0))
+ flip_pending->sync_flip, NULL, 0, 0, NULL))
present_set_abort_flip(screen);
}
} else {
@@ -588,15 +598,16 @@ present_check_flip_window (WindowPtr window)
* Check current flip
*/
if (window == screen_priv->flip_window) {
- if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0))
+ if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
present_unflip(screen);
}
}

/* Now check any queued vblanks */
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
- if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) {
+ if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
vblank->flip = FALSE;
+ vblank->reason = reason;
if (vblank->sync_flip)
vblank->requeue = TRUE;
}
@@ -756,10 +767,14 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
/* Compute correct CompleteMode
*/
if (vblank->kind == PresentCompleteKindPixmap) {
- if (vblank->pixmap && vblank->window)
- mode = PresentCompleteModeCopy;
- else
+ if (vblank->pixmap && vblank->window) {
+ if (vblank->has_suboptimal && vblank->reason == PRESENT_FLIP_REASON_BUFFER_FORMAT)
+ mode = PresentCompleteModeSuboptimalCopy;
+ else
+ mode = PresentCompleteModeCopy;
+ } else {
mode = PresentCompleteModeSkip;
+ }
}
else
mode = PresentCompleteModeCopy;
@@ -795,6 +810,7 @@ present_pixmap(WindowPtr window,
ScreenPtr screen = window->drawable.pScreen;
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+ PresentFlipReason reason = PRESENT_FLIP_REASON_UNKNOWN;

if (!window_priv)
return BadAlloc;
@@ -912,22 +928,24 @@ present_pixmap(WindowPtr window,
vblank->msc_offset = window_priv->msc_offset;
vblank->notifies = notifies;
vblank->num_notifies = num_notifies;
+ vblank->has_suboptimal = (options & PresentOptionSuboptimal);

if (pixmap != NULL &&
!(options & PresentOptionCopy) &&
screen_priv->info) {
if (msc_is_after(target_msc, crtc_msc) &&
- present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off))
+ present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
{
vblank->flip = TRUE;
vblank->sync_flip = TRUE;
target_msc--;
} else if ((screen_priv->info->capabilities & PresentCapabilityAsync) &&
- present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off))
+ present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
{
vblank->flip = TRUE;
}
}
+ vblank->reason = reason;

if (wait_fence) {
vblank->wait_fence = present_fence_create(wait_fence);
diff --git a/present/present.h b/present/present.h
index aab2e168a..6542dc385 100644
--- a/present/present.h
+++ b/present/present.h
@@ -27,6 +27,11 @@
#include "randrstr.h"
#include "presentext.h"

+typedef enum {
+ PRESENT_FLIP_REASON_UNKNOWN,
+ PRESENT_FLIP_REASON_BUFFER_FORMAT
+} PresentFlipReason;
+
typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;

/* Return the current CRTC for 'window'.
@@ -59,6 +64,10 @@ typedef void (*present_flush_ptr) (WindowPtr window);
*/
typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);

+/* Same as 'check_flip' but it can return a 'reason' why the flip would fail.
+ */
+typedef Bool (*present_check_flip2_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip, PresentFlipReason *reason);
+
/* Flip pixmap, return false if it didn't happen.
*
* 'crtc' is to be used for any necessary synchronization.
@@ -83,7 +92,7 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
typedef void (*present_unflip_ptr) (ScreenPtr screen,
uint64_t event_id);

-#define PRESENT_SCREEN_INFO_VERSION 0
+#define PRESENT_SCREEN_INFO_VERSION 1

typedef struct present_screen_info {
uint32_t version;
@@ -97,6 +106,7 @@ typedef struct present_screen_info {
present_check_flip_ptr check_flip;
present_flip_ptr flip;
present_unflip_ptr unflip;
+ present_check_flip2_ptr check_flip2;

} present_screen_info_rec, *present_screen_info_ptr;

diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bdea9..6980ddd11 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -75,6 +75,8 @@ struct present_vblank {
Bool flip_ready; /* wants to flip, but waiting for previous flip or unflip */
Bool sync_flip; /* do flip synchronous to vblank */
Bool abort_flip; /* aborting this flip */
+ PresentFlipReason reason; /* reason for which flip is not possible */
+ Bool has_suboptimal; /* whether client can support SuboptimalCopy mode */
};

typedef struct present_screen_priv {
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info:
Daniel Stone
2018-02-28 01:16:31 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

In order to flip between compressed and uncompressed buffers -
something drmModePageFlip explicitly bans us from doing - we need
to port use the atomic modesetting API. It's only 'fake' atomic
though given we still commit for each CRTC separately and
CRTC and connector properties are not set with the atomic API.

The helper functions to retrieve DRM properties have been borrowed
from Weston.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 3 +
hw/xfree86/drivers/modesetting/driver.c | 6 +
hw/xfree86/drivers/modesetting/driver.h | 1 +
hw/xfree86/drivers/modesetting/drmmode_display.c | 374 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 36 +++
hw/xfree86/drivers/modesetting/pageflip.c | 22 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
8 files changed, 443 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index cef9503d7..46662867f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2106,6 +2106,9 @@ if test "x$GLAMOR" = xyes; then
fi
fi

+ PKG_CHECK_EXISTS(libdrm >= 2.4.62,
+ [AC_DEFINE(GLAMOR_HAS_DRM_ATOMIC, 1, [libdrm supports atomic API])],
+ [])
PKG_CHECK_EXISTS(libdrm >= 2.4.74,
[AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
[])
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index ec2aa9a27..88a42257c 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1018,6 +1018,12 @@ PreInit(ScrnInfoPtr pScrn, int flags)
}
#endif

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ ret |= drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+ ms->atomic_modeset = (ret == 0);
+#endif
+
if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
goto fail;
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
index fe835918b..ed32239db 100644
--- a/hw/xfree86/drivers/modesetting/driver.h
+++ b/hw/xfree86/drivers/modesetting/driver.h
@@ -105,6 +105,7 @@ typedef struct _modesettingRec {
* Page flipping stuff.
* @{
*/
+ Bool atomic_modeset;
/** @} */

DamagePtr damage;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index bfc8c50db..8674c2c16 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -75,6 +75,233 @@ drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name
return ret;
}

+static uint64_t
+drmmode_prop_get_value(drmmode_prop_info_ptr info,
+ drmModeObjectPropertiesPtr props,
+ uint64_t def)
+{
+ unsigned int i;
+
+ if (info->prop_id == 0)
+ return def;
+
+ for (i = 0; i < props->count_props; i++) {
+ unsigned int j;
+
+ if (props->props[i] != info->prop_id)
+ continue;
+
+ /* Simple (non-enum) types can return the value directly */
+ if (info->num_enum_values == 0)
+ return props->prop_values[i];
+
+ /* Map from raw value to enum value */
+ for (j = 0; j < info->num_enum_values; j++) {
+ if (!info->enum_values[j].valid)
+ continue;
+ if (info->enum_values[j].value != props->prop_values[i])
+ continue;
+
+ return j;
+ }
+ }
+
+ return def;
+}
+
+static uint32_t
+drmmode_prop_info_update(drmmode_ptr drmmode,
+ drmmode_prop_info_ptr info,
+ unsigned int num_infos,
+ drmModeObjectProperties *props)
+{
+ drmModePropertyRes *prop;
+ uint32_t valid_mask = 0;
+ unsigned i, j;
+
+ assert(num_infos <= 32 && "update return type");
+
+ for (i = 0; i < props->count_props; i++) {
+ Bool props_incomplete = FALSE;
+ unsigned int k;
+
+ for (j = 0; j < num_infos; j++) {
+ if (info[j].prop_id == props->props[i])
+ break;
+ if (!info[j].prop_id)
+ props_incomplete = TRUE;
+ }
+
+ /* We've already discovered this property. */
+ if (j != num_infos)
+ continue;
+
+ /* We haven't found this property ID, but as we've already
+ * found all known properties, we don't need to look any
+ * further. */
+ if (!props_incomplete)
+ break;
+
+ prop = drmModeGetProperty(drmmode->fd, props->props[i]);
+ if (!prop)
+ continue;
+
+ for (j = 0; j < num_infos; j++) {
+ if (!strcmp(prop->name, info[j].name))
+ break;
+ }
+
+ /* We don't know/care about this property. */
+ if (j == num_infos) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ info[j].prop_id = props->props[i];
+ valid_mask |= 1U << j;
+
+ if (info[j].num_enum_values == 0) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
+ "expected property %s to be an enum,"
+ " but it is not; ignoring\n", prop->name);
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ for (k = 0; k < info[j].num_enum_values; k++) {
+ int l;
+
+ if (info[j].enum_values[k].valid)
+ continue;
+
+ for (l = 0; l < prop->count_enums; l++) {
+ if (!strcmp(prop->enums[l].name,
+ info[j].enum_values[k].name))
+ break;
+ }
+
+ if (l == prop->count_enums)
+ continue;
+
+ info[j].enum_values[k].valid = TRUE;
+ info[j].enum_values[k].value = prop->enums[l].value;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+
+ return valid_mask;
+}
+
+static Bool
+drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
+ const drmmode_prop_info_rec *src,
+ unsigned int num_props,
+ Bool copy_prop_id)
+{
+ unsigned int i;
+
+ memcpy(dst, src, num_props * sizeof(*dst));
+
+ for (i = 0; i < num_props; i++) {
+ unsigned int j;
+
+ if (copy_prop_id)
+ dst[i].prop_id = src[i].prop_id;
+ else
+ dst[i].prop_id = 0;
+
+ if (src[i].num_enum_values == 0)
+ continue;
+
+ dst[i].enum_values =
+ malloc(src[i].num_enum_values *
+ sizeof(*dst[i].enum_values));
+ if (!dst[i].enum_values)
+ goto err;
+
+ memcpy(dst[i].enum_values, src[i].enum_values,
+ src[i].num_enum_values * sizeof(*dst[i].enum_values));
+
+ for (j = 0; j < dst[i].num_enum_values; j++)
+ dst[i].enum_values[j].valid = FALSE;
+ }
+
+ return TRUE;
+
+err:
+ while (i--)
+ free(dst[i].enum_values);
+ free(dst);
+ return FALSE;
+}
+
+static void
+drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
+{
+ int i;
+
+ for (i = 0; i < num_props; i++)
+ free(info[i].enum_values);
+}
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static int
+plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+ enum drmmode_plane_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+#endif
+
+int
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+ int x, int y, uint32_t flags, void *data)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ int ret = 0;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (ms->atomic_modeset) {
+ drmModeAtomicReq *req = drmModeAtomicAlloc();
+
+ if (!req)
+ return 1;
+
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
+ fb_id);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
+ drmmode_crtc->mode_crtc->crtc_id);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+
+ if (ret == 0)
+ ret = drmModeAtomicCommit(ms->fd, req, flags, data);
+
+ drmModeAtomicFree(req);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+
int
drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
{
@@ -1076,6 +1303,14 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
}
}

+static void
+drmmode_crtc_destroy(xf86CrtcPtr crtc)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+}
+
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.dpms = drmmode_crtc_dpms,
.set_mode_major = drmmode_set_mode_major,
@@ -1086,7 +1321,7 @@ static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.load_cursor_argb_check = drmmode_load_cursor_argb_check,

.gamma_set = drmmode_crtc_gamma_set,
- .destroy = NULL, /* XXX */
+ .destroy = drmmode_crtc_destroy,
.set_scanout_pixmap = drmmode_set_scanout_pixmap,
.shadow_allocate = drmmode_shadow_allocate,
.shadow_create = drmmode_shadow_create,
@@ -1104,6 +1339,136 @@ drmmode_crtc_vblank_pipe(int crtc_id)
return 0;
}

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static Bool
+is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c;
+
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr iter = xf86_config->crtc[c];
+ drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
+ if (drmmode_crtc->plane_id == plane_id)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ drmModePlaneRes *kplane_res;
+ drmModePlane *kplane;
+ drmModeObjectProperties *props;
+ uint32_t i, type;
+ int current_crtc, best_plane = 0;
+
+ static drmmode_prop_enum_info_rec plane_type_enums[] = {
+ [DRMMODE_PLANE_TYPE_PRIMARY] = {
+ .name = "Primary",
+ },
+ [DRMMODE_PLANE_TYPE_OVERLAY] = {
+ .name = "Overlay",
+ },
+ [DRMMODE_PLANE_TYPE_CURSOR] = {
+ .name = "Cursor",
+ },
+ };
+ static const drmmode_prop_info_rec plane_props[] = {
+ [DRMMODE_PLANE_TYPE] = {
+ .name = "type",
+ .enum_values = plane_type_enums,
+ .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
+ },
+ [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
+ [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
+ [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ };
+ drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
+
+ if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "failed to copy plane property info\n");
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ return;
+ }
+
+ kplane_res = drmModeGetPlaneResources(drmmode->fd);
+ if (!kplane_res) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "failed to get plane resources: %s\n", strerror(errno));
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ return;
+ }
+
+ for (i = 0; i < kplane_res->count_planes; i++) {
+ int plane_id;
+
+ kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
+ if (!kplane)
+ continue;
+
+ if (!(kplane->possible_crtcs & (1 << num)) ||
+ is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
+ drmModeFreePlane(kplane);
+ continue;
+ }
+
+ plane_id = kplane->plane_id;
+ drmModeFreePlane(kplane);
+
+ props = drmModeObjectGetProperties(drmmode->fd, plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (!props) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "couldn't get plane properties\n");
+ continue;
+ }
+
+ drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
+
+ /* Only primary planes are important for atomic page-flipping */
+ type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
+ props, DRMMODE_PLANE_TYPE__COUNT);
+ if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+ drmModeFreeObjectProperties(props);
+ continue;
+ }
+
+ /* Check if plane is already on this CRTC */
+ current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
+ props, 0);
+ if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
+ if (best_plane)
+ drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ best_plane = plane_id;
+ drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+ DRMMODE_PLANE__COUNT, 1);
+ drmModeFreeObjectProperties(props);
+ break;
+ }
+
+ if (!best_plane) {
+ best_plane = plane_id;
+ drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+ DRMMODE_PLANE__COUNT, 1);
+ }
+
+ drmModeFreeObjectProperties(props);
+ }
+
+ drmmode_crtc->plane_id = best_plane;
+
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ drmModeFreePlaneResources(kplane_res);
+}
+#endif
+
static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
{
@@ -1122,6 +1487,10 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
crtc->driver_private = drmmode_crtc;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_crtc_create_planes(crtc, num);
+#endif
+
/* Hide any cursors which may be active from previous users */
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);

@@ -1477,7 +1846,8 @@ drmmode_property_ignore(drmModePropertyPtr prop)
if (prop->flags & DRM_MODE_PROP_BLOB)
return TRUE;
/* ignore standard property */
- if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
+ if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
+ !strcmp(prop->name, "CRTC_ID"))
return TRUE;

return FALSE;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 267040918..1f24c3a5b 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -36,6 +36,22 @@

struct gbm_device;

+enum drmmode_plane_property {
+ DRMMODE_PLANE_TYPE = 0,
+ DRMMODE_PLANE_FB_ID,
+ DRMMODE_PLANE_CRTC_ID,
+ DRMMODE_PLANE_SRC_X,
+ DRMMODE_PLANE_SRC_Y,
+ DRMMODE_PLANE__COUNT
+};
+
+enum drmmode_plane_type {
+ DRMMODE_PLANE_TYPE_PRIMARY = 0,
+ DRMMODE_PLANE_TYPE_CURSOR,
+ DRMMODE_PLANE_TYPE_OVERLAY,
+ DRMMODE_PLANE_TYPE__COUNT
+};
+
typedef struct {
struct dumb_bo *dumb;
#ifdef GLAMOR_HAS_GBM
@@ -88,6 +104,19 @@ typedef struct {
Bool present_enable;
} drmmode_rec, *drmmode_ptr;

+typedef struct {
+ const char *name;
+ Bool valid;
+ uint64_t value;
+} drmmode_prop_enum_info_rec, *drmmode_prop_enum_info_ptr;
+
+typedef struct {
+ const char *name;
+ uint32_t prop_id;
+ unsigned int num_enum_values;
+ drmmode_prop_enum_info_rec *enum_values;
+} drmmode_prop_info_rec, *drmmode_prop_info_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -97,6 +126,9 @@ typedef struct {
Bool cursor_up;
uint16_t lut_r[256], lut_g[256], lut_b[256];

+ drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
+ uint32_t plane_id;
+
drmmode_bo rotate_bo;
unsigned rotate_fb_id;

@@ -205,6 +237,10 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
int *depth, int *bpp);

void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
+
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+ int x, int y, uint32_t flags, void *data);
+
#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
#define DRM_CAP_DUMB_PREFERRED_DEPTH 3
#endif
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index d5fd0625b..dd296cd12 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -159,6 +159,25 @@ ms_pageflip_abort(void *data)
ms_pageflip_free(flip);
}

+static Bool
+do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
+ uint32_t flags, uint32_t seq)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (ms->atomic_modeset) {
+ flags |= DRM_MODE_ATOMIC_NONBLOCK;
+ return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+ (void *) (uintptr_t) seq);
+ }
+#endif
+
+ return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
+ ms->drmmode.fb_id, flags,
+ (void *) (uintptr_t) seq);
+}
+
static Bool
queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
struct ms_flipdata *flipdata,
@@ -193,8 +212,7 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
/* take a reference on flipdata for use in flip */
flipdata->flip_count++;

- while (drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
- ms->drmmode.fb_id, flags, (void *) (uintptr_t) seq)) {
+ while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
err = errno;
/* We may have failed because the event queue was full. Flush it
* and retry. If there was nothing to flush, then we failed for
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index f12df74da..9f8dc913f 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -491,6 +491,9 @@
/* Build glamor use new drmGetDeviceNameFromFD2 */
#undef GLAMOR_HAS_DRM_NAME_FROM_FD_2

+/* Glamor should use atomic DRM API */
+#undef GLAMOR_HAS_DRM_ATOMIC
+
/* byte order */
#undef X_BYTE_ORDER

diff --git a/include/meson.build b/include/meson.build
index 83778c69b..dceca2b7d 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -74,6 +74,8 @@ conf_data.set_quoted('SHMDIR', '/tmp')

conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found())
conf_data.set('WITH_LIBDRM', libdrm_dep.found())
+conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
+ libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
conf_data.set('GLXEXT', build_glx)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https:
Daniel Stone
2018-02-28 01:16:29 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Initial implementation for DRI3 v1.1. Only the DRI3 implementation
is there, backends need to implement the proper hooks.

Version is still set to 1.0 so clients shouldn't use the new
requests yet.

v2: Use depth/bpp instead of DRM formats in requests

v3: Remove DMA fence requests from v1.1
Add screen/drawable modifier sets

v4: Free array returned by 'get_drawable_modifiers()'

v5: Fix FD leak

Signed-off-by: Daniel Stone <***@collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
---
configure.ac | 2 +-
dri3/dri3.c | 19 +++
dri3/dri3.h | 44 ++++++-
dri3/dri3_priv.h | 27 +++-
dri3/dri3_request.c | 294 ++++++++++++++++++++++++++++++++++++++++--
dri3/dri3_screen.c | 196 ++++++++++++++++++++++++++--
hw/xwayland/xwayland-glamor.c | 4 +-
meson.build | 2 +-
8 files changed, 559 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4d7c24fa9..47469d864 100644
--- a/configure.ac
+++ b/configure.ac
@@ -729,7 +729,7 @@ SCRNSAVERPROTO="scrnsaverproto >= 1.1"
RESOURCEPROTO="resourceproto >= 1.2.0"
DRIPROTO="xf86driproto >= 2.1.0"
DRI2PROTO="dri2proto >= 2.8"
-DRI3PROTO="dri3proto >= 1.0"
+DRI3PROTO="dri3proto >= 1.2"
XINERAMAPROTO="xineramaproto"
BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
DGAPROTO="xf86dgaproto >= 2.0.99.1"
diff --git a/dri3/dri3.c b/dri3/dri3.c
index d042b8b7d..8ac0f3ae2 100644
--- a/dri3/dri3.c
+++ b/dri3/dri3.c
@@ -26,6 +26,8 @@

#include "dri3_priv.h"

+#include <drm_fourcc.h>
+
static int dri3_request;
DevPrivateKeyRec dri3_screen_private_key;

@@ -99,3 +101,20 @@ dri3_extension_init(void)
bail:
FatalError("Cannot initialize DRI3 extension");
}
+
+uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp)
+{
+ switch (bpp) {
+ case 16:
+ return DRM_FORMAT_RGB565;
+ case 24:
+ return DRM_FORMAT_XRGB8888;
+ case 30:
+ return DRM_FORMAT_XRGB2101010;
+ case 32:
+ return DRM_FORMAT_ARGB8888;
+ default:
+ return 0;
+ }
+}
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..89ad13ad9 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,7 @@
#include <X11/extensions/dri3proto.h>
#include <randrstr.h>

-#define DRI3_SCREEN_INFO_VERSION 1
+#define DRI3_SCREEN_INFO_VERSION 2

typedef int (*dri3_open_proc)(ScreenPtr screen,
RRProviderPtr provider,
@@ -47,11 +47,43 @@ typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
CARD8 depth,
CARD8 bpp);

+typedef PixmapPtr (*dri3_pixmap_from_fds_proc) (ScreenPtr screen,
+ CARD8 num_fds,
+ int *fds,
+ CARD16 width,
+ CARD16 height,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD8 depth,
+ CARD8 bpp,
+ CARD64 modifier);
+
typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride,
CARD32 *size);

+typedef int (*dri3_fds_from_pixmap_proc) (ScreenPtr screen,
+ PixmapPtr pixmap,
+ int *fds,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD64 *modifier);
+
+typedef int (*dri3_get_formats_proc) (ScreenPtr screen,
+ CARD32 *num_formats,
+ CARD32 **formats);
+
+typedef int (*dri3_get_modifiers_proc) (ScreenPtr screen,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ CARD64 **modifiers);
+
+typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ CARD64 **modifiers);
+
typedef struct dri3_screen_info {
uint32_t version;

@@ -62,6 +94,13 @@ typedef struct dri3_screen_info {
/* Version 1 */
dri3_open_client_proc open_client;

+ /* Version 2 */
+ dri3_pixmap_from_fds_proc pixmap_from_fds;
+ dri3_fds_from_pixmap_proc fds_from_pixmap;
+ dri3_get_formats_proc get_formats;
+ dri3_get_modifiers_proc get_modifiers;
+ dri3_get_drawable_modifiers_proc get_drawable_modifiers;
+
} dri3_screen_info_rec, *dri3_screen_info_ptr;

extern _X_EXPORT Bool
@@ -70,6 +109,9 @@ dri3_screen_init(ScreenPtr screen, dri3_screen_info_ptr info);
extern _X_EXPORT int
dri3_send_open_reply(ClientPtr client, int fd);

+extern _X_EXPORT uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp);
+
#endif

#endif /* _DRI3_H_ */
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..8447680ba 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,21 @@

extern DevPrivateKeyRec dri3_screen_private_key;

+typedef struct dri3_dmabuf_format {
+ uint32_t format;
+ uint32_t num_modifiers;
+ uint64_t *modifiers;
+} dri3_dmabuf_format_rec, *dri3_dmabuf_format_ptr;
+
typedef struct dri3_screen_priv {
CloseScreenProcPtr CloseScreen;
ConfigNotifyProcPtr ConfigNotify;
DestroyWindowProcPtr DestroyWindow;

+ Bool formats_cached;
+ CARD32 num_formats;
+ dri3_dmabuf_format_ptr formats;
+
dri3_screen_info_ptr info;
} dri3_screen_priv_rec, *dri3_screen_priv_ptr;

@@ -69,10 +79,21 @@ int
dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd);

int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp);
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height, CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp, CARD64 modifier);
+
+int
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+ CARD32 *strides, CARD32 *offsets,
+ CARD64 *modifier);

int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+ CARD8 depth, CARD8 bpp,
+ CARD32 *num_drawable_modifiers,
+ CARD64 **drawable_modifiers,
+ CARD32 *num_screen_modifiers,
+ CARD64 **screen_modifiers);

#endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index b28d883a5..7f3f0d08c 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -30,6 +30,7 @@
#include <xace.h>
#include "../Xext/syncsdk.h"
#include <protocol-versions.h>
+#include <drm_fourcc.h>

static int
proc_dri3_query_version(ClientPtr client)
@@ -124,6 +125,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
int fd;
DrawablePtr drawable;
PixmapPtr pixmap;
+ CARD32 stride, offset;
int rc;

SetReqFds(client, 1);
@@ -159,11 +161,14 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
if (fd < 0)
return BadValue;

- rc = dri3_pixmap_from_fd(&pixmap,
- drawable->pScreen, fd,
- stuff->width, stuff->height,
- stuff->stride, stuff->depth,
- stuff->bpp);
+ offset = 0;
+ stride = stuff->stride;
+ rc = dri3_pixmap_from_fds(&pixmap,
+ drawable->pScreen, 1, &fd,
+ stuff->width, stuff->height,
+ &stride, &offset,
+ stuff->depth, stuff->bpp,
+ DRM_FORMAT_MOD_INVALID);
close (fd);
if (rc != Success)
return rc;
@@ -195,7 +200,10 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
.length = 0,
};
int rc;
- int fd;
+ int num_fds;
+ int fds[4];
+ uint32_t strides[4], offsets[4];
+ uint64_t modifier;
PixmapPtr pixmap;

REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -211,9 +219,12 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
rep.depth = pixmap->drawable.depth;
rep.bpp = pixmap->drawable.bitsPerPixel;

- rc = dri3_fd_from_pixmap(&fd, pixmap, &rep.stride, &rep.size);
- if (rc != Success)
- return rc;
+ num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+ if (num_fds != 1)
+ return BadPixmap;
+
+ rep.stride = (CARD16) strides[0];
+ rep.size = rep.stride * rep.height;

if (client->swapped) {
swaps(&rep.sequenceNumber);
@@ -223,8 +234,8 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
swaps(&rep.height);
swaps(&rep.stride);
}
- if (WriteFdToClient(client, fd, TRUE) < 0) {
- close(fd);
+ if (WriteFdToClient(client, fds[0], TRUE) < 0) {
+ close(fds[0]);
return BadAlloc;
}

@@ -299,6 +310,216 @@ proc_dri3_fd_from_fence(ClientPtr client)
return Success;
}

+static int
+proc_dri3_get_supported_modifiers(ClientPtr client)
+{
+ REQUEST(xDRI3GetSupportedModifiersReq);
+ xDRI3GetSupportedModifiersReply rep = {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ };
+ WindowPtr window;
+ ScreenPtr pScreen;
+ CARD64 *window_modifiers = NULL;
+ CARD64 *screen_modifiers = NULL;
+ CARD32 nwindowmodifiers = 0;
+ CARD32 nscreenmodifiers = 0;
+ int status;
+ int i;
+
+ REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+ status = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
+ if (status != Success)
+ return status;
+ pScreen = window->drawable.pScreen;
+
+ dri3_get_supported_modifiers(pScreen, &window->drawable,
+ stuff->depth, stuff->bpp,
+ &nwindowmodifiers, &window_modifiers,
+ &nscreenmodifiers, &screen_modifiers);
+
+ rep.numWindowModifiers = nwindowmodifiers;
+ rep.numScreenModifiers = nscreenmodifiers;
+ rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) +
+ bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swapl(&rep.numWindowModifiers);
+ swapl(&rep.numScreenModifiers);
+ for (i = 0; i < nwindowmodifiers; i++)
+ swapll(&window_modifiers[i]);
+ for (i = 0; i < nscreenmodifiers; i++)
+ swapll(&screen_modifiers[i]);
+ }
+
+ WriteToClient(client, sizeof(rep), &rep);
+ WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers);
+ WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
+
+ free(window_modifiers);
+ free(screen_modifiers);
+
+ return Success;
+}
+
+static int
+proc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+ REQUEST(xDRI3PixmapFromBuffersReq);
+ int fds[4];
+ CARD32 strides[4], offsets[4];
+ ScreenPtr screen;
+ WindowPtr window;
+ PixmapPtr pixmap;
+ int rc;
+ int i;
+
+ SetReqFds(client, stuff->num_buffers);
+ REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+ LEGAL_NEW_RESOURCE(stuff->pixmap, client);
+ rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->window;
+ return rc;
+ }
+ screen = window->drawable.pScreen;
+
+ if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
+ client->errorValue = 0;
+ return BadValue;
+ }
+
+ if (stuff->width > 32767 || stuff->height > 32767)
+ return BadAlloc;
+
+ if (stuff->depth != 1) {
+ DepthPtr depth = screen->allowedDepths;
+ int j;
+ for (j = 0; j < screen->numDepths; j++, depth++)
+ if (depth->depth == stuff->depth)
+ break;
+ if (j == screen->numDepths) {
+ client->errorValue = stuff->depth;
+ return BadValue;
+ }
+ }
+
+ if (!stuff->num_buffers || stuff->num_buffers > 4) {
+ client->errorValue = stuff->num_buffers;
+ return BadValue;
+ }
+
+ for (i = 0; i < stuff->num_buffers; i++) {
+ fds[i] = ReadFdFromClient(client);
+ if (fds[i] < 0) {
+ while (--i >= 0)
+ close(fds[i]);
+ return BadValue;
+ }
+ }
+
+ strides[0] = stuff->stride0;
+ strides[1] = stuff->stride1;
+ strides[2] = stuff->stride2;
+ strides[3] = stuff->stride3;
+ offsets[0] = stuff->offset0;
+ offsets[1] = stuff->offset1;
+ offsets[2] = stuff->offset2;
+ offsets[3] = stuff->offset3;
+
+ rc = dri3_pixmap_from_fds(&pixmap, screen,
+ stuff->num_buffers, fds,
+ stuff->width, stuff->height,
+ strides, offsets,
+ stuff->depth, stuff->bpp,
+ stuff->modifier);
+
+ for (i = 0; i < stuff->num_buffers; i++)
+ close (fds[i]);
+
+ if (rc != Success)
+ return rc;
+
+ pixmap->drawable.id = stuff->pixmap;
+
+ /* security creation/labeling check */
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
+ pixmap, RT_NONE, NULL, DixCreateAccess);
+
+ if (rc != Success) {
+ (*screen->DestroyPixmap) (pixmap);
+ return rc;
+ }
+ if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
+ return BadAlloc;
+
+ return Success;
+}
+
+static int
+proc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+ REQUEST(xDRI3BuffersFromPixmapReq);
+ xDRI3BuffersFromPixmapReply rep = {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ };
+ int rc;
+ int fds[4];
+ int num_fds;
+ uint32_t strides[4], offsets[4];
+ uint64_t modifier;
+ int i;
+ PixmapPtr pixmap;
+
+ REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
+ rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
+ client, DixWriteAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->pixmap;
+ return rc;
+ }
+
+ num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+ if (num_fds == 0)
+ return BadPixmap;
+
+ rep.nfd = num_fds;
+ rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
+ rep.width = pixmap->drawable.width;
+ rep.height = pixmap->drawable.height;
+ rep.modifier = modifier;
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swaps(&rep.width);
+ swaps(&rep.height);
+ swapll(&rep.modifier);
+ for (i = 0; i < num_fds; i++) {
+ swapl(&strides[i]);
+ swapl(&offsets[i]);
+ }
+ }
+
+ for (i = 0; i < num_fds; i++) {
+ if (WriteFdToClient(client, fds[i], TRUE) < 0) {
+ while (i--)
+ close(fds[i]);
+ return BadAlloc;
+ }
+ }
+
+ WriteToClient(client, sizeof(rep), &rep);
+ WriteToClient(client, num_fds * sizeof(CARD32), strides);
+ WriteToClient(client, num_fds * sizeof(CARD32), offsets);
+
+ return Success;
+}
+
int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
proc_dri3_query_version, /* 0 */
proc_dri3_open, /* 1 */
@@ -306,6 +527,9 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
proc_dri3_buffer_from_pixmap, /* 3 */
proc_dri3_fence_from_fd, /* 4 */
proc_dri3_fd_from_fence, /* 5 */
+ proc_dri3_get_supported_modifiers, /* 6 */
+ proc_dri3_pixmap_from_buffers, /* 7 */
+ proc_dri3_buffers_from_pixmap, /* 8 */
};

int
@@ -394,6 +618,51 @@ sproc_dri3_fd_from_fence(ClientPtr client)
return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
}

+static int _X_COLD
+sproc_dri3_get_supported_modifiers(ClientPtr client)
+{
+ REQUEST(xDRI3GetSupportedModifiersReq);
+ REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->window);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+ REQUEST(xDRI3PixmapFromBuffersReq);
+ REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->pixmap);
+ swapl(&stuff->window);
+ swaps(&stuff->width);
+ swaps(&stuff->height);
+ swapl(&stuff->stride0);
+ swapl(&stuff->offset0);
+ swapl(&stuff->stride1);
+ swapl(&stuff->offset1);
+ swapl(&stuff->stride2);
+ swapl(&stuff->offset2);
+ swapl(&stuff->stride3);
+ swapl(&stuff->offset3);
+ swapll(&stuff->modifier);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+ REQUEST(xDRI3BuffersFromPixmapReq);
+ REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->pixmap);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
sproc_dri3_query_version, /* 0 */
sproc_dri3_open, /* 1 */
@@ -401,6 +670,9 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
sproc_dri3_buffer_from_pixmap, /* 3 */
sproc_dri3_fence_from_fd, /* 4 */
sproc_dri3_fd_from_fence, /* 5 */
+ sproc_dri3_get_supported_modifiers, /* 6 */
+ sproc_dri3_pixmap_from_buffers, /* 7 */
+ sproc_dri3_buffers_from_pixmap, /* 8 */
};

int _X_COLD
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..df40f8281 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -29,6 +29,7 @@
#include <misync.h>
#include <misyncshm.h>
#include <randrstr.h>
+#include <drm_fourcc.h>

static inline Bool has_open(dri3_screen_info_ptr info) {
if (info == NULL)
@@ -60,17 +61,30 @@ dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
}

int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp, CARD64 modifier)
{
dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
dri3_screen_info_ptr info = ds->info;
PixmapPtr pixmap;

- if (!info || !info->pixmap_from_fd)
+ if (!info)
return BadImplementation;

- pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+ if (info->version >= 2 && info->pixmap_from_fds != NULL) {
+ pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+ strides, offsets, depth, bpp, modifier);
+ } else if (info->pixmap_from_fd != NULL && num_fds == 1 &&
+ modifier == DRM_FORMAT_MOD_INVALID) {
+ pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
+ strides[0], depth, bpp);
+ } else {
+ return BadImplementation;
+ }
+
if (!pixmap)
return BadAlloc;

@@ -79,20 +93,182 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
}

int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+ CARD32 *strides, CARD32 *offsets,
+ CARD64 *modifier)
{
ScreenPtr screen = pixmap->drawable.pScreen;
dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
dri3_screen_info_ptr info = ds->info;
- int fd;

- if (!info || !info->fd_from_pixmap)
+ if (!info)
+ return 0;
+
+ if (info->version >= 2 && info->fds_from_pixmap != NULL) {
+ return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
+ modifier);
+ } else if (info->fd_from_pixmap != NULL) {
+ CARD16 stride;
+ CARD32 size;
+
+ fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
+ if (fds[0] < 0)
+ return 0;
+
+ strides[0] = stride;
+ offsets[0] = 0;
+ *modifier = DRM_FORMAT_MOD_INVALID;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+cache_formats_and_modifiers(ScreenPtr screen)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ dri3_screen_info_ptr info = ds->info;
+ CARD32 *formats = NULL;
+ CARD64 *modifiers = NULL;
+ int i;
+
+ if (ds->formats_cached)
+ return Success;
+
+ if (!info)
return BadImplementation;

- fd = (*info->fd_from_pixmap)(screen, pixmap, stride, size);
- if (fd < 0)
+ if (!info->get_formats || !info->get_modifiers) {
+ ds->formats = NULL;
+ ds->num_formats = 0;
+ ds->formats_cached = TRUE;
+ return Success;
+ }
+
+ (*info->get_formats) (screen, &ds->num_formats, &formats);
+ ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+ if (!ds->formats)
return BadAlloc;
- *pfd = fd;
+
+ for (i = 0; i < ds->num_formats; i++) {
+ dri3_dmabuf_format_ptr iter = &ds->formats[i];
+
+ iter->format = formats[i];
+ (*info->get_modifiers) (screen, formats[i],
+ &iter->num_modifiers,
+ &modifiers);
+
+ iter->modifiers = malloc(iter->num_modifiers * sizeof(CARD64));
+ if (iter->modifiers == NULL)
+ goto error;
+
+ memcpy(iter->modifiers, modifiers,
+ iter->num_modifiers * sizeof(CARD64));
+ goto done;
+
+error:
+ iter->num_modifiers = 0;
+ free(iter->modifiers);
+done:
+ free(modifiers);
+ }
+ free(formats);
+ ds->formats_cached = TRUE;
+
return Success;
}

+int
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+ CARD8 depth, CARD8 bpp,
+ CARD32 *num_intersect_modifiers,
+ CARD64 **intersect_modifiers,
+ CARD32 *num_screen_modifiers,
+ CARD64 **screen_modifiers)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ dri3_screen_info_ptr info = ds->info;
+ int i, j;
+ int ret;
+ CARD32 num_drawable_mods;
+ CARD64 *drawable_mods;
+ CARD64 *intersect_mods = NULL;
+ CARD64 *screen_mods = NULL;
+ CARD32 format;
+ dri3_dmabuf_format_ptr screen_format = NULL;
+
+ ret = cache_formats_and_modifiers(screen);
+ if (ret != Success)
+ return ret;
+
+ format = drm_format_for_depth(depth, bpp);
+ if (format == 0)
+ return BadValue;
+
+ /* Find screen-global modifiers from cache
+ */
+ for (i = 0; i < ds->num_formats; i++) {
+ if (ds->formats[i].format == format) {
+ screen_format = &ds->formats[i];
+ break;
+ }
+ }
+ if (screen_format == NULL)
+ return BadMatch;
+
+ if (screen_format->num_modifiers == 0) {
+ *num_screen_modifiers = 0;
+ *num_intersect_modifiers = 0;
+ return Success;
+ }
+
+ if (info->get_drawable_modifiers)
+ (*info->get_drawable_modifiers) (drawable, format,
+ &num_drawable_mods,
+ &drawable_mods);
+
+ /* We're allocating slightly more memory than necessary but it reduces
+ * the complexity of finding the intersection set.
+ */
+ screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+ if (!screen_mods)
+ return BadAlloc;
+ if (num_drawable_mods > 0) {
+ intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+ if (!intersect_mods) {
+ free(screen_mods);
+ return BadAlloc;
+ }
+ }
+
+ *num_screen_modifiers = 0;
+ *num_intersect_modifiers = 0;
+ for (i = 0; i < screen_format->num_modifiers; i++) {
+ CARD64 modifier = screen_format->modifiers[i];
+ Bool intersect = FALSE;
+
+ for (j = 0; j < num_drawable_mods; j++) {
+ if (drawable_mods[j] == modifier) {
+ intersect = TRUE;
+ break;
+ }
+ }
+
+ if (intersect) {
+ intersect_mods[*num_intersect_modifiers] = modifier;
+ *num_intersect_modifiers += 1;
+ } else {
+ screen_mods[*num_screen_modifiers] = modifier;
+ *num_screen_modifiers += 1;
+ }
+ }
+
+ assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
+
+ *intersect_modifiers = intersect_mods;
+ *screen_modifiers = screen_mods;
+ free(drawable_mods);
+
+ return Success;
+}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 8ffb40d6f..0933e9411 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -59,7 +59,7 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
}

static uint32_t
-drm_format_for_depth(int depth)
+wl_drm_format_for_depth(int depth)
{
switch (depth) {
case 15:
@@ -170,7 +170,7 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
pixmap->drawable.width,
pixmap->drawable.height,
- drm_format_for_depth(pixmap->drawable.depth),
+ wl_drm_format_for_depth(pixmap->drawable.depth),
0, gbm_bo_get_stride(xwl_pixmap->bo),
0, 0,
0, 0);
diff --git a/meson.build b/meson.build
index 77d3c9def..2477bb931 100644
--- a/meson.build
+++ b/meson.build
@@ -78,7 +78,7 @@ scrnsaverproto_dep = dependency('scrnsaverproto', version: '>= 1.1')
resourceproto_dep = dependency('resourceproto', version: '>= 1.2.0')
xf86driproto_dep = dependency('xf86driproto', version: '>= 2.1.0', required: get_option('dri1') == 'true')
dri2proto_dep = dependency('dri2proto', version: '>= 2.8', required: get_option('dri2') == 'true')
-dri3proto_dep = dependency('dri3proto', version: '>= 1.0', required: get_option('dri3') == 'true')
+dri3proto_dep = dependency('dri3proto', version: '>= 1.2', required: get_option('dri3') == 'true')
xineramaproto_dep = dependency('xineramaproto')
xf86bigfontproto_dep = dependency('xf86bigfontproto', version: '>= 1.2.0')
xf86vidmodeproto_dep = dependency('xf86vidmodeproto', version: '>= 2.2.99.1', required: false)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https:
Daniel Stone
2018-02-28 01:16:34 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Retrieve IN_FORMATS property from the plane. It gives the
allowed formats and modifiers for BO allocation.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 4 +
hw/xfree86/drivers/modesetting/drmmode_display.c | 114 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 9 ++
include/dix-config.h.in | 3 +
include/meson.build | 2 +
5 files changed, 128 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 46662867f..283d8e20c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2112,6 +2112,10 @@ if test "x$GLAMOR" = xyes; then
PKG_CHECK_EXISTS(libdrm >= 2.4.74,
[AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
[])
+
+ PKG_CHECK_EXISTS(libdrm >= 2.4.83,
+ [AC_DEFINE(GLAMOR_HAS_DRM_MODIFIERS, 1, [Have GLAMOR_HAS_DRM_MODIFIERS])],
+ [])
fi
AM_CONDITIONAL([GLAMOR_EGL], [test "x$GBM" = xyes])

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 3e3613a98..7af805da2 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -56,6 +56,23 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
+
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+
+static inline uint32_t *
+formats_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (uint32_t *)(((char *)blob) + blob->formats_offset);
+}
+
+static inline struct drm_format_modifier *
+modifiers_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
+}
+
+#endif
+
static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
{
@@ -1532,15 +1549,76 @@ is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
return FALSE;
}

+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+/**
+ * Populates the formats array, and the modifiers of each format for a drm_plane.
+ */
+static Bool
+populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
+ uint32_t blob_id)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ unsigned i, j;
+ drmModePropertyBlobRes *blob;
+ struct drm_format_modifier_blob *fmt_mod_blob;
+ uint32_t *blob_formats;
+ struct drm_format_modifier *blob_modifiers;
+
+ blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
+ if (!blob)
+ return FALSE;
+
+ fmt_mod_blob = blob->data;
+ blob_formats = formats_ptr(fmt_mod_blob);
+ blob_modifiers = modifiers_ptr(fmt_mod_blob);
+
+ assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
+
+ for (i = 0; i < fmt_mod_blob->count_formats; i++) {
+ uint32_t num_modifiers = 0;
+ uint64_t *modifiers = NULL;
+ uint64_t *tmp;
+
+ for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
+ struct drm_format_modifier *mod = &blob_modifiers[j];
+
+ if ((i < mod->offset) || (i > mod->offset + 63))
+ continue;
+ if (!(mod->formats & (1 << (i - mod->offset))))
+ continue;
+
+ num_modifiers++;
+ tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
+ if (!tmp) {
+ free(modifiers);
+ drmModeFreePropertyBlob(blob);
+ return FALSE;
+ }
+ modifiers = tmp;
+ modifiers[num_modifiers - 1] = mod->modifier;
+ }
+
+ drmmode_crtc->formats[i].format = blob_formats[i];
+ drmmode_crtc->formats[i].modifiers = modifiers;
+ drmmode_crtc->formats[i].num_modifiers = num_modifiers;
+ }
+
+ drmModeFreePropertyBlob(blob);
+
+ return TRUE;
+}
+#endif
+
static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmModePlaneRes *kplane_res;
- drmModePlane *kplane;
+ drmModePlane *kplane, *best_kplane = NULL;
drmModeObjectProperties *props;
- uint32_t i, type;
+ uint32_t i, type, blob_id;
int current_crtc, best_plane = 0;

static drmmode_prop_enum_info_rec plane_type_enums[] = {
@@ -1562,6 +1640,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
},
[DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
[DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
[DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
[DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
[DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
@@ -1602,13 +1681,13 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
}

plane_id = kplane->plane_id;
- drmModeFreePlane(kplane);

props = drmModeObjectGetProperties(drmmode->fd, plane_id,
DRM_MODE_OBJECT_PLANE);
if (!props) {
xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
"couldn't get plane properties\n");
+ drmModeFreePlane(kplane);
continue;
}

@@ -1618,6 +1697,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
props, DRMMODE_PLANE_TYPE__COUNT);
if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+ drmModeFreePlane(kplane);
drmModeFreeObjectProperties(props);
continue;
}
@@ -1626,9 +1706,14 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
props, 0);
if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
- if (best_plane)
+ if (best_plane) {
+ drmModeFreePlane(best_kplane);
drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ }
best_plane = plane_id;
+ best_kplane = kplane;
+ blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+ props, 0);
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
DRMMODE_PLANE__COUNT, 1);
drmModeFreeObjectProperties(props);
@@ -1637,14 +1722,35 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)

if (!best_plane) {
best_plane = plane_id;
+ best_kplane = kplane;
+ blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+ props, 0);
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
DRMMODE_PLANE__COUNT, 1);
+ } else {
+ drmModeFreePlane(kplane);
}

drmModeFreeObjectProperties(props);
}

drmmode_crtc->plane_id = best_plane;
+ if (best_kplane) {
+ drmmode_crtc->num_formats = best_kplane->count_formats;
+ drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
+ best_kplane->count_formats);
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+ if (blob_id) {
+ populate_format_modifiers(crtc, best_kplane, blob_id);
+ }
+ else
+#endif
+ {
+ for (i = 0; i < best_kplane->count_formats; i++)
+ drmmode_crtc->formats[i].format = best_kplane->formats[i];
+ }
+ drmModeFreePlane(best_kplane);
+ }

drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
drmModeFreePlaneResources(kplane_res);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index e5f3542c5..75e4b8499 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -39,6 +39,7 @@ struct gbm_device;
enum drmmode_plane_property {
DRMMODE_PLANE_TYPE = 0,
DRMMODE_PLANE_FB_ID,
+ DRMMODE_PLANE_IN_FORMATS,
DRMMODE_PLANE_CRTC_ID,
DRMMODE_PLANE_SRC_X,
DRMMODE_PLANE_SRC_Y,
@@ -142,6 +143,12 @@ typedef struct {
struct xorg_list entry;
} drmmode_mode_rec, *drmmode_mode_ptr;

+typedef struct {
+ uint32_t format;
+ uint32_t num_modifiers;
+ uint64_t *modifiers;
+} drmmode_format_rec, *drmmode_format_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -155,6 +162,8 @@ typedef struct {
drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
uint32_t plane_id;
drmmode_mode_ptr current_mode;
+ uint32_t num_formats;
+ drmmode_format_rec *formats;

drmmode_bo rotate_bo;
unsigned rotate_fb_id;
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 9f8dc913f..65d655ca8 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -494,6 +494,9 @@
/* Glamor should use atomic DRM API */
#undef GLAMOR_HAS_DRM_ATOMIC

+/* Glamor can retrieve supported DRM formats/modifiers */
+#undef GLAMOR_HAS_DRM_MODIFIERS
+
/* byte order */
#undef X_BYTE_ORDER

diff --git a/include/meson.build b/include/meson.build
index dceca2b7d..bbb7d14e8 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -78,6 +78,8 @@ conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
+conf_data.set('GLAMOR_HAS_DRM_MODIFIERS',
+ libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.83'))
conf_data.set('GLXEXT', build_glx)
conf_data.set('GLAMOR', build_glamor)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists
Daniel Stone
2018-02-28 01:16:35 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Use most optimal buffer format (e.g. tiled/compressed) available
for scanout.

v2: Don't use multi-plane modifier to create scanout buffer

v3: Add flag to retrieve modifiers set from enabled CRTCs only

v4: Fix uses when GBM/EGL driver doesn't support modifiers

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 90 +++++++++++++++++++++++-
1 file changed, 87 insertions(+), 3 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7af805da2..6fa22da56 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -73,6 +73,68 @@ modifiers_ptr(struct drm_format_modifier_blob *blob)

#endif

+#ifdef GBM_BO_WITH_MODIFIERS
+static uint32_t
+get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
+ Bool enabled_crtc_only, Bool exclude_multiplane)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ modesettingPtr ms = modesettingPTR(scrn);
+ drmmode_ptr drmmode = &ms->drmmode;
+ int c, i, j, k, count_modifiers = 0;
+ uint64_t *tmp, *ret = NULL;
+
+ *modifiers = NULL;
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ if (enabled_crtc_only && !crtc->enabled)
+ continue;
+
+ for (i = 0; i < drmmode_crtc->num_formats; i++) {
+ drmmode_format_ptr iter = &drmmode_crtc->formats[i];
+
+ if (iter->format != format)
+ continue;
+
+ for (j = 0; j < iter->num_modifiers; j++) {
+ Bool found = FALSE;
+
+ /* Don't choose multi-plane formats for our screen pixmap.
+ * These will get used with frontbuffer rendering, which will
+ * lead to worse-than-tearing with multi-plane formats, as the
+ * primary and auxiliary planes go out of sync. */
+ if (exclude_multiplane &&
+ gbm_device_get_format_modifier_plane_count(drmmode->gbm,
+ format,
+ iter->modifiers[j]) > 1) {
+ continue;
+ }
+
+ for (k = 0; k < count_modifiers; k++) {
+ if (iter->modifiers[j] == ret[k])
+ found = TRUE;
+ }
+ if (!found) {
+ count_modifiers++;
+ tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
+ if (!tmp) {
+ free(ret);
+ return 0;
+ }
+ ret = tmp;
+ ret[count_modifiers - 1] = iter->modifiers[j];
+ }
+ }
+ }
+ }
+
+ *modifiers = ret;
+ return count_modifiers;
+}
+#endif
+
static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
{
@@ -593,14 +655,36 @@ static Bool
drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
unsigned width, unsigned height, unsigned bpp)
{
+ uint32_t format;
+
+ if (drmmode->scrn->depth == 30)
+ format = GBM_FORMAT_ARGB2101010;
+ else
+ format = GBM_FORMAT_ARGB8888;
+
bo->width = width;
bo->height = height;

#ifdef GLAMOR_HAS_GBM
if (drmmode->glamor) {
- bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
- drmmode->scrn->depth == 30 ?
- GBM_FORMAT_ARGB2101010 : GBM_FORMAT_ARGB8888,
+#ifdef GBM_BO_WITH_MODIFIERS
+ uint32_t num_modifiers;
+ uint64_t *modifiers = NULL;
+
+ num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
+ FALSE, TRUE);
+ if (num_modifiers > 0 &&
+ !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
+ bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
+ format, modifiers,
+ num_modifiers);
+ free(modifiers);
+ if (bo->gbm)
+ return TRUE;
+ }
+#endif
+
+ bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
return bo->gbm != NULL;
}
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mai
Daniel Stone
2018-02-28 01:16:32 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

This allows the uses of CCS compressed or tiled pixmaps as BOs when
page-flipping.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 49 ++++++++++++++++++++++++
hw/xfree86/drivers/modesetting/drmmode_display.h | 4 ++
hw/xfree86/drivers/modesetting/pageflip.c | 16 ++++----
3 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 8674c2c16..ee9f4d724 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -39,6 +39,8 @@
#include "micmap.h"
#include "xf86cmap.h"
#include "xf86DDC.h"
+#include <drm_fourcc.h>
+#include <drm_mode.h>

#include <xf86drm.h>
#include "xf86Crtc.h"
@@ -376,10 +378,57 @@ drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
return bo->dumb->ptr;
}

+int
+drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+ uint32_t *fb_id)
+{
+#ifdef GBM_BO_WITH_MODIFIERS
+ if (bo->gbm &&
+ gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
+ int num_fds;
+
+ num_fds = gbm_bo_get_plane_count(bo->gbm);
+ if (num_fds > 0) {
+ int i;
+ uint32_t format;
+ uint32_t handles[4];
+ uint32_t strides[4];
+ uint32_t offsets[4];
+ uint64_t modifiers[4];
+
+ memset(handles, 0, sizeof(handles));
+ memset(strides, 0, sizeof(strides));
+ memset(offsets, 0, sizeof(offsets));
+ memset(modifiers, 0, sizeof(modifiers));
+
+ format = gbm_bo_get_format(bo->gbm);
+ for (i = 0; i < num_fds; i++) {
+ handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
+ strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
+ offsets[i] = gbm_bo_get_offset(bo->gbm, i);
+ modifiers[i] = gbm_bo_get_modifier(bo->gbm);
+ }
+
+ return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
+ format, handles, strides,
+ offsets, modifiers, fb_id,
+ DRM_MODE_FB_MODIFIERS);
+ }
+ }
+#endif
+ return drmModeAddFB(drmmode->fd, bo->width, bo->height,
+ drmmode->scrn->depth, drmmode->scrn->bitsPerPixel,
+ drmmode_bo_get_pitch(bo),
+ drmmode_bo_get_handle(bo), fb_id);
+}
+
static Bool
drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
unsigned width, unsigned height, unsigned bpp)
{
+ bo->width = width;
+ bo->height = height;
+
#ifdef GLAMOR_HAS_GBM
if (drmmode->glamor) {
bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 1f24c3a5b..177ccabd7 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -53,6 +53,8 @@ enum drmmode_plane_type {
};

typedef struct {
+ uint32_t width;
+ uint32_t height;
struct dumb_bo *dumb;
#ifdef GLAMOR_HAS_GBM
struct gbm_bo *gbm;
@@ -202,6 +204,8 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec;

#define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))

+int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+ uint32_t *fb_id);
int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo);
uint32_t drmmode_bo_get_pitch(drmmode_bo *bo);
uint32_t drmmode_bo_get_handle(drmmode_bo *bo);
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index dd296cd12..027ebfe42 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -258,6 +258,7 @@ ms_do_pageflip(ScreenPtr screen,

new_front_bo.gbm = glamor_gbm_bo_from_pixmap(screen, new_front);
new_front_bo.dumb = NULL;
+
if (!new_front_bo.gbm) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Failed to get GBM bo for flip to new front.\n");
@@ -288,14 +289,12 @@ ms_do_pageflip(ScreenPtr screen,

/* Create a new handle for the back buffer */
flipdata->old_fb_id = ms->drmmode.fb_id;
- if (drmModeAddFB(ms->fd, scrn->virtualX, scrn->virtualY,
- scrn->depth, scrn->bitsPerPixel,
- drmmode_bo_get_pitch(&new_front_bo),
- drmmode_bo_get_handle(&new_front_bo), &ms->drmmode.fb_id)) {
- goto error_out;
- }

- drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+ new_front_bo.width = new_front->drawable.width;
+ new_front_bo.height = new_front->drawable.height;
+ if (drmmode_bo_import(&ms->drmmode, &new_front_bo,
+ &ms->drmmode.fb_id))
+ goto error_out;

flags = DRM_MODE_PAGE_FLIP_EVENT;
if (async)
@@ -323,6 +322,8 @@ ms_do_pageflip(ScreenPtr screen,
}
}

+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+
/*
* Do we have more than our local reference,
* if so and no errors, then drop our local
@@ -348,6 +349,7 @@ error_undo:
error_out:
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
strerror(errno));
+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
/* if only the local reference - free the structure,
* else drop the local reference and return */
if (flipdata->flip_count == 1)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/list
Daniel Stone
2018-02-28 01:16:33 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

To make sure we also use the same primary plane and to avoid
mixing uses of two APIs, it is better to always use the atomic
modesetting API when possible.

v2: Don't use mode_output->connector_id

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 262 +++++++++++++++++++----
hw/xfree86/drivers/modesetting/drmmode_display.h | 30 ++-
hw/xfree86/drivers/modesetting/pageflip.c | 2 +-
hw/xfree86/drivers/modesetting/present.c | 3 +-
4 files changed, 252 insertions(+), 45 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index ee9f4d724..3e3613a98 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -267,16 +267,100 @@ plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
info->prop_id, val);
return (ret <= 0) ? -1 : 0;
}
+
+static int
+crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+ enum drmmode_crtc_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+
+static int
+connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
+ enum drmmode_connector_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+
+static int
+drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
+{
+ return memcmp(kmode, other, sizeof(*kmode));
+}
+
+static int
+drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_mode_ptr mode;
+ int ret;
+
+ if (drmmode_crtc->current_mode &&
+ drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
+ return 0;
+
+ mode = calloc(sizeof(drmmode_mode_rec), 1);
+ if (!mode)
+ return -1;
+
+ mode->mode_info = mode_info;
+ ret = drmModeCreatePropertyBlob(ms->fd,
+ &mode->mode_info,
+ sizeof(mode->mode_info),
+ &mode->blob_id);
+ drmmode_crtc->current_mode = mode;
+ xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
+
+ return ret;
+}
+
+static void
+drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ if (mode->blob_id)
+ drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
+ xorg_list_del(&mode->entry);
+ free(mode);
+}
#endif

+static void
+drmmode_ConvertToKMode(ScrnInfoPtr scrn,
+ drmModeModeInfo * kmode, DisplayModePtr mode);
+
int
-drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
int x, int y, uint32_t flags, void *data)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
- int ret = 0;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ int output_count = 0;
+ uint32_t *output_ids = NULL;
+ drmModeModeInfo kmode;
+ int i, ret = 0;
+
+ if (mode)
+ drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);

#ifdef GLAMOR_HAS_DRM_ATOMIC
if (ms->atomic_modeset) {
@@ -285,12 +369,56 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
if (!req)
return 1;

+ if (mode) {
+ ret = drm_mode_ensure_blob(crtc, kmode);
+
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ if (output->crtc != crtc)
+ continue;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
+
+ if (drmmode_output->dpms == DPMSModeOn) {
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_ACTIVE, 1);
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_MODE_ID,
+ drmmode_crtc->current_mode->blob_id);
+ ret |= connector_add_prop(req, drmmode_output,
+ DRMMODE_CONNECTOR_CRTC_ID,
+ drmmode_crtc->mode_crtc->crtc_id);
+ } else {
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_ACTIVE, 0);
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_MODE_ID, 0);
+ ret |= connector_add_prop(req, drmmode_output,
+ DRMMODE_CONNECTOR_CRTC_ID, 0);
+ }
+ }
+ }
+
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
fb_id);
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
drmmode_crtc->mode_crtc->crtc_id);
- ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
- ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
+ drmmode->front_bo.width << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
+ drmmode->front_bo.height << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
+ drmmode->front_bo.width);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
+ drmmode->front_bo.height);

if (ret == 0)
ret = drmModeAtomicCommit(ms->fd, req, flags, data);
@@ -300,7 +428,29 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
}
#endif

- return 0;
+ output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
+ if (!output_ids)
+ return -1;
+
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ if (output->crtc != crtc)
+ continue;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
+ output_ids[output_count] = drmmode_output->output_id;
+ output_count++;
+ }
+
+ ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+ fb_id, x, y, output_ids, output_count, &kmode);
+
+ free(output_ids);
+ return ret;
}


@@ -858,23 +1008,16 @@ static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
{
- ScrnInfoPtr pScrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int saved_x, saved_y;
Rotation saved_rotation;
DisplayModeRec saved_mode;
- uint32_t *output_ids = NULL;
- int output_count = 0;
Bool ret = TRUE;
int i;
uint32_t fb_id = 0;
- drmModeModeInfo kmode;
-
- output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
- if (!output_ids)
- return FALSE;
+ uint32_t flags = 0;

saved_mode = crtc->mode;
saved_x = crtc->x;
@@ -887,29 +1030,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
crtc->y = y;
crtc->rotation = rotation;

- for (i = 0; i < xf86_config->num_output; i++) {
- xf86OutputPtr output = xf86_config->output[i];
- drmmode_output_private_ptr drmmode_output;
-
- if (output->crtc != crtc)
- continue;
-
- drmmode_output = output->driver_private;
- if (drmmode_output->output_id == -1)
- continue;
- output_ids[output_count] =
- drmmode_output->mode_output->connector_id;
- output_count++;
- }
-
if (!xf86CrtcRotate(crtc)) {
goto done;
}
+
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);

- drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
-
fb_id = drmmode->fb_id;
if (drmmode_crtc->prime_pixmap) {
if (!drmmode->reverse_prime_offload_mode) {
@@ -927,12 +1054,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
}

if (fb_id == 0) {
- ret = drmModeAddFB(drmmode->fd,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->depth, drmmode->kbpp,
- drmmode_bo_get_pitch(&drmmode->front_bo),
- drmmode_bo_get_handle(&drmmode->front_bo),
- &drmmode->fb_id);
+ ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
+ &drmmode->fb_id);
if (ret < 0) {
ErrorF("failed to add fb %d\n", ret);
ret = FALSE;
@@ -941,8 +1064,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
fb_id = drmmode->fb_id;
}

- if (drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
- fb_id, x, y, output_ids, output_count, &kmode)) {
+ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+ if (drmmode_crtc_set_fb(crtc, mode, fb_id, x, y, flags, NULL)) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"failed to set mode: %s\n", strerror(errno));
ret = FALSE;
@@ -983,8 +1106,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
} else
crtc->active = TRUE;

- free(output_ids);
-
return ret;
}

@@ -1355,9 +1476,15 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)
{
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_mode_ptr iterator, next;
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;

drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
+ drm_mode_destroy(crtc, iterator);
+ }
+#endif
}

static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
@@ -1437,6 +1564,12 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
[DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
[DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
[DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
+ [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
+ [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
+ [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
+ [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
+ [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
};
drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];

@@ -1524,19 +1657,37 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
xf86CrtcPtr crtc;
drmmode_crtc_private_ptr drmmode_crtc;
modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmModeObjectPropertiesPtr props;
+ static const drmmode_prop_info_rec crtc_props[] = {
+ [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
+ [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
+ };
+#endif

crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
if (crtc == NULL)
return 0;
-
drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
+ crtc->driver_private = drmmode_crtc;
drmmode_crtc->mode_crtc =
drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
drmmode_crtc->drmmode = drmmode;
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
- crtc->driver_private = drmmode_crtc;
+ xorg_list_init(&drmmode_crtc->mode_list);

#ifdef GLAMOR_HAS_DRM_ATOMIC
+ props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
+ DRM_MODE_OBJECT_CRTC);
+ if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
+ DRMMODE_CRTC__COUNT, 0)) {
+ xf86CrtcDestroy(crtc);
+ return 0;
+ }
+
+ drmmode_prop_info_update(drmmode, drmmode_crtc->props,
+ DRMMODE_CRTC__COUNT, props);
+ drmModeFreeObjectProperties(props);
drmmode_crtc_create_planes(crtc, num);
#endif

@@ -1680,6 +1831,7 @@ koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
return idx;
}

+#ifndef GLAMOR_HAS_DRM_ATOMIC
static int
koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
int type, const char *name)
@@ -1688,6 +1840,7 @@ koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,

return (idx > -1) ? koutput->props[idx] : -1;
}
+#endif

static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
@@ -1859,13 +2012,19 @@ drmmode_output_dpms(xf86OutputPtr output, int mode)
drmmode_output_private_ptr drmmode_output = output->driver_private;
xf86CrtcPtr crtc = output->crtc;
drmModeConnectorPtr koutput = drmmode_output->mode_output;
+#ifndef GLAMOR_HAS_DRM_ATOMIC
drmmode_ptr drmmode = drmmode_output->drmmode;
+#endif

if (!koutput)
return;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_output->dpms = mode;
+#else
drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
drmmode_output->dpms_enum_id, mode);
+#endif

if (crtc) {
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
@@ -2214,6 +2373,13 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
Bool nonDesktop = FALSE;
drmModePropertyBlobPtr path_blob = NULL;
const char *s;
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmModeObjectPropertiesPtr props;
+ static const drmmode_prop_info_rec connector_props[] = {
+ [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
+ };
+#endif
+
koutput =
drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
if (!koutput)
@@ -2301,8 +2467,20 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
/* work out the possible clones later */
output->possible_clones = 0;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (!drmmode_prop_info_copy(drmmode_output->props_connector, connector_props,
+ DRMMODE_CONNECTOR__COUNT, 0)) {
+ goto out_free_encoders;
+ }
+ props = drmModeObjectGetProperties(drmmode->fd,
+ drmmode_output->output_id,
+ DRM_MODE_OBJECT_CONNECTOR);
+ drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
+ DRMMODE_CONNECTOR__COUNT, props);
+#else
drmmode_output->dpms_enum_id =
koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM, "DPMS");
+#endif

if (dynamic)
output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 177ccabd7..e5f3542c5 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -42,6 +42,12 @@ enum drmmode_plane_property {
DRMMODE_PLANE_CRTC_ID,
DRMMODE_PLANE_SRC_X,
DRMMODE_PLANE_SRC_Y,
+ DRMMODE_PLANE_SRC_W,
+ DRMMODE_PLANE_SRC_H,
+ DRMMODE_PLANE_CRTC_X,
+ DRMMODE_PLANE_CRTC_Y,
+ DRMMODE_PLANE_CRTC_W,
+ DRMMODE_PLANE_CRTC_H,
DRMMODE_PLANE__COUNT
};

@@ -52,6 +58,17 @@ enum drmmode_plane_type {
DRMMODE_PLANE_TYPE__COUNT
};

+enum drmmode_connector_property {
+ DRMMODE_CONNECTOR_CRTC_ID,
+ DRMMODE_CONNECTOR__COUNT
+};
+
+enum drmmode_crtc_property {
+ DRMMODE_CRTC_ACTIVE,
+ DRMMODE_CRTC_MODE_ID,
+ DRMMODE_CRTC__COUNT
+};
+
typedef struct {
uint32_t width;
uint32_t height;
@@ -119,6 +136,12 @@ typedef struct {
drmmode_prop_enum_info_rec *enum_values;
} drmmode_prop_info_rec, *drmmode_prop_info_ptr;

+typedef struct {
+ drmModeModeInfo mode_info;
+ uint32_t blob_id;
+ struct xorg_list entry;
+} drmmode_mode_rec, *drmmode_mode_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -128,8 +151,10 @@ typedef struct {
Bool cursor_up;
uint16_t lut_r[256], lut_g[256], lut_b[256];

+ drmmode_prop_info_rec props[DRMMODE_CRTC__COUNT];
drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
uint32_t plane_id;
+ drmmode_mode_ptr current_mode;

drmmode_bo rotate_bo;
unsigned rotate_fb_id;
@@ -151,6 +176,7 @@ typedef struct {
/** @} */

Bool need_modeset;
+ struct xorg_list mode_list;

Bool enable_flipping;
Bool flipping_active;
@@ -171,8 +197,10 @@ typedef struct {
drmModePropertyBlobPtr edid_blob;
drmModePropertyBlobPtr tile_blob;
int dpms_enum_id;
+ int dpms;
int num_props;
drmmode_prop_ptr props;
+ drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT];
int enc_mask;
int enc_clone_mask;
} drmmode_output_private_rec, *drmmode_output_private_ptr;
@@ -242,7 +270,7 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,

void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);

-int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
int x, int y, uint32_t flags, void *data);

#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index 027ebfe42..26738f928 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -168,7 +168,7 @@ do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
#ifdef GLAMOR_HAS_DRM_ATOMIC
if (ms->atomic_modeset) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
- return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+ return drmmode_crtc_set_fb(crtc, NULL, ms->drmmode.fb_id, 0, 0, flags,
(void *) (uintptr_t) seq);
}
#endif
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index c01be3486..4a01d19ea 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -248,7 +248,8 @@ ms_present_check_flip(RRCrtcPtr crtc,
return FALSE;

/* Check stride, can't change that on flip */
- if (pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
+ if (!ms->atomic_modeset &&
+ pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
return FALSE;

/* Make sure there's a bo we can get to */
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo
Daniel Stone
2018-02-28 01:19:35 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Initial implementation for DRI3 v1.1. Only the DRI3 implementation
is there, backends need to implement the proper hooks.

Version is still set to 1.0 so clients shouldn't use the new
requests yet.

v2: Use depth/bpp instead of DRM formats in requests

v3: Remove DMA fence requests from v1.1
Add screen/drawable modifier sets

v4: Free array returned by 'get_drawable_modifiers()'

v5: Fix FD leak

Signed-off-by: Daniel Stone <***@collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
---
configure.ac | 2 +-
dri3/dri3.c | 19 +++
dri3/dri3.h | 44 ++++++-
dri3/dri3_priv.h | 27 +++-
dri3/dri3_request.c | 294 ++++++++++++++++++++++++++++++++++++++++--
dri3/dri3_screen.c | 196 ++++++++++++++++++++++++++--
hw/xwayland/xwayland-glamor.c | 4 +-
meson.build | 2 +-
8 files changed, 559 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4d7c24fa9..47469d864 100644
--- a/configure.ac
+++ b/configure.ac
@@ -729,7 +729,7 @@ SCRNSAVERPROTO="scrnsaverproto >= 1.1"
RESOURCEPROTO="resourceproto >= 1.2.0"
DRIPROTO="xf86driproto >= 2.1.0"
DRI2PROTO="dri2proto >= 2.8"
-DRI3PROTO="dri3proto >= 1.0"
+DRI3PROTO="dri3proto >= 1.2"
XINERAMAPROTO="xineramaproto"
BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
DGAPROTO="xf86dgaproto >= 2.0.99.1"
diff --git a/dri3/dri3.c b/dri3/dri3.c
index d042b8b7d..8ac0f3ae2 100644
--- a/dri3/dri3.c
+++ b/dri3/dri3.c
@@ -26,6 +26,8 @@

#include "dri3_priv.h"

+#include <drm_fourcc.h>
+
static int dri3_request;
DevPrivateKeyRec dri3_screen_private_key;

@@ -99,3 +101,20 @@ dri3_extension_init(void)
bail:
FatalError("Cannot initialize DRI3 extension");
}
+
+uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp)
+{
+ switch (bpp) {
+ case 16:
+ return DRM_FORMAT_RGB565;
+ case 24:
+ return DRM_FORMAT_XRGB8888;
+ case 30:
+ return DRM_FORMAT_XRGB2101010;
+ case 32:
+ return DRM_FORMAT_ARGB8888;
+ default:
+ return 0;
+ }
+}
diff --git a/dri3/dri3.h b/dri3/dri3.h
index 7562352ff..89ad13ad9 100644
--- a/dri3/dri3.h
+++ b/dri3/dri3.h
@@ -28,7 +28,7 @@
#include <X11/extensions/dri3proto.h>
#include <randrstr.h>

-#define DRI3_SCREEN_INFO_VERSION 1
+#define DRI3_SCREEN_INFO_VERSION 2

typedef int (*dri3_open_proc)(ScreenPtr screen,
RRProviderPtr provider,
@@ -47,11 +47,43 @@ typedef PixmapPtr (*dri3_pixmap_from_fd_proc) (ScreenPtr screen,
CARD8 depth,
CARD8 bpp);

+typedef PixmapPtr (*dri3_pixmap_from_fds_proc) (ScreenPtr screen,
+ CARD8 num_fds,
+ int *fds,
+ CARD16 width,
+ CARD16 height,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD8 depth,
+ CARD8 bpp,
+ CARD64 modifier);
+
typedef int (*dri3_fd_from_pixmap_proc) (ScreenPtr screen,
PixmapPtr pixmap,
CARD16 *stride,
CARD32 *size);

+typedef int (*dri3_fds_from_pixmap_proc) (ScreenPtr screen,
+ PixmapPtr pixmap,
+ int *fds,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD64 *modifier);
+
+typedef int (*dri3_get_formats_proc) (ScreenPtr screen,
+ CARD32 *num_formats,
+ CARD32 **formats);
+
+typedef int (*dri3_get_modifiers_proc) (ScreenPtr screen,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ CARD64 **modifiers);
+
+typedef int (*dri3_get_drawable_modifiers_proc) (DrawablePtr draw,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ CARD64 **modifiers);
+
typedef struct dri3_screen_info {
uint32_t version;

@@ -62,6 +94,13 @@ typedef struct dri3_screen_info {
/* Version 1 */
dri3_open_client_proc open_client;

+ /* Version 2 */
+ dri3_pixmap_from_fds_proc pixmap_from_fds;
+ dri3_fds_from_pixmap_proc fds_from_pixmap;
+ dri3_get_formats_proc get_formats;
+ dri3_get_modifiers_proc get_modifiers;
+ dri3_get_drawable_modifiers_proc get_drawable_modifiers;
+
} dri3_screen_info_rec, *dri3_screen_info_ptr;

extern _X_EXPORT Bool
@@ -70,6 +109,9 @@ dri3_screen_init(ScreenPtr screen, dri3_screen_info_ptr info);
extern _X_EXPORT int
dri3_send_open_reply(ClientPtr client, int fd);

+extern _X_EXPORT uint32_t
+drm_format_for_depth(uint32_t depth, uint32_t bpp);
+
#endif

#endif /* _DRI3_H_ */
diff --git a/dri3/dri3_priv.h b/dri3/dri3_priv.h
index e61ef226c..8447680ba 100644
--- a/dri3/dri3_priv.h
+++ b/dri3/dri3_priv.h
@@ -34,11 +34,21 @@

extern DevPrivateKeyRec dri3_screen_private_key;

+typedef struct dri3_dmabuf_format {
+ uint32_t format;
+ uint32_t num_modifiers;
+ uint64_t *modifiers;
+} dri3_dmabuf_format_rec, *dri3_dmabuf_format_ptr;
+
typedef struct dri3_screen_priv {
CloseScreenProcPtr CloseScreen;
ConfigNotifyProcPtr ConfigNotify;
DestroyWindowProcPtr DestroyWindow;

+ Bool formats_cached;
+ CARD32 num_formats;
+ dri3_dmabuf_format_ptr formats;
+
dri3_screen_info_ptr info;
} dri3_screen_priv_rec, *dri3_screen_priv_ptr;

@@ -69,10 +79,21 @@ int
dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd);

int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp);
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen, CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height, CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp, CARD64 modifier);
+
+int
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+ CARD32 *strides, CARD32 *offsets,
+ CARD64 *modifier);

int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size);
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+ CARD8 depth, CARD8 bpp,
+ CARD32 *num_drawable_modifiers,
+ CARD64 **drawable_modifiers,
+ CARD32 *num_screen_modifiers,
+ CARD64 **screen_modifiers);

#endif /* _DRI3PRIV_H_ */
diff --git a/dri3/dri3_request.c b/dri3/dri3_request.c
index b28d883a5..7f3f0d08c 100644
--- a/dri3/dri3_request.c
+++ b/dri3/dri3_request.c
@@ -30,6 +30,7 @@
#include <xace.h>
#include "../Xext/syncsdk.h"
#include <protocol-versions.h>
+#include <drm_fourcc.h>

static int
proc_dri3_query_version(ClientPtr client)
@@ -124,6 +125,7 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
int fd;
DrawablePtr drawable;
PixmapPtr pixmap;
+ CARD32 stride, offset;
int rc;

SetReqFds(client, 1);
@@ -159,11 +161,14 @@ proc_dri3_pixmap_from_buffer(ClientPtr client)
if (fd < 0)
return BadValue;

- rc = dri3_pixmap_from_fd(&pixmap,
- drawable->pScreen, fd,
- stuff->width, stuff->height,
- stuff->stride, stuff->depth,
- stuff->bpp);
+ offset = 0;
+ stride = stuff->stride;
+ rc = dri3_pixmap_from_fds(&pixmap,
+ drawable->pScreen, 1, &fd,
+ stuff->width, stuff->height,
+ &stride, &offset,
+ stuff->depth, stuff->bpp,
+ DRM_FORMAT_MOD_INVALID);
close (fd);
if (rc != Success)
return rc;
@@ -195,7 +200,10 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
.length = 0,
};
int rc;
- int fd;
+ int num_fds;
+ int fds[4];
+ uint32_t strides[4], offsets[4];
+ uint64_t modifier;
PixmapPtr pixmap;

REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
@@ -211,9 +219,12 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
rep.depth = pixmap->drawable.depth;
rep.bpp = pixmap->drawable.bitsPerPixel;

- rc = dri3_fd_from_pixmap(&fd, pixmap, &rep.stride, &rep.size);
- if (rc != Success)
- return rc;
+ num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+ if (num_fds != 1)
+ return BadPixmap;
+
+ rep.stride = (CARD16) strides[0];
+ rep.size = rep.stride * rep.height;

if (client->swapped) {
swaps(&rep.sequenceNumber);
@@ -223,8 +234,8 @@ proc_dri3_buffer_from_pixmap(ClientPtr client)
swaps(&rep.height);
swaps(&rep.stride);
}
- if (WriteFdToClient(client, fd, TRUE) < 0) {
- close(fd);
+ if (WriteFdToClient(client, fds[0], TRUE) < 0) {
+ close(fds[0]);
return BadAlloc;
}

@@ -299,6 +310,216 @@ proc_dri3_fd_from_fence(ClientPtr client)
return Success;
}

+static int
+proc_dri3_get_supported_modifiers(ClientPtr client)
+{
+ REQUEST(xDRI3GetSupportedModifiersReq);
+ xDRI3GetSupportedModifiersReply rep = {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ };
+ WindowPtr window;
+ ScreenPtr pScreen;
+ CARD64 *window_modifiers = NULL;
+ CARD64 *screen_modifiers = NULL;
+ CARD32 nwindowmodifiers = 0;
+ CARD32 nscreenmodifiers = 0;
+ int status;
+ int i;
+
+ REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+ status = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
+ if (status != Success)
+ return status;
+ pScreen = window->drawable.pScreen;
+
+ dri3_get_supported_modifiers(pScreen, &window->drawable,
+ stuff->depth, stuff->bpp,
+ &nwindowmodifiers, &window_modifiers,
+ &nscreenmodifiers, &screen_modifiers);
+
+ rep.numWindowModifiers = nwindowmodifiers;
+ rep.numScreenModifiers = nscreenmodifiers;
+ rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) +
+ bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swapl(&rep.numWindowModifiers);
+ swapl(&rep.numScreenModifiers);
+ for (i = 0; i < nwindowmodifiers; i++)
+ swapll(&window_modifiers[i]);
+ for (i = 0; i < nscreenmodifiers; i++)
+ swapll(&screen_modifiers[i]);
+ }
+
+ WriteToClient(client, sizeof(rep), &rep);
+ WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers);
+ WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
+
+ free(window_modifiers);
+ free(screen_modifiers);
+
+ return Success;
+}
+
+static int
+proc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+ REQUEST(xDRI3PixmapFromBuffersReq);
+ int fds[4];
+ CARD32 strides[4], offsets[4];
+ ScreenPtr screen;
+ WindowPtr window;
+ PixmapPtr pixmap;
+ int rc;
+ int i;
+
+ SetReqFds(client, stuff->num_buffers);
+ REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+ LEGAL_NEW_RESOURCE(stuff->pixmap, client);
+ rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->window;
+ return rc;
+ }
+ screen = window->drawable.pScreen;
+
+ if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
+ client->errorValue = 0;
+ return BadValue;
+ }
+
+ if (stuff->width > 32767 || stuff->height > 32767)
+ return BadAlloc;
+
+ if (stuff->depth != 1) {
+ DepthPtr depth = screen->allowedDepths;
+ int j;
+ for (j = 0; j < screen->numDepths; j++, depth++)
+ if (depth->depth == stuff->depth)
+ break;
+ if (j == screen->numDepths) {
+ client->errorValue = stuff->depth;
+ return BadValue;
+ }
+ }
+
+ if (!stuff->num_buffers || stuff->num_buffers > 4) {
+ client->errorValue = stuff->num_buffers;
+ return BadValue;
+ }
+
+ for (i = 0; i < stuff->num_buffers; i++) {
+ fds[i] = ReadFdFromClient(client);
+ if (fds[i] < 0) {
+ while (--i >= 0)
+ close(fds[i]);
+ return BadValue;
+ }
+ }
+
+ strides[0] = stuff->stride0;
+ strides[1] = stuff->stride1;
+ strides[2] = stuff->stride2;
+ strides[3] = stuff->stride3;
+ offsets[0] = stuff->offset0;
+ offsets[1] = stuff->offset1;
+ offsets[2] = stuff->offset2;
+ offsets[3] = stuff->offset3;
+
+ rc = dri3_pixmap_from_fds(&pixmap, screen,
+ stuff->num_buffers, fds,
+ stuff->width, stuff->height,
+ strides, offsets,
+ stuff->depth, stuff->bpp,
+ stuff->modifier);
+
+ for (i = 0; i < stuff->num_buffers; i++)
+ close (fds[i]);
+
+ if (rc != Success)
+ return rc;
+
+ pixmap->drawable.id = stuff->pixmap;
+
+ /* security creation/labeling check */
+ rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
+ pixmap, RT_NONE, NULL, DixCreateAccess);
+
+ if (rc != Success) {
+ (*screen->DestroyPixmap) (pixmap);
+ return rc;
+ }
+ if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
+ return BadAlloc;
+
+ return Success;
+}
+
+static int
+proc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+ REQUEST(xDRI3BuffersFromPixmapReq);
+ xDRI3BuffersFromPixmapReply rep = {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ };
+ int rc;
+ int fds[4];
+ int num_fds;
+ uint32_t strides[4], offsets[4];
+ uint64_t modifier;
+ int i;
+ PixmapPtr pixmap;
+
+ REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
+ rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
+ client, DixWriteAccess);
+ if (rc != Success) {
+ client->errorValue = stuff->pixmap;
+ return rc;
+ }
+
+ num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
+ if (num_fds == 0)
+ return BadPixmap;
+
+ rep.nfd = num_fds;
+ rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
+ rep.width = pixmap->drawable.width;
+ rep.height = pixmap->drawable.height;
+ rep.modifier = modifier;
+
+ if (client->swapped) {
+ swaps(&rep.sequenceNumber);
+ swapl(&rep.length);
+ swaps(&rep.width);
+ swaps(&rep.height);
+ swapll(&rep.modifier);
+ for (i = 0; i < num_fds; i++) {
+ swapl(&strides[i]);
+ swapl(&offsets[i]);
+ }
+ }
+
+ for (i = 0; i < num_fds; i++) {
+ if (WriteFdToClient(client, fds[i], TRUE) < 0) {
+ while (i--)
+ close(fds[i]);
+ return BadAlloc;
+ }
+ }
+
+ WriteToClient(client, sizeof(rep), &rep);
+ WriteToClient(client, num_fds * sizeof(CARD32), strides);
+ WriteToClient(client, num_fds * sizeof(CARD32), offsets);
+
+ return Success;
+}
+
int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
proc_dri3_query_version, /* 0 */
proc_dri3_open, /* 1 */
@@ -306,6 +527,9 @@ int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
proc_dri3_buffer_from_pixmap, /* 3 */
proc_dri3_fence_from_fd, /* 4 */
proc_dri3_fd_from_fence, /* 5 */
+ proc_dri3_get_supported_modifiers, /* 6 */
+ proc_dri3_pixmap_from_buffers, /* 7 */
+ proc_dri3_buffers_from_pixmap, /* 8 */
};

int
@@ -394,6 +618,51 @@ sproc_dri3_fd_from_fence(ClientPtr client)
return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
}

+static int _X_COLD
+sproc_dri3_get_supported_modifiers(ClientPtr client)
+{
+ REQUEST(xDRI3GetSupportedModifiersReq);
+ REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->window);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_pixmap_from_buffers(ClientPtr client)
+{
+ REQUEST(xDRI3PixmapFromBuffersReq);
+ REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->pixmap);
+ swapl(&stuff->window);
+ swaps(&stuff->width);
+ swaps(&stuff->height);
+ swapl(&stuff->stride0);
+ swapl(&stuff->offset0);
+ swapl(&stuff->stride1);
+ swapl(&stuff->offset1);
+ swapl(&stuff->stride2);
+ swapl(&stuff->offset2);
+ swapl(&stuff->stride3);
+ swapl(&stuff->offset3);
+ swapll(&stuff->modifier);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
+static int _X_COLD
+sproc_dri3_buffers_from_pixmap(ClientPtr client)
+{
+ REQUEST(xDRI3BuffersFromPixmapReq);
+ REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
+
+ swaps(&stuff->length);
+ swapl(&stuff->pixmap);
+ return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
+}
+
int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
sproc_dri3_query_version, /* 0 */
sproc_dri3_open, /* 1 */
@@ -401,6 +670,9 @@ int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
sproc_dri3_buffer_from_pixmap, /* 3 */
sproc_dri3_fence_from_fd, /* 4 */
sproc_dri3_fd_from_fence, /* 5 */
+ sproc_dri3_get_supported_modifiers, /* 6 */
+ sproc_dri3_pixmap_from_buffers, /* 7 */
+ sproc_dri3_buffers_from_pixmap, /* 8 */
};

int _X_COLD
diff --git a/dri3/dri3_screen.c b/dri3/dri3_screen.c
index 6c0c60cbf..df40f8281 100644
--- a/dri3/dri3_screen.c
+++ b/dri3/dri3_screen.c
@@ -29,6 +29,7 @@
#include <misync.h>
#include <misyncshm.h>
#include <randrstr.h>
+#include <drm_fourcc.h>

static inline Bool has_open(dri3_screen_info_ptr info) {
if (info == NULL)
@@ -60,17 +61,30 @@ dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
}

int
-dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride, CARD8 depth, CARD8 bpp)
+dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp, CARD64 modifier)
{
dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
dri3_screen_info_ptr info = ds->info;
PixmapPtr pixmap;

- if (!info || !info->pixmap_from_fd)
+ if (!info)
return BadImplementation;

- pixmap = (*info->pixmap_from_fd) (screen, fd, width, height, stride, depth, bpp);
+ if (info->version >= 2 && info->pixmap_from_fds != NULL) {
+ pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
+ strides, offsets, depth, bpp, modifier);
+ } else if (info->pixmap_from_fd != NULL && num_fds == 1 &&
+ modifier == DRM_FORMAT_MOD_INVALID) {
+ pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
+ strides[0], depth, bpp);
+ } else {
+ return BadImplementation;
+ }
+
if (!pixmap)
return BadAlloc;

@@ -79,20 +93,182 @@ dri3_pixmap_from_fd(PixmapPtr *ppixmap, ScreenPtr screen, int fd,
}

int
-dri3_fd_from_pixmap(int *pfd, PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
+ CARD32 *strides, CARD32 *offsets,
+ CARD64 *modifier)
{
ScreenPtr screen = pixmap->drawable.pScreen;
dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
dri3_screen_info_ptr info = ds->info;
- int fd;

- if (!info || !info->fd_from_pixmap)
+ if (!info)
+ return 0;
+
+ if (info->version >= 2 && info->fds_from_pixmap != NULL) {
+ return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
+ modifier);
+ } else if (info->fd_from_pixmap != NULL) {
+ CARD16 stride;
+ CARD32 size;
+
+ fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
+ if (fds[0] < 0)
+ return 0;
+
+ strides[0] = stride;
+ offsets[0] = 0;
+ *modifier = DRM_FORMAT_MOD_INVALID;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+cache_formats_and_modifiers(ScreenPtr screen)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ dri3_screen_info_ptr info = ds->info;
+ CARD32 *formats = NULL;
+ CARD64 *modifiers = NULL;
+ int i;
+
+ if (ds->formats_cached)
+ return Success;
+
+ if (!info)
return BadImplementation;

- fd = (*info->fd_from_pixmap)(screen, pixmap, stride, size);
- if (fd < 0)
+ if (!info->get_formats || !info->get_modifiers) {
+ ds->formats = NULL;
+ ds->num_formats = 0;
+ ds->formats_cached = TRUE;
+ return Success;
+ }
+
+ (*info->get_formats) (screen, &ds->num_formats, &formats);
+ ds->formats = calloc(ds->num_formats, sizeof(dri3_dmabuf_format_rec));
+ if (!ds->formats)
return BadAlloc;
- *pfd = fd;
+
+ for (i = 0; i < ds->num_formats; i++) {
+ dri3_dmabuf_format_ptr iter = &ds->formats[i];
+
+ iter->format = formats[i];
+ (*info->get_modifiers) (screen, formats[i],
+ &iter->num_modifiers,
+ &modifiers);
+
+ iter->modifiers = malloc(iter->num_modifiers * sizeof(CARD64));
+ if (iter->modifiers == NULL)
+ goto error;
+
+ memcpy(iter->modifiers, modifiers,
+ iter->num_modifiers * sizeof(CARD64));
+ goto done;
+
+error:
+ iter->num_modifiers = 0;
+ free(iter->modifiers);
+done:
+ free(modifiers);
+ }
+ free(formats);
+ ds->formats_cached = TRUE;
+
return Success;
}

+int
+dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
+ CARD8 depth, CARD8 bpp,
+ CARD32 *num_intersect_modifiers,
+ CARD64 **intersect_modifiers,
+ CARD32 *num_screen_modifiers,
+ CARD64 **screen_modifiers)
+{
+ dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
+ dri3_screen_info_ptr info = ds->info;
+ int i, j;
+ int ret;
+ CARD32 num_drawable_mods;
+ CARD64 *drawable_mods;
+ CARD64 *intersect_mods = NULL;
+ CARD64 *screen_mods = NULL;
+ CARD32 format;
+ dri3_dmabuf_format_ptr screen_format = NULL;
+
+ ret = cache_formats_and_modifiers(screen);
+ if (ret != Success)
+ return ret;
+
+ format = drm_format_for_depth(depth, bpp);
+ if (format == 0)
+ return BadValue;
+
+ /* Find screen-global modifiers from cache
+ */
+ for (i = 0; i < ds->num_formats; i++) {
+ if (ds->formats[i].format == format) {
+ screen_format = &ds->formats[i];
+ break;
+ }
+ }
+ if (screen_format == NULL)
+ return BadMatch;
+
+ if (screen_format->num_modifiers == 0) {
+ *num_screen_modifiers = 0;
+ *num_intersect_modifiers = 0;
+ return Success;
+ }
+
+ if (info->get_drawable_modifiers)
+ (*info->get_drawable_modifiers) (drawable, format,
+ &num_drawable_mods,
+ &drawable_mods);
+
+ /* We're allocating slightly more memory than necessary but it reduces
+ * the complexity of finding the intersection set.
+ */
+ screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+ if (!screen_mods)
+ return BadAlloc;
+ if (num_drawable_mods > 0) {
+ intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
+ if (!intersect_mods) {
+ free(screen_mods);
+ return BadAlloc;
+ }
+ }
+
+ *num_screen_modifiers = 0;
+ *num_intersect_modifiers = 0;
+ for (i = 0; i < screen_format->num_modifiers; i++) {
+ CARD64 modifier = screen_format->modifiers[i];
+ Bool intersect = FALSE;
+
+ for (j = 0; j < num_drawable_mods; j++) {
+ if (drawable_mods[j] == modifier) {
+ intersect = TRUE;
+ break;
+ }
+ }
+
+ if (intersect) {
+ intersect_mods[*num_intersect_modifiers] = modifier;
+ *num_intersect_modifiers += 1;
+ } else {
+ screen_mods[*num_screen_modifiers] = modifier;
+ *num_screen_modifiers += 1;
+ }
+ }
+
+ assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
+
+ *intersect_modifiers = intersect_mods;
+ *screen_modifiers = screen_mods;
+ free(drawable_mods);
+
+ return Success;
+}
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 8ffb40d6f..0933e9411 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -59,7 +59,7 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx)
}

static uint32_t
-drm_format_for_depth(int depth)
+wl_drm_format_for_depth(int depth)
{
switch (depth) {
case 15:
@@ -170,7 +170,7 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
pixmap->drawable.width,
pixmap->drawable.height,
- drm_format_for_depth(pixmap->drawable.depth),
+ wl_drm_format_for_depth(pixmap->drawable.depth),
0, gbm_bo_get_stride(xwl_pixmap->bo),
0, 0,
0, 0);
diff --git a/meson.build b/meson.build
index 77d3c9def..2477bb931 100644
--- a/meson.build
+++ b/meson.build
@@ -78,7 +78,7 @@ scrnsaverproto_dep = dependency('scrnsaverproto', version: '>= 1.1')
resourceproto_dep = dependency('resourceproto', version: '>= 1.2.0')
xf86driproto_dep = dependency('xf86driproto', version: '>= 2.1.0', required: get_option('dri1') == 'true')
dri2proto_dep = dependency('dri2proto', version: '>= 2.8', required: get_option('dri2') == 'true')
-dri3proto_dep = dependency('dri3proto', version: '>= 1.0', required: get_option('dri3') == 'true')
+dri3proto_dep = dependency('dri3proto', version: '>= 1.2', required: get_option('dri3') == 'true')
xineramaproto_dep = dependency('xineramaproto')
xf86bigfontproto_dep = dependency('xf86bigfontproto', version: '>= 1.2.0')
xf86vidmodeproto_dep = dependency('xf86vidmodeproto', version: '>= 2.2.99.1', required: false)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https:
Daniel Stone
2018-02-28 01:19:34 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

If the Complete event has this mode, the client is not using
the more optimal format/modifier for the buffer allocation. The
client must explicitely inform the server that it understands
this mode by adding the PresentOptionSuboptimal flag when calling
PresentPixmap.

Its main usage as of now is to allow clients to re-fetch DRI3
format modifiers as some modifiers might allow direct scanout.

Bump presentproto version to 1.2.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
include/X11/extensions/presenttokens.h | 13 +++++++-----
meson.build | 2 +-
presentproto.pc.in | 2 +-
presentproto.txt | 36 ++++++++++++++++++++++++----------
4 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/include/X11/extensions/presenttokens.h b/include/X11/extensions/presenttokens.h
index acb7576..9211207 100644
--- a/include/X11/extensions/presenttokens.h
+++ b/include/X11/extensions/presenttokens.h
@@ -25,7 +25,7 @@

#define PRESENT_NAME "Present"
#define PRESENT_MAJOR 1
-#define PRESENT_MINOR 0
+#define PRESENT_MINOR 2

#define PresentNumberErrors 0
#define PresentNumberEvents 0
@@ -44,10 +44,12 @@
#define PresentOptionAsync (1 << 0)
#define PresentOptionCopy (1 << 1)
#define PresentOptionUST (1 << 2)
+#define PresentOptionSuboptimal (1 << 3)

#define PresentAllOptions (PresentOptionAsync | \
PresentOptionCopy | \
- PresentOptionUST)
+ PresentOptionUST | \
+ PresentOptionSuboptimal)

/* Present capabilities */

@@ -94,8 +96,9 @@

/* Complete Modes */

-#define PresentCompleteModeCopy 0
-#define PresentCompleteModeFlip 1
-#define PresentCompleteModeSkip 2
+#define PresentCompleteModeCopy 0
+#define PresentCompleteModeFlip 1
+#define PresentCompleteModeSkip 2
+#define PresentCompleteModeSuboptimalCopy 3

#endif
diff --git a/meson.build b/meson.build
index cb92280..6fb1541 100644
--- a/meson.build
+++ b/meson.build
@@ -36,7 +36,7 @@ pcs = [
['glproto', '1.4.17'],
['inputproto', '2.3.2'],
['kbproto', '1.0.7'],
- ['presentproto', '1.1'],
+ ['presentproto', '1.2'],
['randrproto', '1.6.0'],
['recordproto', '1.14.2'],
['renderproto', '0.11.1'],
diff --git a/presentproto.pc.in b/presentproto.pc.in
index 9a32fa8..6ec4b7d 100644
--- a/presentproto.pc.in
+++ b/presentproto.pc.in
@@ -5,5 +5,5 @@ includedir=@includedir@

Name: PresentProto
Description: Present extension headers
-Version: 1.1
+Version: 1.2
Cflags: -I${includedir}
diff --git a/presentproto.txt b/presentproto.txt
index fdaf658..6ba55ae 100644
--- a/presentproto.txt
+++ b/presentproto.txt
@@ -1,6 +1,6 @@
The Present Extension
- Version 1.0
- 2013-6-6
+ Version 1.2
+ 2018-02-26

Keith Packard
***@keithp.com
@@ -24,6 +24,7 @@ change and is provided only as an aid to further Present development.
Eric Anholt <***@anholt.net>
Owen Taylor <***@redhat.com>
James Jones <***@nvidia.com>
+Louis-Francis Ratté-Boulianne <***@collabora.com>

❄ ❄ ❄ ❄ ❄ ❄ ❄

@@ -55,7 +56,8 @@ PRESENTEVENTMASK { PresentConfigureNotifyMask,

PRESENTOPTION { PresentOptionAsync,
PresentOptionCopy,
- PresentOptionUST }
+ PresentOptionUST,
+ PresentOptionSuboptimal }

PRESENTCAPABILITY { PresentCapabilityAsync,
PresentCapabilityFence,
@@ -66,7 +68,8 @@ PRESENTCOMPLETEKIND { PresentCompleteKindPixmap,

PRESENTCOMPLETEMODE { PresentCompleteModeCopy,
PresentCompleteModeFlip,
- PresentCompleteModeSkip }
+ PresentCompleteModeSkip,
+ PresentCompleteModeSuboptimalCopy }

The Present extension also uses the Sync extension Fence data type to
provide synchronization for pixmaps.
@@ -226,6 +229,10 @@ The name of this extension is "Present"
server will take the target UST time and convert it to a
suitable target MSC value.

+ If 'options' contains PresentOptionSuboptimal, then the
+ PresentCompleteNotify event can have mode
+ PresentCompleteModeSuboptimalCopy as the client supports it.
+
After the presentation occurs, a PresentCompleteNotify event
with kind PresentCompleteKindPixmap will be generated, both to
'window' as well as all members of 'notifies'.
@@ -408,12 +415,16 @@ The name of this extension is "Present"
'mode' is PresentCompleteModeCopy when the source pixmap
contents are taken from the pixmap and the pixmap is idle
immediately after the presentation completes. 'mode' is
- PresentCompleteModeFlip when the pixmap remains in-use even
- after the presentation completes. It will become idle no later
- than when the next PresentPixmap operation targeting the same
- window by any client completes. If the presentation operation
- was skipped because some later operation made it irrelevant,
- then 'mode' will be PresentCompleteModeSkip.
+ PresentCompleteModeSuboptimalCopy when the source pixmap
+ contents are copied but it would be possible to flip the
+ pixmap if the buffer format/modifier was different (options
+ given to PresentPixmap must contain PresentOptionSuboptimal).
+ 'mode' is PresentCompleteModeFlip when the pixmap remains in-use
+ even after the presentation completes. It will become idle no
+ later than when the next PresentPixmap operation targeting the
+ same window by any client completes. If the presentation
+ operation was skipped because some later operation made it
+ irrelevant, then 'mode' will be PresentCompleteModeSkip.

'serial' is the value provided in the generating PresentPixmap
request.
@@ -505,6 +516,9 @@ The name of this extension is "Present"

1.0: First published version

+ 1.2: Added PresentCompleteModeSuboptimalCopy flag and
+ PresentOptionSuboptimal option
+
❄ ❄ ❄ ❄ ❄ ❄ ❄


@@ -569,6 +583,7 @@ A.1 Common Types
1 PresentOptionAsync
2 PresentOptionCopy;
4 PresentOptionUST
+ 8 PresentOptionSuboptimal
└───

┌───
@@ -589,6 +604,7 @@ A.1 Common Types
0 PresentCompleteModeCopy
1 PresentCompleteModeFlip
2 PresentCompleteModeSkip
+ 3 PresentCompleteModeSuboptimalCopy
└───

┌───
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/m
Adam Jackson
2018-02-28 16:39:24 UTC
Permalink
Post by Daniel Stone
If the Complete event has this mode, the client is not using
the more optimal format/modifier for the buffer allocation. The
client must explicitely inform the server that it understands
this mode by adding the PresentOptionSuboptimal flag when calling
PresentPixmap.
Its main usage as of now is to allow clients to re-fetch DRI3
format modifiers as some modifiers might allow direct scanout.
Bump presentproto version to 1.2.
Merged:

To ssh://git.freedesktop.org/git/xorg/proto/xorgproto
29c53a2..751cf1e master -> master

Still need to wire xorgproto up to patchwork, it seems.

- ajax
_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mai
Daniel Stone
2018-02-28 01:19:46 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Enable DRI3 v1.2 now that all functions have been implemented and
that there is at least one backend implementing the driver hooks
(modesetting/glamor).

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
include/protocol-versions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 39cd2e909..7cab7cd5b 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -48,7 +48,7 @@

/* DRI3 */
#define SERVER_DRI3_MAJOR_VERSION 1
-#define SERVER_DRI3_MINOR_VERSION 0
+#define SERVER_DRI3_MINOR_VERSION 2

/* DMX */
#define SERVER_DMX_MAJOR_VERSION 2
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-d
Daniel Stone
2018-02-28 01:19:44 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Implement function added in DRI3 v1.1.

A newest version of libepoxy (>= 1.4.4) is required as earlier
versions use a problematic version of Khronos
EXT_image_dma_buf_import_modifiers spec.

v4: Only send scanout-supported modifiers if flipping is possible
v5: Fix memory corruption in XWayland (uninitialized pointer)

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 4 +
glamor/glamor.c | 25 +++++
glamor/glamor.h | 23 ++++
glamor/glamor_egl.c | 92 +++++++++++++++
glamor/glamor_priv.h | 1 +
glamor/meson.build | 4 +-
hw/kdrive/ephyr/meson.build | 1 +
hw/xfree86/common/xf86Mode.c | 1 +
hw/xfree86/drivers/modesetting/driver.c | 12 +-
hw/xfree86/drivers/modesetting/drmmode_display.c | 38 +++++++
hw/xfree86/drivers/modesetting/drmmode_display.h | 1 +
hw/xwayland/xwayland-glamor.c | 135 ++++++++++++++++++++---
hw/xwayland/xwayland.h | 9 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
meson.build | 4 +-
present/present.c | 38 +++++++
present/present.h | 3 +
18 files changed, 372 insertions(+), 24 deletions(-)

diff --git a/configure.ac b/configure.ac
index 392511541..8e247cdcf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2092,6 +2092,10 @@ if test "x$GLAMOR" = xyes; then
AC_DEFINE(GLAMOR, 1, [Build glamor])
PKG_CHECK_MODULES([GLAMOR], [epoxy])

+ PKG_CHECK_EXISTS(epoxy >= 1.4.4,
+ [AC_DEFINE(GLAMOR_HAS_EGL_QUERY_DMABUF, 1, [Have GLAMOR_HAS_EGL_QUERY_DMABUF])],
+ [])
+
PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no])
if test "x$GBM" = xyes; then
AC_DEFINE(GLAMOR_HAS_GBM, 1,
diff --git a/glamor/glamor.c b/glamor/glamor.c
index c890d0ce0..c7077dd84 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -793,6 +793,31 @@ glamor_supports_pixmap_import_export(ScreenPtr screen)
return glamor_priv->dri3_enabled;
}

+_X_EXPORT void
+glamor_set_drawable_modifiers_func(ScreenPtr screen,
+ GetDrawableModifiersFuncPtr func)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+ glamor_priv->get_drawable_modifiers = func;
+}
+
+_X_EXPORT Bool
+glamor_get_drawable_modifiers(DrawablePtr draw, CARD32 format,
+ CARD32 *num_modifiers, uint64_t **modifiers)
+{
+ struct glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(draw->pScreen);
+
+ if (glamor_priv->get_drawable_modifiers) {
+ return glamor_priv->get_drawable_modifiers(draw, format,
+ num_modifiers, modifiers);
+ }
+ *num_modifiers = 0;
+ *modifiers = NULL;
+ return TRUE;
+}
+
_X_EXPORT int
glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
uint32_t *strides, uint32_t *offsets,
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 8f8c31b45..5475aedbb 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -60,6 +60,11 @@ typedef enum glamor_pixmap_type {
GLAMOR_TEXTURE_ONLY,
} glamor_pixmap_type_t;

+typedef Bool (*GetDrawableModifiersFuncPtr) (DrawablePtr draw,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ uint64_t **modifiers);
+
#define GLAMOR_EGL_EXTERNAL_BUFFER 3
#define GLAMOR_USE_EGL_SCREEN (1 << 0)
#define GLAMOR_NO_DRI3 (1 << 1)
@@ -272,6 +277,24 @@ extern _X_EXPORT Bool glamor_back_pixmap_from_fd(PixmapPtr pixmap,
CARD16 stride,
CARD8 depth,
CARD8 bpp);
+
+extern _X_EXPORT Bool glamor_get_formats(ScreenPtr screen,
+ CARD32 *num_formats,
+ CARD32 **formats);
+
+extern _X_EXPORT Bool glamor_get_modifiers(ScreenPtr screen,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ uint64_t **modifiers);
+
+extern _X_EXPORT Bool glamor_get_drawable_modifiers(DrawablePtr draw,
+ CARD32 format,
+ CARD32 *num_modifiers,
+ uint64_t **modifiers);
+
+extern _X_EXPORT void glamor_set_drawable_modifiers_func(ScreenPtr screen,
+ GetDrawableModifiersFuncPtr func);
+
#ifdef GLAMOR_FOR_XORG

#define GLAMOR_EGL_MODULE_NAME "glamoregl"
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index cf2513491..c00fb3c1b 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -505,6 +505,95 @@ glamor_pixmap_from_fds(ScreenPtr screen,
return pixmap;
}

+_X_EXPORT Bool
+glamor_get_formats(ScreenPtr screen,
+ CARD32 *num_formats, CARD32 **formats)
+{
+#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLint num;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+ if (!glamor_egl->dmabuf_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, 0, NULL, &num)) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ if (num == 0) {
+ *num_formats = 0;
+ return TRUE;
+ }
+
+ *formats = calloc(num, sizeof(CARD32));
+ if (*formats == NULL) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufFormatsEXT(glamor_egl->display, num,
+ (EGLint *) *formats, &num)) {
+ *num_formats = 0;
+ free(*formats);
+ return FALSE;
+ }
+
+ *num_formats = num;
+ return TRUE;
+#else
+ *num_formats = 0;
+ return TRUE;
+#endif
+}
+
+_X_EXPORT Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+ CARD32 *num_modifiers, uint64_t **modifiers)
+{
+#ifdef GLAMOR_HAS_EGL_QUERY_DMABUF
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLint num;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));
+
+ if (!glamor_egl->dmabuf_capable)
+ return FALSE;
+
+ if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, 0, NULL,
+ NULL, &num)) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ if (num == 0) {
+ *num_modifiers = 0;
+ return TRUE;
+ }
+
+ *modifiers = calloc(num, sizeof(uint64_t));
+ if (*modifiers == NULL) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ if (!eglQueryDmaBufModifiersEXT(glamor_egl->display, format, num,
+ (EGLuint64KHR *) *modifiers, NULL, &num)) {
+ *num_modifiers = 0;
+ free(*modifiers);
+ return FALSE;
+ }
+
+ *num_modifiers = num;
+ return TRUE;
+#else
+ *num_modifiers = 0;
+ return TRUE;
+#endif
+}
+
static Bool
glamor_egl_destroy_pixmap(PixmapPtr pixmap)
{
@@ -626,6 +715,9 @@ static dri3_screen_info_rec glamor_dri3_info = {
.open_client = glamor_dri3_open_client,
.pixmap_from_fds = glamor_pixmap_from_fds,
.fds_from_pixmap = glamor_egl_fds_from_pixmap,
+ .get_formats = glamor_get_formats,
+ .get_modifiers = glamor_get_modifiers,
+ .get_drawable_modifiers = glamor_get_drawable_modifiers,
};
#endif /* DRI3 */

diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
index 2344066cb..3fff6396c 100644
--- a/glamor/glamor_priv.h
+++ b/glamor/glamor_priv.h
@@ -281,6 +281,7 @@ typedef struct glamor_screen_private {
int radial_max_nstops;

struct glamor_saved_procs saved_procs;
+ GetDrawableModifiersFuncPtr get_drawable_modifiers;
int flags;
ScreenPtr screen;
int dri3_enabled;
diff --git a/glamor/meson.build b/glamor/meson.build
index 0b963275e..268af593e 100644
--- a/glamor/meson.build
+++ b/glamor/meson.build
@@ -38,12 +38,14 @@ if build_xv
srcs_glamor += 'glamor_xv.c'
endif

+epoxy_dep = dependency('epoxy')
+
glamor = static_library('glamor',
srcs_glamor,
include_directories: inc,
dependencies: [
common_dep,
- dependency('epoxy'),
+ epoxy_dep,
],
)

diff --git a/hw/kdrive/ephyr/meson.build b/hw/kdrive/ephyr/meson.build
index 31e167387..b48afd612 100644
--- a/hw/kdrive/ephyr/meson.build
+++ b/hw/kdrive/ephyr/meson.build
@@ -30,6 +30,7 @@ if build_glamor
xephyr_glamor += glamor
xephyr_glamor += glamor_egl_stubs
xephyr_dep += dependency('x11-xcb')
+ xephyr_dep += epoxy_dep
endif

if build_xv
diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c
index 40d09a9f4..484cde7ab 100644
--- a/hw/xfree86/common/xf86Mode.c
+++ b/hw/xfree86/common/xf86Mode.c
@@ -86,6 +86,7 @@

#include <X11/X.h>
#include "xf86Modes.h"
+#include "xf86Crtc.h"
#include "os.h"
#include "servermd.h"
#include "globals.h"
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index 88a42257c..f20284bb0 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1601,15 +1601,11 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv)

fbPictureInit(pScreen, NULL, 0);

-#ifdef GLAMOR_HAS_GBM
- if (ms->drmmode.glamor) {
- if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Failed to initialize glamor at ScreenInit() time.\n");
- return FALSE;
- }
+ if (drmmode_init(pScrn, &ms->drmmode) == FALSE) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to initialize glamor at ScreenInit() time.\n");
+ return FALSE;
}
-#endif

if (ms->drmmode.shadow_enable && !msShadowInit(pScreen)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "shadow fb init failed\n");
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 785849ef9..721d0d4c3 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -45,6 +45,7 @@
#include <xf86drm.h>
#include "xf86Crtc.h"
#include "drmmode_display.h"
+#include "present.h"

#include <cursorstr.h>

@@ -175,6 +176,24 @@ get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
*modifiers = ret;
return count_modifiers;
}
+
+static Bool
+get_drawable_modifiers(DrawablePtr draw, uint32_t format,
+ uint32_t *num_modifiers, uint64_t **modifiers)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
+ modesettingPtr ms = modesettingPTR(scrn);
+
+ if (!present_can_window_flip((WindowPtr) draw) ||
+ !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
+ *num_modifiers = 0;
+ *modifiers = NULL;
+ return TRUE;
+ }
+
+ *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
+ return TRUE;
+}
#endif

static Bool
@@ -3116,6 +3135,25 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
return TRUE;
}

+Bool
+drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
+{
+#ifdef GLAMOR_HAS_GBM
+ ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
+
+ if (drmmode->glamor) {
+ if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
+ return FALSE;
+ }
+#ifdef GBM_BO_WITH_MODIFIERS
+ glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
+#endif
+ }
+#endif
+
+ return TRUE;
+}
+
void
drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
{
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 607fe8179..ee59711cb 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -263,6 +263,7 @@ Bool drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
void drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode);

extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp);
+extern Bool drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y);
extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw);
extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 774a18893..72e2625fb 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -407,19 +407,6 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
static void
xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
{
- struct xwl_screen *xwl_screen = data;
-
- switch (format) {
- case WL_DRM_FORMAT_ARGB8888:
- xwl_screen->formats |= XWL_FORMAT_ARGB8888;
- break;
- case WL_DRM_FORMAT_XRGB8888:
- xwl_screen->formats |= XWL_FORMAT_XRGB8888;
- break;
- case WL_DRM_FORMAT_RGB565:
- xwl_screen->formats |= XWL_FORMAT_RGB565;
- break;
- }
}

static void
@@ -446,6 +433,54 @@ static const struct wl_drm_listener xwl_drm_listener = {
xwl_drm_handle_capabilities
};

+static void
+xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+ uint32_t format)
+{
+}
+
+static void
+xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
+ uint32_t format, uint32_t modifier_hi,
+ uint32_t modifier_lo)
+{
+ struct xwl_screen *xwl_screen = data;
+ struct xwl_format *xwl_format = NULL;
+ int i;
+
+ for (i = 0; i < xwl_screen->num_formats; i++) {
+ if (xwl_screen->formats[i].format == format) {
+ xwl_format = &xwl_screen->formats[i];
+ break;
+ }
+ }
+
+ if (xwl_format == NULL) {
+ xwl_screen->num_formats++;
+ xwl_screen->formats = realloc(xwl_screen->formats,
+ xwl_screen->num_formats * sizeof(*xwl_format));
+ if (!xwl_screen->formats)
+ return;
+ xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1];
+ xwl_format->format = format;
+ xwl_format->num_modifiers = 0;
+ xwl_format->modifiers = NULL;
+ }
+
+ xwl_format->num_modifiers++;
+ xwl_format->modifiers = realloc(xwl_format->modifiers,
+ xwl_format->num_modifiers * sizeof(uint64_t));
+ if (!xwl_format->modifiers)
+ return;
+ xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo;
+ xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32;
+}
+
+static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
+ .format = xwl_dmabuf_handle_format,
+ .modifier = xwl_dmabuf_handle_modifier
+};
+
Bool
xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
uint32_t id, uint32_t version)
@@ -470,6 +505,7 @@ xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,

xwl_screen->dmabuf =
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+ zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);

return TRUE;
}
@@ -678,12 +714,85 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
#endif
}

+_X_EXPORT Bool
+glamor_get_formats(ScreenPtr screen,
+ CARD32 *num_formats, CARD32 **formats)
+{
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ int i;
+
+ if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
+ return FALSE;
+
+ if (xwl_screen->num_formats == 0) {
+ *num_formats = 0;
+ return TRUE;
+ }
+
+ *formats = calloc(xwl_screen->num_formats, sizeof(CARD32));
+ if (*formats == NULL) {
+ *num_formats = 0;
+ return FALSE;
+ }
+
+ for (i = 0; i < xwl_screen->num_formats; i++)
+ (*formats)[i] = xwl_screen->formats[i].format;
+ *num_formats = xwl_screen->num_formats;
+
+ return TRUE;
+}
+
+_X_EXPORT Bool
+glamor_get_modifiers(ScreenPtr screen, CARD32 format,
+ CARD32 *num_modifiers, uint64_t **modifiers)
+{
+ struct xwl_screen *xwl_screen = xwl_screen_get(screen);
+ struct xwl_format *xwl_format = NULL;
+ int i;
+
+ if (!xwl_screen->dmabuf_capable || !xwl_screen->dmabuf)
+ return FALSE;
+
+ if (xwl_screen->num_formats == 0) {
+ *num_modifiers = 0;
+ return TRUE;
+ }
+
+ for (i = 0; i < xwl_screen->num_formats; i++) {
+ if (xwl_screen->formats[i].format == format) {
+ xwl_format = &xwl_screen->formats[i];
+ break;
+ }
+ }
+
+ if (!xwl_format) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t));
+ if (*modifiers == NULL) {
+ *num_modifiers = 0;
+ return FALSE;
+ }
+
+ for (i = 0; i < xwl_format->num_modifiers; i++)
+ (*modifiers)[i] = xwl_format->modifiers[i];
+ *num_modifiers = xwl_format->num_modifiers;
+
+ return TRUE;
+}
+
+
static dri3_screen_info_rec xwl_dri3_info = {
.version = 2,
.open = NULL,
.pixmap_from_fds = glamor_pixmap_from_fds,
.fds_from_pixmap = glamor_fds_from_pixmap,
.open_client = xwl_dri3_open_client,
+ .get_formats = glamor_get_formats,
+ .get_modifiers = glamor_get_modifiers,
+ .get_drawable_modifiers = glamor_get_drawable_modifiers,
};

Bool
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index be95bab55..36ebeaa83 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -49,6 +49,12 @@
#include "xdg-output-unstable-v1-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"

+struct xwl_format {
+ uint32_t format;
+ int num_modifiers;
+ uint64_t *modifiers;
+};
+
struct xwl_screen {
int width;
int height;
@@ -100,7 +106,8 @@ struct xwl_screen {
int drm_authenticated;
struct wl_drm *drm;
struct zwp_linux_dmabuf_v1 *dmabuf;
- uint32_t formats;
+ uint32_t num_formats;
+ struct xwl_format *formats;
uint32_t capabilities;
void *egl_display, *egl_context;
struct gbm_device *gbm;
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index ea932c46d..58585724c 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -500,6 +500,9 @@
/* Glamor can retrieve supported DRM formats/modifiers */
#undef GLAMOR_HAS_DRM_MODIFIERS

+/* Glamor can use eglQueryDmaBuf* functions */
+#undef GLAMOR_HAS_EGL_QUERY_DMABUF
+
/* byte order */
#undef X_BYTE_ORDER

diff --git a/include/meson.build b/include/meson.build
index 88ced768f..b61231612 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -80,6 +80,8 @@ conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
conf_data.set('GLAMOR_HAS_DRM_MODIFIERS',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.83'))
+conf_data.set('GLAMOR_HAS_EGL_QUERY_DMABUF',
+ epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.4.4'))
conf_data.set('GLXEXT', build_glx)
conf_data.set('GLAMOR', build_glamor)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
diff --git a/meson.build b/meson.build
index 2477bb931..ad84d5ecd 100644
--- a/meson.build
+++ b/meson.build
@@ -262,9 +262,11 @@ else
build_glamor = get_option('glamor') == 'true'
endif

-gbm_dep = dependency('', required:false)
+gbm_dep = dependency('', required: false)
+epoxy_dep = dependency('', required: false)
if build_glamor
gbm_dep = dependency('gbm', version: '>= 10.2', required: false)
+ epoxy_dep = dependency('epoxy', required: false)
endif

# XXX: Add more sha1 options, because Linux is about choice
diff --git a/present/present.c b/present/present.c
index 42e5fb4fc..080cafcba 100644
--- a/present/present.c
+++ b/present/present.c
@@ -614,6 +614,44 @@ present_check_flip_window (WindowPtr window)
}
}

+Bool
+present_can_window_flip(WindowPtr window)
+{
+ ScreenPtr screen = window->drawable.pScreen;
+ PixmapPtr window_pixmap;
+ WindowPtr root = screen->root;
+ present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+
+ if (!screen_priv)
+ return FALSE;
+
+ if (!screen_priv->info)
+ return FALSE;
+
+ /* Check to see if the driver supports flips at all */
+ if (!screen_priv->info->flip)
+ return FALSE;
+
+ /* Make sure the window hasn't been redirected with Composite */
+ window_pixmap = screen->GetWindowPixmap(window);
+ if (window_pixmap != screen->GetScreenPixmap(screen) &&
+ window_pixmap != screen_priv->flip_pixmap &&
+ window_pixmap != present_flip_pending_pixmap(screen))
+ return FALSE;
+
+ /* Check for full-screen window */
+ if (!RegionEqual(&window->clipList, &root->winSize)) {
+ return FALSE;
+ }
+
+ /* Does the window match the pixmap exactly? */
+ if (window->drawable.x != 0 || window->drawable.y != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/*
* Called when the wait fence is triggered; just gets the current msc/ust and
* calls present_execute again. That will re-check the fence and pend the
diff --git a/present/present.h b/present/present.h
index 6542dc385..ade838bda 100644
--- a/present/present.h
+++ b/present/present.h
@@ -135,4 +135,7 @@ typedef void (*present_complete_notify_proc)(WindowPtr window,
extern _X_EXPORT void
present_register_complete_notify(present_complete_notify_proc proc);

+extern _X_EXPORT Bool
+present_can_window_flip(WindowPtr window);
+
#endif /* _PRESENT_H_ */
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info:
Daniel Stone
2018-02-28 01:19:39 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

To make sure we also use the same primary plane and to avoid
mixing uses of two APIs, it is better to always use the atomic
modesetting API when possible.

v2: Don't use mode_output->connector_id

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 262 +++++++++++++++++++----
hw/xfree86/drivers/modesetting/drmmode_display.h | 30 ++-
hw/xfree86/drivers/modesetting/pageflip.c | 2 +-
hw/xfree86/drivers/modesetting/present.c | 3 +-
4 files changed, 252 insertions(+), 45 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index ee9f4d724..3e3613a98 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -267,16 +267,100 @@ plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
info->prop_id, val);
return (ret <= 0) ? -1 : 0;
}
+
+static int
+crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+ enum drmmode_crtc_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+
+static int
+connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
+ enum drmmode_connector_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+
+static int
+drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
+{
+ return memcmp(kmode, other, sizeof(*kmode));
+}
+
+static int
+drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_mode_ptr mode;
+ int ret;
+
+ if (drmmode_crtc->current_mode &&
+ drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
+ return 0;
+
+ mode = calloc(sizeof(drmmode_mode_rec), 1);
+ if (!mode)
+ return -1;
+
+ mode->mode_info = mode_info;
+ ret = drmModeCreatePropertyBlob(ms->fd,
+ &mode->mode_info,
+ sizeof(mode->mode_info),
+ &mode->blob_id);
+ drmmode_crtc->current_mode = mode;
+ xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
+
+ return ret;
+}
+
+static void
+drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ if (mode->blob_id)
+ drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
+ xorg_list_del(&mode->entry);
+ free(mode);
+}
#endif

+static void
+drmmode_ConvertToKMode(ScrnInfoPtr scrn,
+ drmModeModeInfo * kmode, DisplayModePtr mode);
+
int
-drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
int x, int y, uint32_t flags, void *data)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
- int ret = 0;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ int output_count = 0;
+ uint32_t *output_ids = NULL;
+ drmModeModeInfo kmode;
+ int i, ret = 0;
+
+ if (mode)
+ drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);

#ifdef GLAMOR_HAS_DRM_ATOMIC
if (ms->atomic_modeset) {
@@ -285,12 +369,56 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
if (!req)
return 1;

+ if (mode) {
+ ret = drm_mode_ensure_blob(crtc, kmode);
+
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ if (output->crtc != crtc)
+ continue;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
+
+ if (drmmode_output->dpms == DPMSModeOn) {
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_ACTIVE, 1);
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_MODE_ID,
+ drmmode_crtc->current_mode->blob_id);
+ ret |= connector_add_prop(req, drmmode_output,
+ DRMMODE_CONNECTOR_CRTC_ID,
+ drmmode_crtc->mode_crtc->crtc_id);
+ } else {
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_ACTIVE, 0);
+ ret |= crtc_add_prop(req, drmmode_crtc,
+ DRMMODE_CRTC_MODE_ID, 0);
+ ret |= connector_add_prop(req, drmmode_output,
+ DRMMODE_CONNECTOR_CRTC_ID, 0);
+ }
+ }
+ }
+
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
fb_id);
ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
drmmode_crtc->mode_crtc->crtc_id);
- ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
- ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
+ drmmode->front_bo.width << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
+ drmmode->front_bo.height << 16);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
+ drmmode->front_bo.width);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
+ drmmode->front_bo.height);

if (ret == 0)
ret = drmModeAtomicCommit(ms->fd, req, flags, data);
@@ -300,7 +428,29 @@ drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
}
#endif

- return 0;
+ output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
+ if (!output_ids)
+ return -1;
+
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ if (output->crtc != crtc)
+ continue;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
+ output_ids[output_count] = drmmode_output->output_id;
+ output_count++;
+ }
+
+ ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+ fb_id, x, y, output_ids, output_count, &kmode);
+
+ free(output_ids);
+ return ret;
}


@@ -858,23 +1008,16 @@ static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
{
- ScrnInfoPtr pScrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int saved_x, saved_y;
Rotation saved_rotation;
DisplayModeRec saved_mode;
- uint32_t *output_ids = NULL;
- int output_count = 0;
Bool ret = TRUE;
int i;
uint32_t fb_id = 0;
- drmModeModeInfo kmode;
-
- output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
- if (!output_ids)
- return FALSE;
+ uint32_t flags = 0;

saved_mode = crtc->mode;
saved_x = crtc->x;
@@ -887,29 +1030,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
crtc->y = y;
crtc->rotation = rotation;

- for (i = 0; i < xf86_config->num_output; i++) {
- xf86OutputPtr output = xf86_config->output[i];
- drmmode_output_private_ptr drmmode_output;
-
- if (output->crtc != crtc)
- continue;
-
- drmmode_output = output->driver_private;
- if (drmmode_output->output_id == -1)
- continue;
- output_ids[output_count] =
- drmmode_output->mode_output->connector_id;
- output_count++;
- }
-
if (!xf86CrtcRotate(crtc)) {
goto done;
}
+
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);

- drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
-
fb_id = drmmode->fb_id;
if (drmmode_crtc->prime_pixmap) {
if (!drmmode->reverse_prime_offload_mode) {
@@ -927,12 +1054,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
}

if (fb_id == 0) {
- ret = drmModeAddFB(drmmode->fd,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->depth, drmmode->kbpp,
- drmmode_bo_get_pitch(&drmmode->front_bo),
- drmmode_bo_get_handle(&drmmode->front_bo),
- &drmmode->fb_id);
+ ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
+ &drmmode->fb_id);
if (ret < 0) {
ErrorF("failed to add fb %d\n", ret);
ret = FALSE;
@@ -941,8 +1064,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
fb_id = drmmode->fb_id;
}

- if (drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
- fb_id, x, y, output_ids, output_count, &kmode)) {
+ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
+ if (drmmode_crtc_set_fb(crtc, mode, fb_id, x, y, flags, NULL)) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"failed to set mode: %s\n", strerror(errno));
ret = FALSE;
@@ -983,8 +1106,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
} else
crtc->active = TRUE;

- free(output_ids);
-
return ret;
}

@@ -1355,9 +1476,15 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)
{
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_mode_ptr iterator, next;
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;

drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
+ drm_mode_destroy(crtc, iterator);
+ }
+#endif
}

static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
@@ -1437,6 +1564,12 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
[DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
[DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
[DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
+ [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
+ [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
+ [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
+ [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
+ [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
};
drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];

@@ -1524,19 +1657,37 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
xf86CrtcPtr crtc;
drmmode_crtc_private_ptr drmmode_crtc;
modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmModeObjectPropertiesPtr props;
+ static const drmmode_prop_info_rec crtc_props[] = {
+ [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
+ [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
+ };
+#endif

crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
if (crtc == NULL)
return 0;
-
drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
+ crtc->driver_private = drmmode_crtc;
drmmode_crtc->mode_crtc =
drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
drmmode_crtc->drmmode = drmmode;
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
- crtc->driver_private = drmmode_crtc;
+ xorg_list_init(&drmmode_crtc->mode_list);

#ifdef GLAMOR_HAS_DRM_ATOMIC
+ props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
+ DRM_MODE_OBJECT_CRTC);
+ if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
+ DRMMODE_CRTC__COUNT, 0)) {
+ xf86CrtcDestroy(crtc);
+ return 0;
+ }
+
+ drmmode_prop_info_update(drmmode, drmmode_crtc->props,
+ DRMMODE_CRTC__COUNT, props);
+ drmModeFreeObjectProperties(props);
drmmode_crtc_create_planes(crtc, num);
#endif

@@ -1680,6 +1831,7 @@ koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
return idx;
}

+#ifndef GLAMOR_HAS_DRM_ATOMIC
static int
koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
int type, const char *name)
@@ -1688,6 +1840,7 @@ koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,

return (idx > -1) ? koutput->props[idx] : -1;
}
+#endif

static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
@@ -1859,13 +2012,19 @@ drmmode_output_dpms(xf86OutputPtr output, int mode)
drmmode_output_private_ptr drmmode_output = output->driver_private;
xf86CrtcPtr crtc = output->crtc;
drmModeConnectorPtr koutput = drmmode_output->mode_output;
+#ifndef GLAMOR_HAS_DRM_ATOMIC
drmmode_ptr drmmode = drmmode_output->drmmode;
+#endif

if (!koutput)
return;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_output->dpms = mode;
+#else
drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
drmmode_output->dpms_enum_id, mode);
+#endif

if (crtc) {
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
@@ -2214,6 +2373,13 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
Bool nonDesktop = FALSE;
drmModePropertyBlobPtr path_blob = NULL;
const char *s;
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmModeObjectPropertiesPtr props;
+ static const drmmode_prop_info_rec connector_props[] = {
+ [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
+ };
+#endif
+
koutput =
drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
if (!koutput)
@@ -2301,8 +2467,20 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
/* work out the possible clones later */
output->possible_clones = 0;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (!drmmode_prop_info_copy(drmmode_output->props_connector, connector_props,
+ DRMMODE_CONNECTOR__COUNT, 0)) {
+ goto out_free_encoders;
+ }
+ props = drmModeObjectGetProperties(drmmode->fd,
+ drmmode_output->output_id,
+ DRM_MODE_OBJECT_CONNECTOR);
+ drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
+ DRMMODE_CONNECTOR__COUNT, props);
+#else
drmmode_output->dpms_enum_id =
koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM, "DPMS");
+#endif

if (dynamic)
output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 177ccabd7..e5f3542c5 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -42,6 +42,12 @@ enum drmmode_plane_property {
DRMMODE_PLANE_CRTC_ID,
DRMMODE_PLANE_SRC_X,
DRMMODE_PLANE_SRC_Y,
+ DRMMODE_PLANE_SRC_W,
+ DRMMODE_PLANE_SRC_H,
+ DRMMODE_PLANE_CRTC_X,
+ DRMMODE_PLANE_CRTC_Y,
+ DRMMODE_PLANE_CRTC_W,
+ DRMMODE_PLANE_CRTC_H,
DRMMODE_PLANE__COUNT
};

@@ -52,6 +58,17 @@ enum drmmode_plane_type {
DRMMODE_PLANE_TYPE__COUNT
};

+enum drmmode_connector_property {
+ DRMMODE_CONNECTOR_CRTC_ID,
+ DRMMODE_CONNECTOR__COUNT
+};
+
+enum drmmode_crtc_property {
+ DRMMODE_CRTC_ACTIVE,
+ DRMMODE_CRTC_MODE_ID,
+ DRMMODE_CRTC__COUNT
+};
+
typedef struct {
uint32_t width;
uint32_t height;
@@ -119,6 +136,12 @@ typedef struct {
drmmode_prop_enum_info_rec *enum_values;
} drmmode_prop_info_rec, *drmmode_prop_info_ptr;

+typedef struct {
+ drmModeModeInfo mode_info;
+ uint32_t blob_id;
+ struct xorg_list entry;
+} drmmode_mode_rec, *drmmode_mode_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -128,8 +151,10 @@ typedef struct {
Bool cursor_up;
uint16_t lut_r[256], lut_g[256], lut_b[256];

+ drmmode_prop_info_rec props[DRMMODE_CRTC__COUNT];
drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
uint32_t plane_id;
+ drmmode_mode_ptr current_mode;

drmmode_bo rotate_bo;
unsigned rotate_fb_id;
@@ -151,6 +176,7 @@ typedef struct {
/** @} */

Bool need_modeset;
+ struct xorg_list mode_list;

Bool enable_flipping;
Bool flipping_active;
@@ -171,8 +197,10 @@ typedef struct {
drmModePropertyBlobPtr edid_blob;
drmModePropertyBlobPtr tile_blob;
int dpms_enum_id;
+ int dpms;
int num_props;
drmmode_prop_ptr props;
+ drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT];
int enc_mask;
int enc_clone_mask;
} drmmode_output_private_rec, *drmmode_output_private_ptr;
@@ -242,7 +270,7 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,

void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);

-int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, DisplayModePtr mode, uint32_t fb_id,
int x, int y, uint32_t flags, void *data);

#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index 027ebfe42..26738f928 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -168,7 +168,7 @@ do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
#ifdef GLAMOR_HAS_DRM_ATOMIC
if (ms->atomic_modeset) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
- return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+ return drmmode_crtc_set_fb(crtc, NULL, ms->drmmode.fb_id, 0, 0, flags,
(void *) (uintptr_t) seq);
}
#endif
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index c01be3486..4a01d19ea 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -248,7 +248,8 @@ ms_present_check_flip(RRCrtcPtr crtc,
return FALSE;

/* Check stride, can't change that on flip */
- if (pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
+ if (!ms->atomic_modeset &&
+ pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
return FALSE;

/* Make sure there's a bo we can get to */
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo
Daniel Stone
2018-02-28 01:19:45 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Using modifier might allow the driver to use a more optimal format
(e.g. tiled/compressed). Let's try to use those if possible.

v2: Don't filter out multi-plane modifiers

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
glamor/glamor_egl.c | 32 ++++++++++++++++++++++++++------
hw/xwayland/xwayland-glamor.c | 22 +++++++++++++++++++---
2 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index c00fb3c1b..ca368c15c 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -256,6 +256,7 @@ glamor_make_pixmap_exportable(PixmapPtr pixmap)
glamor_get_pixmap_private(pixmap);
unsigned width = pixmap->drawable.width;
unsigned height = pixmap->drawable.height;
+ uint32_t format;
struct gbm_bo *bo;
PixmapPtr exported;
GCPtr scratch_gc;
@@ -270,14 +271,33 @@ glamor_make_pixmap_exportable(PixmapPtr pixmap)
return FALSE;
}

- bo = gbm_bo_create(glamor_egl->gbm, width, height,
- (pixmap->drawable.depth == 30) ?
- GBM_FORMAT_ARGB2101010 : GBM_FORMAT_ARGB8888,
+ if (pixmap->drawable.depth == 30)
+ format = GBM_FORMAT_ARGB2101010;
+ else
+ format = GBM_FORMAT_ARGB8888;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+ if (glamor_egl->dmabuf_capable) {
+ uint32_t num_modifiers;
+ uint64_t *modifiers = NULL;
+
+ glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
+
+ bo = gbm_bo_create_with_modifiers(glamor_egl->gbm, width, height,
+ format, modifiers, num_modifiers);
+ free(modifiers);
+ }
+ else
+#endif
+ {
+ bo = gbm_bo_create(glamor_egl->gbm, width, height, format,
#ifdef GLAMOR_HAS_GBM_LINEAR
- (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
- GBM_BO_USE_LINEAR : 0) |
+ (pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED ?
+ GBM_BO_USE_LINEAR : 0) |
#endif
- GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
+ GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
+ }
+
if (!bo) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Failed to make %dx%dx%dbpp GBM bo\n",
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 72e2625fb..b961695d7 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -227,14 +227,30 @@ xwl_glamor_create_pixmap(ScreenPtr screen,
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
struct gbm_bo *bo;
+ uint32_t format;

if (width > 0 && height > 0 && depth >= 15 &&
(hint == 0 ||
hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP ||
hint == CREATE_PIXMAP_USAGE_SHARED)) {
- bo = gbm_bo_create(xwl_screen->gbm, width, height,
- gbm_format_for_depth(depth),
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ format = gbm_format_for_depth(depth);
+
+#ifdef GBM_BO_WITH_MODIFIERS
+ if (xwl_screen->dmabuf_capable) {
+ uint32_t num_modifiers;
+ uint64_t *modifiers = NULL;
+
+ glamor_get_modifiers(screen, format, &num_modifiers, &modifiers);
+ bo = gbm_bo_create_with_modifiers(xwl_screen->gbm, width, height,
+ format, modifiers, num_modifiers);
+ free(modifiers);
+ }
+ else
+#endif
+ {
+ bo = gbm_bo_create(xwl_screen->gbm, width, height, format,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ }

if (bo)
return xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xo
Daniel Stone
2018-02-28 01:19:37 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

In order to flip between compressed and uncompressed buffers -
something drmModePageFlip explicitly bans us from doing - we need
to port use the atomic modesetting API. It's only 'fake' atomic
though given we still commit for each CRTC separately and
CRTC and connector properties are not set with the atomic API.

The helper functions to retrieve DRM properties have been borrowed
from Weston.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 3 +
hw/xfree86/drivers/modesetting/driver.c | 6 +
hw/xfree86/drivers/modesetting/driver.h | 1 +
hw/xfree86/drivers/modesetting/drmmode_display.c | 374 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 36 +++
hw/xfree86/drivers/modesetting/pageflip.c | 22 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
8 files changed, 443 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index cef9503d7..46662867f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2106,6 +2106,9 @@ if test "x$GLAMOR" = xyes; then
fi
fi

+ PKG_CHECK_EXISTS(libdrm >= 2.4.62,
+ [AC_DEFINE(GLAMOR_HAS_DRM_ATOMIC, 1, [libdrm supports atomic API])],
+ [])
PKG_CHECK_EXISTS(libdrm >= 2.4.74,
[AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
[])
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index ec2aa9a27..88a42257c 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1018,6 +1018,12 @@ PreInit(ScrnInfoPtr pScrn, int flags)
}
#endif

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ ret |= drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+ ms->atomic_modeset = (ret == 0);
+#endif
+
if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
goto fail;
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
index fe835918b..ed32239db 100644
--- a/hw/xfree86/drivers/modesetting/driver.h
+++ b/hw/xfree86/drivers/modesetting/driver.h
@@ -105,6 +105,7 @@ typedef struct _modesettingRec {
* Page flipping stuff.
* @{
*/
+ Bool atomic_modeset;
/** @} */

DamagePtr damage;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index bfc8c50db..8674c2c16 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -75,6 +75,233 @@ drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name
return ret;
}

+static uint64_t
+drmmode_prop_get_value(drmmode_prop_info_ptr info,
+ drmModeObjectPropertiesPtr props,
+ uint64_t def)
+{
+ unsigned int i;
+
+ if (info->prop_id == 0)
+ return def;
+
+ for (i = 0; i < props->count_props; i++) {
+ unsigned int j;
+
+ if (props->props[i] != info->prop_id)
+ continue;
+
+ /* Simple (non-enum) types can return the value directly */
+ if (info->num_enum_values == 0)
+ return props->prop_values[i];
+
+ /* Map from raw value to enum value */
+ for (j = 0; j < info->num_enum_values; j++) {
+ if (!info->enum_values[j].valid)
+ continue;
+ if (info->enum_values[j].value != props->prop_values[i])
+ continue;
+
+ return j;
+ }
+ }
+
+ return def;
+}
+
+static uint32_t
+drmmode_prop_info_update(drmmode_ptr drmmode,
+ drmmode_prop_info_ptr info,
+ unsigned int num_infos,
+ drmModeObjectProperties *props)
+{
+ drmModePropertyRes *prop;
+ uint32_t valid_mask = 0;
+ unsigned i, j;
+
+ assert(num_infos <= 32 && "update return type");
+
+ for (i = 0; i < props->count_props; i++) {
+ Bool props_incomplete = FALSE;
+ unsigned int k;
+
+ for (j = 0; j < num_infos; j++) {
+ if (info[j].prop_id == props->props[i])
+ break;
+ if (!info[j].prop_id)
+ props_incomplete = TRUE;
+ }
+
+ /* We've already discovered this property. */
+ if (j != num_infos)
+ continue;
+
+ /* We haven't found this property ID, but as we've already
+ * found all known properties, we don't need to look any
+ * further. */
+ if (!props_incomplete)
+ break;
+
+ prop = drmModeGetProperty(drmmode->fd, props->props[i]);
+ if (!prop)
+ continue;
+
+ for (j = 0; j < num_infos; j++) {
+ if (!strcmp(prop->name, info[j].name))
+ break;
+ }
+
+ /* We don't know/care about this property. */
+ if (j == num_infos) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ info[j].prop_id = props->props[i];
+ valid_mask |= 1U << j;
+
+ if (info[j].num_enum_values == 0) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
+ "expected property %s to be an enum,"
+ " but it is not; ignoring\n", prop->name);
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ for (k = 0; k < info[j].num_enum_values; k++) {
+ int l;
+
+ if (info[j].enum_values[k].valid)
+ continue;
+
+ for (l = 0; l < prop->count_enums; l++) {
+ if (!strcmp(prop->enums[l].name,
+ info[j].enum_values[k].name))
+ break;
+ }
+
+ if (l == prop->count_enums)
+ continue;
+
+ info[j].enum_values[k].valid = TRUE;
+ info[j].enum_values[k].value = prop->enums[l].value;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+
+ return valid_mask;
+}
+
+static Bool
+drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
+ const drmmode_prop_info_rec *src,
+ unsigned int num_props,
+ Bool copy_prop_id)
+{
+ unsigned int i;
+
+ memcpy(dst, src, num_props * sizeof(*dst));
+
+ for (i = 0; i < num_props; i++) {
+ unsigned int j;
+
+ if (copy_prop_id)
+ dst[i].prop_id = src[i].prop_id;
+ else
+ dst[i].prop_id = 0;
+
+ if (src[i].num_enum_values == 0)
+ continue;
+
+ dst[i].enum_values =
+ malloc(src[i].num_enum_values *
+ sizeof(*dst[i].enum_values));
+ if (!dst[i].enum_values)
+ goto err;
+
+ memcpy(dst[i].enum_values, src[i].enum_values,
+ src[i].num_enum_values * sizeof(*dst[i].enum_values));
+
+ for (j = 0; j < dst[i].num_enum_values; j++)
+ dst[i].enum_values[j].valid = FALSE;
+ }
+
+ return TRUE;
+
+err:
+ while (i--)
+ free(dst[i].enum_values);
+ free(dst);
+ return FALSE;
+}
+
+static void
+drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
+{
+ int i;
+
+ for (i = 0; i < num_props; i++)
+ free(info[i].enum_values);
+}
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static int
+plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
+ enum drmmode_plane_property prop, uint64_t val)
+{
+ drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
+ int ret;
+
+ if (!info)
+ return -1;
+
+ ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
+ info->prop_id, val);
+ return (ret <= 0) ? -1 : 0;
+}
+#endif
+
+int
+drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+ int x, int y, uint32_t flags, void *data)
+{
+ modesettingPtr ms = modesettingPTR(crtc->scrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ int ret = 0;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (ms->atomic_modeset) {
+ drmModeAtomicReq *req = drmModeAtomicAlloc();
+
+ if (!req)
+ return 1;
+
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
+ fb_id);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
+ drmmode_crtc->mode_crtc->crtc_id);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x);
+ ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y);
+
+ if (ret == 0)
+ ret = drmModeAtomicCommit(ms->fd, req, flags, data);
+
+ drmModeAtomicFree(req);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+
int
drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
{
@@ -1076,6 +1303,14 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
}
}

+static void
+drmmode_crtc_destroy(xf86CrtcPtr crtc)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+}
+
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.dpms = drmmode_crtc_dpms,
.set_mode_major = drmmode_set_mode_major,
@@ -1086,7 +1321,7 @@ static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.load_cursor_argb_check = drmmode_load_cursor_argb_check,

.gamma_set = drmmode_crtc_gamma_set,
- .destroy = NULL, /* XXX */
+ .destroy = drmmode_crtc_destroy,
.set_scanout_pixmap = drmmode_set_scanout_pixmap,
.shadow_allocate = drmmode_shadow_allocate,
.shadow_create = drmmode_shadow_create,
@@ -1104,6 +1339,136 @@ drmmode_crtc_vblank_pipe(int crtc_id)
return 0;
}

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+static Bool
+is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c;
+
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr iter = xf86_config->crtc[c];
+ drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
+ if (drmmode_crtc->plane_id == plane_id)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ drmModePlaneRes *kplane_res;
+ drmModePlane *kplane;
+ drmModeObjectProperties *props;
+ uint32_t i, type;
+ int current_crtc, best_plane = 0;
+
+ static drmmode_prop_enum_info_rec plane_type_enums[] = {
+ [DRMMODE_PLANE_TYPE_PRIMARY] = {
+ .name = "Primary",
+ },
+ [DRMMODE_PLANE_TYPE_OVERLAY] = {
+ .name = "Overlay",
+ },
+ [DRMMODE_PLANE_TYPE_CURSOR] = {
+ .name = "Cursor",
+ },
+ };
+ static const drmmode_prop_info_rec plane_props[] = {
+ [DRMMODE_PLANE_TYPE] = {
+ .name = "type",
+ .enum_values = plane_type_enums,
+ .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
+ },
+ [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
+ [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
+ [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ };
+ drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
+
+ if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "failed to copy plane property info\n");
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ return;
+ }
+
+ kplane_res = drmModeGetPlaneResources(drmmode->fd);
+ if (!kplane_res) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "failed to get plane resources: %s\n", strerror(errno));
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ return;
+ }
+
+ for (i = 0; i < kplane_res->count_planes; i++) {
+ int plane_id;
+
+ kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
+ if (!kplane)
+ continue;
+
+ if (!(kplane->possible_crtcs & (1 << num)) ||
+ is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
+ drmModeFreePlane(kplane);
+ continue;
+ }
+
+ plane_id = kplane->plane_id;
+ drmModeFreePlane(kplane);
+
+ props = drmModeObjectGetProperties(drmmode->fd, plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (!props) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
+ "couldn't get plane properties\n");
+ continue;
+ }
+
+ drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
+
+ /* Only primary planes are important for atomic page-flipping */
+ type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
+ props, DRMMODE_PLANE_TYPE__COUNT);
+ if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+ drmModeFreeObjectProperties(props);
+ continue;
+ }
+
+ /* Check if plane is already on this CRTC */
+ current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
+ props, 0);
+ if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
+ if (best_plane)
+ drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ best_plane = plane_id;
+ drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+ DRMMODE_PLANE__COUNT, 1);
+ drmModeFreeObjectProperties(props);
+ break;
+ }
+
+ if (!best_plane) {
+ best_plane = plane_id;
+ drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
+ DRMMODE_PLANE__COUNT, 1);
+ }
+
+ drmModeFreeObjectProperties(props);
+ }
+
+ drmmode_crtc->plane_id = best_plane;
+
+ drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
+ drmModeFreePlaneResources(kplane_res);
+}
+#endif
+
static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
{
@@ -1122,6 +1487,10 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
crtc->driver_private = drmmode_crtc;

+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ drmmode_crtc_create_planes(crtc, num);
+#endif
+
/* Hide any cursors which may be active from previous users */
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);

@@ -1477,7 +1846,8 @@ drmmode_property_ignore(drmModePropertyPtr prop)
if (prop->flags & DRM_MODE_PROP_BLOB)
return TRUE;
/* ignore standard property */
- if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
+ if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
+ !strcmp(prop->name, "CRTC_ID"))
return TRUE;

return FALSE;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 267040918..1f24c3a5b 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -36,6 +36,22 @@

struct gbm_device;

+enum drmmode_plane_property {
+ DRMMODE_PLANE_TYPE = 0,
+ DRMMODE_PLANE_FB_ID,
+ DRMMODE_PLANE_CRTC_ID,
+ DRMMODE_PLANE_SRC_X,
+ DRMMODE_PLANE_SRC_Y,
+ DRMMODE_PLANE__COUNT
+};
+
+enum drmmode_plane_type {
+ DRMMODE_PLANE_TYPE_PRIMARY = 0,
+ DRMMODE_PLANE_TYPE_CURSOR,
+ DRMMODE_PLANE_TYPE_OVERLAY,
+ DRMMODE_PLANE_TYPE__COUNT
+};
+
typedef struct {
struct dumb_bo *dumb;
#ifdef GLAMOR_HAS_GBM
@@ -88,6 +104,19 @@ typedef struct {
Bool present_enable;
} drmmode_rec, *drmmode_ptr;

+typedef struct {
+ const char *name;
+ Bool valid;
+ uint64_t value;
+} drmmode_prop_enum_info_rec, *drmmode_prop_enum_info_ptr;
+
+typedef struct {
+ const char *name;
+ uint32_t prop_id;
+ unsigned int num_enum_values;
+ drmmode_prop_enum_info_rec *enum_values;
+} drmmode_prop_info_rec, *drmmode_prop_info_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -97,6 +126,9 @@ typedef struct {
Bool cursor_up;
uint16_t lut_r[256], lut_g[256], lut_b[256];

+ drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
+ uint32_t plane_id;
+
drmmode_bo rotate_bo;
unsigned rotate_fb_id;

@@ -205,6 +237,10 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
int *depth, int *bpp);

void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
+
+int drmmode_crtc_set_fb(xf86CrtcPtr crtc, uint32_t fb_id,
+ int x, int y, uint32_t flags, void *data);
+
#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
#define DRM_CAP_DUMB_PREFERRED_DEPTH 3
#endif
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index d5fd0625b..dd296cd12 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -159,6 +159,25 @@ ms_pageflip_abort(void *data)
ms_pageflip_free(flip);
}

+static Bool
+do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
+ uint32_t flags, uint32_t seq)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ if (ms->atomic_modeset) {
+ flags |= DRM_MODE_ATOMIC_NONBLOCK;
+ return drmmode_crtc_set_fb(crtc, ms->drmmode.fb_id, 0, 0, flags,
+ (void *) (uintptr_t) seq);
+ }
+#endif
+
+ return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
+ ms->drmmode.fb_id, flags,
+ (void *) (uintptr_t) seq);
+}
+
static Bool
queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
struct ms_flipdata *flipdata,
@@ -193,8 +212,7 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
/* take a reference on flipdata for use in flip */
flipdata->flip_count++;

- while (drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
- ms->drmmode.fb_id, flags, (void *) (uintptr_t) seq)) {
+ while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
err = errno;
/* We may have failed because the event queue was full. Flush it
* and retry. If there was nothing to flush, then we failed for
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index f12df74da..9f8dc913f 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -491,6 +491,9 @@
/* Build glamor use new drmGetDeviceNameFromFD2 */
#undef GLAMOR_HAS_DRM_NAME_FROM_FD_2

+/* Glamor should use atomic DRM API */
+#undef GLAMOR_HAS_DRM_ATOMIC
+
/* byte order */
#undef X_BYTE_ORDER

diff --git a/include/meson.build b/include/meson.build
index 83778c69b..dceca2b7d 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -74,6 +74,8 @@ conf_data.set_quoted('SHMDIR', '/tmp')

conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found())
conf_data.set('WITH_LIBDRM', libdrm_dep.found())
+conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
+ libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
conf_data.set('GLXEXT', build_glx)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https:
Dave Airlie
2018-09-12 01:01:18 UTC
Permalink
Post by Daniel Stone
In order to flip between compressed and uncompressed buffers -
something drmModePageFlip explicitly bans us from doing - we need
to port use the atomic modesetting API. It's only 'fake' atomic
though given we still commit for each CRTC separately and
CRTC and connector properties are not set with the atomic API.
The helper functions to retrieve DRM properties have been borrowed
from Weston.
---
configure.ac | 3 +
hw/xfree86/drivers/modesetting/driver.c | 6 +
hw/xfree86/drivers/modesetting/driver.h | 1 +
hw/xfree86/drivers/modesetting/drmmode_display.c | 374 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 36 +++
hw/xfree86/drivers/modesetting/pageflip.c | 22 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
8 files changed, 443 insertions(+), 4 deletions(-)
diff --git a/configure.ac b/configure.ac
index cef9503d7..46662867f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2106,6 +2106,9 @@ if test "x$GLAMOR" = xyes; then
fi
fi
+ PKG_CHECK_EXISTS(libdrm >= 2.4.62,
+ [AC_DEFINE(GLAMOR_HAS_DRM_ATOMIC, 1, [libdrm supports atomic API])],
+ [])
PKG_CHECK_EXISTS(libdrm >= 2.4.74,
[AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
[])
diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c
index ec2aa9a27..88a42257c 100644
--- a/hw/xfree86/drivers/modesetting/driver.c
+++ b/hw/xfree86/drivers/modesetting/driver.c
@@ -1018,6 +1018,12 @@ PreInit(ScrnInfoPtr pScrn, int flags)
}
#endif
+#ifdef GLAMOR_HAS_DRM_ATOMIC
+ ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ ret |= drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
+ ms->atomic_modeset = (ret == 0);
+#endif
+
if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
goto fail;
diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h
index fe835918b..ed32239db 100644
--- a/hw/xfree86/drivers/modesetting/driver.h
+++ b/hw/xfree86/drivers/modesetting/driver.h
@@ -105,6 +105,7 @@ typedef struct _modesettingRec {
* Page flipping stuff.
*/
+ Bool atomic_modeset;
DamagePtr damage;
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index bfc8c50db..8674c2c16 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -75,6 +75,233 @@ drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name
return ret;
}
+static uint64_t
+drmmode_prop_get_value(drmmode_prop_info_ptr info,
+ drmModeObjectPropertiesPtr props,
+ uint64_t def)
+{
+ unsigned int i;
+
+ if (info->prop_id == 0)
+ return def;
+
+ for (i = 0; i < props->count_props; i++) {
+ unsigned int j;
+
+ if (props->props[i] != info->prop_id)
+ continue;
+
+ /* Simple (non-enum) types can return the value directly */
+ if (info->num_enum_values == 0)
+ return props->prop_values[i];
+
+ /* Map from raw value to enum value */
+ for (j = 0; j < info->num_enum_values; j++) {
+ if (!info->enum_values[j].valid)
+ continue;
+ if (info->enum_values[j].value != props->prop_values[i])
+ continue;
+
+ return j;
+ }
+ }
+
+ return def;
+}
+
+static uint32_t
+drmmode_prop_info_update(drmmode_ptr drmmode,
+ drmmode_prop_info_ptr info,
+ unsigned int num_infos,
+ drmModeObjectProperties *props)
+{
+ drmModePropertyRes *prop;
+ uint32_t valid_mask = 0;
+ unsigned i, j;
+
+ assert(num_infos <= 32 && "update return type");
+
+ for (i = 0; i < props->count_props; i++) {
+ Bool props_incomplete = FALSE;
+ unsigned int k;
+
+ for (j = 0; j < num_infos; j++) {
+ if (info[j].prop_id == props->props[i])
+ break;
+ if (!info[j].prop_id)
+ props_incomplete = TRUE;
+ }
+
+ /* We've already discovered this property. */
+ if (j != num_infos)
+ continue;
+
+ /* We haven't found this property ID, but as we've already
+ * found all known properties, we don't need to look any
+ * further. */
+ if (!props_incomplete)
+ break;
+
+ prop = drmModeGetProperty(drmmode->fd, props->props[i]);
+ if (!prop)
+ continue;
+
+ for (j = 0; j < num_infos; j++) {
+ if (!strcmp(prop->name, info[j].name))
+ break;
+ }
+
+ /* We don't know/care about this property. */
+ if (j == num_infos) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ info[j].prop_id = props->props[i];
+ valid_mask |= 1U << j;
+
+ if (info[j].num_enum_values == 0) {
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
+ xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
+ "expected property %s to be an enum,"
+ " but it is not; ignoring\n", prop->name);
+ drmModeFreeProperty(prop);
+ continue;
+ }
+
+ for (k = 0; k < info[j].num_enum_values; k++) {
+ int l;
+
+ if (info[j].enum_values[k].valid)
+ continue;
+
+ for (l = 0; l < prop->count_enums; l++) {
+ if (!strcmp(prop->enums[l].name,
+ info[j].enum_values[k].name))
+ break;
+ }
+
+ if (l == prop->count_enums)
+ continue;
+
+ info[j].enum_values[k].valid = TRUE;
+ info[j].enum_values[k].value = prop->enums[l].value;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+
+ return valid_mask;
+}
+
+static Bool
+drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
+ const drmmode_prop_info_rec *src,
+ unsigned int num_props,
+ Bool copy_prop_id)
+{
+ unsigned int i;
+
+ memcpy(dst, src, num_props * sizeof(*dst));
+
+ for (i = 0; i < num_props; i++) {
+ unsigned int j;
+
+ if (copy_prop_id)
+ dst[i].prop_id = src[i].prop_id;
+ else
+ dst[i].prop_id = 0;
+
+ if (src[i].num_enum_values == 0)
+ continue;
+
+ dst[i].enum_values =
+ malloc(src[i].num_enum_values *
+ sizeof(*dst[i].enum_values));
+ if (!dst[i].enum_values)
+ goto err;
+
+ memcpy(dst[i].enum_values, src[i].enum_values,
+ src[i].num_enum_values * sizeof(*dst[i].enum_values));
+
+ for (j = 0; j < dst[i].num_enum_values; j++)
+ dst[i].enum_values[j].valid = FALSE;
+ }
+
+ return TRUE;
+
+ while (i--)
+ free(dst[i].enum_values);
+ free(dst);
+ return FALSE;
+}
On failure this frees dst, however...
Post by Daniel Stone
+drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ drmModePlaneRes *kplane_res;
+ drmModePlane *kplane;
+ drmModeObjectProperties *props;
+ uint32_t i, type;
+ int current_crtc, best_plane = 0;
+
+ static drmmode_prop_enum_info_rec plane_type_enums[] = {
+ [DRMMODE_PLANE_TYPE_PRIMARY] = {
+ .name = "Primary",
+ },
+ [DRMMODE_PLANE_TYPE_OVERLAY] = {
+ .name = "Overlay",
+ },
+ [DRMMODE_PLANE_TYPE_CURSOR] = {
+ .name = "Cursor",
+ },
+ };
+ static const drmmode_prop_info_rec plane_props[] = {
+ [DRMMODE_PLANE_TYPE] = {
+ .name = "type",
+ .enum_values = plane_type_enums,
+ .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
+ },
+ [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
+ [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
+ [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ };
+ drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
We use a stack allocated tmp_props here.

Not sure how to test any fix I write but seems like it shouldn't be a
major problem.

Dave.
_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.
Adam Jackson
2018-10-01 15:31:41 UTC
Permalink
Post by Dave Airlie
Post by Daniel Stone
+static Bool
+drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
+ const drmmode_prop_info_rec *src,
+ unsigned int num_props,
+ Bool copy_prop_id)
+{
+ unsigned int i;
+
+ memcpy(dst, src, num_props * sizeof(*dst));
+
+ for (i = 0; i < num_props; i++) {
+ unsigned int j;
+
+ if (copy_prop_id)
+ dst[i].prop_id = src[i].prop_id;
+ else
+ dst[i].prop_id = 0;
+
+ if (src[i].num_enum_values == 0)
+ continue;
+
+ dst[i].enum_values =
+ malloc(src[i].num_enum_values *
+ sizeof(*dst[i].enum_values));
+ if (!dst[i].enum_values)
+ goto err;
+
+ memcpy(dst[i].enum_values, src[i].enum_values,
+ src[i].num_enum_values * sizeof(*dst[i].enum_values));
+
+ for (j = 0; j < dst[i].num_enum_values; j++)
+ dst[i].enum_values[j].valid = FALSE;
+ }
+
+ return TRUE;
+
+ while (i--)
+ free(dst[i].enum_values);
+ free(dst);
+ return FALSE;
+}
On failure this frees dst, however...
Post by Daniel Stone
+drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ drmModePlaneRes *kplane_res;
+ drmModePlane *kplane;
+ drmModeObjectProperties *props;
+ uint32_t i, type;
+ int current_crtc, best_plane = 0;
+
+ static drmmode_prop_enum_info_rec plane_type_enums[] = {
+ [DRMMODE_PLANE_TYPE_PRIMARY] = {
+ .name = "Primary",
+ },
+ [DRMMODE_PLANE_TYPE_OVERLAY] = {
+ .name = "Overlay",
+ },
+ [DRMMODE_PLANE_TYPE_CURSOR] = {
+ .name = "Cursor",
+ },
+ };
+ static const drmmode_prop_info_rec plane_props[] = {
+ [DRMMODE_PLANE_TYPE] = {
+ .name = "type",
+ .enum_values = plane_type_enums,
+ .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
+ },
+ [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
+ [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
+ [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
+ };
+ drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
We use a stack allocated tmp_props here.
AFAICT the free(dst) is always wrong. The other places we use
drmmode_prop_info_copy, we're initializing an array in the middle of a
drmmode_{crtc,output}_private_rec.

- ajax

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https:
Adam Jackson
2018-10-01 15:48:57 UTC
Permalink
Post by Adam Jackson
AFAICT the free(dst) is always wrong. The other places we use
drmmode_prop_info_copy, we're initializing an array in the middle of a
drmmode_{crtc,output}_private_rec.
https://gitlab.freedesktop.org/xorg/xserver/merge_requests/33

- ajax

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://l

Daniel Stone
2018-02-28 01:19:36 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Add 'check_flip2' hook for driver to let know the core
about why flipping is not possible ('reason').
If it is because of unsupported buffer format/modifier,
a PresentCompleteNotify event is sent to the client with
the PresentCompleteModeSuboptimalCopy mode.

v2: Check for PresentOptionSuboptimal and check driver version
before using 'check_flip2'.

v3: Only require one of 'check_flip' or 'check_flip2' to be
implemented by the driver.
Refactor reasons list to enum

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 2 +-
include/protocol-versions.h | 2 +-
present/meson.build | 2 +-
present/present.c | 50 ++++++++++++++++++++++++++++++---------------
present/present.h | 12 ++++++++++-
present/present_priv.h | 2 ++
6 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/configure.ac b/configure.ac
index 47469d864..cef9503d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -753,7 +753,7 @@ DAMAGEPROTO="damageproto >= 1.1"
XCMISCPROTO="xcmiscproto >= 1.2.0"
BIGREQSPROTO="bigreqsproto >= 1.1.0"
XTRANS="xtrans >= 1.3.5"
-PRESENTPROTO="presentproto >= 1.0"
+PRESENTPROTO="presentproto >= 1.1"

dnl List of libraries that require a specific version
LIBAPPLEWM="applewm >= 1.4"
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index 938b9caa4..39cd2e909 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -69,7 +69,7 @@

/* Present */
#define SERVER_PRESENT_MAJOR_VERSION 1
-#define SERVER_PRESENT_MINOR_VERSION 0
+#define SERVER_PRESENT_MINOR_VERSION 1

/* RandR */
#define SERVER_RANDR_MAJOR_VERSION 1
diff --git a/present/meson.build b/present/meson.build
index a4296ca7a..cf725302a 100644
--- a/present/meson.build
+++ b/present/meson.build
@@ -13,7 +13,7 @@ libxserver_present = static_library('libxserver_present',
include_directories: inc,
dependencies: [
common_dep,
- dependency('presentproto', version: '>= 1.0')
+ dependency('presentproto', version: '>= 1.1')
],
c_args: '-DHAVE_XORG_CONFIG_H'
)
diff --git a/present/present.c b/present/present.c
index 176e89c0b..42e5fb4fc 100644
--- a/present/present.c
+++ b/present/present.c
@@ -118,19 +118,23 @@ present_flip_pending_pixmap(ScreenPtr screen)
}

static Bool
-present_check_flip(RRCrtcPtr crtc,
- WindowPtr window,
- PixmapPtr pixmap,
- Bool sync_flip,
- RegionPtr valid,
- int16_t x_off,
- int16_t y_off)
+present_check_flip(RRCrtcPtr crtc,
+ WindowPtr window,
+ PixmapPtr pixmap,
+ Bool sync_flip,
+ RegionPtr valid,
+ int16_t x_off,
+ int16_t y_off,
+ PresentFlipReason *reason)
{
ScreenPtr screen = window->drawable.pScreen;
PixmapPtr window_pixmap;
WindowPtr root = screen->root;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);

+ if (reason)
+ *reason = PRESENT_FLIP_REASON_UNKNOWN;
+
if (!screen_priv)
return FALSE;

@@ -177,7 +181,12 @@ present_check_flip(RRCrtcPtr crtc,
}

/* Ask the driver for permission */
- if (screen_priv->info->check_flip) {
+ if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
+ if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
+ DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
+ return FALSE;
+ }
+ } else if (screen_priv->info->check_flip) {
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
return FALSE;
@@ -564,6 +573,7 @@ present_check_flip_window (WindowPtr window)
present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr flip_pending = screen_priv->flip_pending;
present_vblank_ptr vblank;
+ PresentFlipReason reason;

/* If this window hasn't ever been used with Present, it can't be
* flipping
@@ -580,7 +590,7 @@ present_check_flip_window (WindowPtr window)
*/
if (flip_pending->window == window) {
if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
- flip_pending->sync_flip, NULL, 0, 0))
+ flip_pending->sync_flip, NULL, 0, 0, NULL))
present_set_abort_flip(screen);
}
} else {
@@ -588,15 +598,16 @@ present_check_flip_window (WindowPtr window)
* Check current flip
*/
if (window == screen_priv->flip_window) {
- if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0))
+ if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
present_unflip(screen);
}
}

/* Now check any queued vblanks */
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
- if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) {
+ if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
vblank->flip = FALSE;
+ vblank->reason = reason;
if (vblank->sync_flip)
vblank->requeue = TRUE;
}
@@ -756,10 +767,14 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
/* Compute correct CompleteMode
*/
if (vblank->kind == PresentCompleteKindPixmap) {
- if (vblank->pixmap && vblank->window)
- mode = PresentCompleteModeCopy;
- else
+ if (vblank->pixmap && vblank->window) {
+ if (vblank->has_suboptimal && vblank->reason == PRESENT_FLIP_REASON_BUFFER_FORMAT)
+ mode = PresentCompleteModeSuboptimalCopy;
+ else
+ mode = PresentCompleteModeCopy;
+ } else {
mode = PresentCompleteModeSkip;
+ }
}
else
mode = PresentCompleteModeCopy;
@@ -795,6 +810,7 @@ present_pixmap(WindowPtr window,
ScreenPtr screen = window->drawable.pScreen;
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
+ PresentFlipReason reason = PRESENT_FLIP_REASON_UNKNOWN;

if (!window_priv)
return BadAlloc;
@@ -912,22 +928,24 @@ present_pixmap(WindowPtr window,
vblank->msc_offset = window_priv->msc_offset;
vblank->notifies = notifies;
vblank->num_notifies = num_notifies;
+ vblank->has_suboptimal = (options & PresentOptionSuboptimal);

if (pixmap != NULL &&
!(options & PresentOptionCopy) &&
screen_priv->info) {
if (msc_is_after(target_msc, crtc_msc) &&
- present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off))
+ present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
{
vblank->flip = TRUE;
vblank->sync_flip = TRUE;
target_msc--;
} else if ((screen_priv->info->capabilities & PresentCapabilityAsync) &&
- present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off))
+ present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
{
vblank->flip = TRUE;
}
}
+ vblank->reason = reason;

if (wait_fence) {
vblank->wait_fence = present_fence_create(wait_fence);
diff --git a/present/present.h b/present/present.h
index aab2e168a..6542dc385 100644
--- a/present/present.h
+++ b/present/present.h
@@ -27,6 +27,11 @@
#include "randrstr.h"
#include "presentext.h"

+typedef enum {
+ PRESENT_FLIP_REASON_UNKNOWN,
+ PRESENT_FLIP_REASON_BUFFER_FORMAT
+} PresentFlipReason;
+
typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;

/* Return the current CRTC for 'window'.
@@ -59,6 +64,10 @@ typedef void (*present_flush_ptr) (WindowPtr window);
*/
typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);

+/* Same as 'check_flip' but it can return a 'reason' why the flip would fail.
+ */
+typedef Bool (*present_check_flip2_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip, PresentFlipReason *reason);
+
/* Flip pixmap, return false if it didn't happen.
*
* 'crtc' is to be used for any necessary synchronization.
@@ -83,7 +92,7 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
typedef void (*present_unflip_ptr) (ScreenPtr screen,
uint64_t event_id);

-#define PRESENT_SCREEN_INFO_VERSION 0
+#define PRESENT_SCREEN_INFO_VERSION 1

typedef struct present_screen_info {
uint32_t version;
@@ -97,6 +106,7 @@ typedef struct present_screen_info {
present_check_flip_ptr check_flip;
present_flip_ptr flip;
present_unflip_ptr unflip;
+ present_check_flip2_ptr check_flip2;

} present_screen_info_rec, *present_screen_info_ptr;

diff --git a/present/present_priv.h b/present/present_priv.h
index dfb4bdea9..6980ddd11 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -75,6 +75,8 @@ struct present_vblank {
Bool flip_ready; /* wants to flip, but waiting for previous flip or unflip */
Bool sync_flip; /* do flip synchronous to vblank */
Bool abort_flip; /* aborting this flip */
+ PresentFlipReason reason; /* reason for which flip is not possible */
+ Bool has_suboptimal; /* whether client can support SuboptimalCopy mode */
};

typedef struct present_screen_priv {
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info:
Daniel Stone
2018-02-28 01:19:41 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Use most optimal buffer format (e.g. tiled/compressed) available
for scanout.

v2: Don't use multi-plane modifier to create scanout buffer

v3: Add flag to retrieve modifiers set from enabled CRTCs only

v4: Fix uses when GBM/EGL driver doesn't support modifiers

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 90 +++++++++++++++++++++++-
1 file changed, 87 insertions(+), 3 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 7af805da2..6fa22da56 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -73,6 +73,68 @@ modifiers_ptr(struct drm_format_modifier_blob *blob)

#endif

+#ifdef GBM_BO_WITH_MODIFIERS
+static uint32_t
+get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
+ Bool enabled_crtc_only, Bool exclude_multiplane)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ modesettingPtr ms = modesettingPTR(scrn);
+ drmmode_ptr drmmode = &ms->drmmode;
+ int c, i, j, k, count_modifiers = 0;
+ uint64_t *tmp, *ret = NULL;
+
+ *modifiers = NULL;
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ if (enabled_crtc_only && !crtc->enabled)
+ continue;
+
+ for (i = 0; i < drmmode_crtc->num_formats; i++) {
+ drmmode_format_ptr iter = &drmmode_crtc->formats[i];
+
+ if (iter->format != format)
+ continue;
+
+ for (j = 0; j < iter->num_modifiers; j++) {
+ Bool found = FALSE;
+
+ /* Don't choose multi-plane formats for our screen pixmap.
+ * These will get used with frontbuffer rendering, which will
+ * lead to worse-than-tearing with multi-plane formats, as the
+ * primary and auxiliary planes go out of sync. */
+ if (exclude_multiplane &&
+ gbm_device_get_format_modifier_plane_count(drmmode->gbm,
+ format,
+ iter->modifiers[j]) > 1) {
+ continue;
+ }
+
+ for (k = 0; k < count_modifiers; k++) {
+ if (iter->modifiers[j] == ret[k])
+ found = TRUE;
+ }
+ if (!found) {
+ count_modifiers++;
+ tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
+ if (!tmp) {
+ free(ret);
+ return 0;
+ }
+ ret = tmp;
+ ret[count_modifiers - 1] = iter->modifiers[j];
+ }
+ }
+ }
+ }
+
+ *modifiers = ret;
+ return count_modifiers;
+}
+#endif
+
static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
{
@@ -593,14 +655,36 @@ static Bool
drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
unsigned width, unsigned height, unsigned bpp)
{
+ uint32_t format;
+
+ if (drmmode->scrn->depth == 30)
+ format = GBM_FORMAT_ARGB2101010;
+ else
+ format = GBM_FORMAT_ARGB8888;
+
bo->width = width;
bo->height = height;

#ifdef GLAMOR_HAS_GBM
if (drmmode->glamor) {
- bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
- drmmode->scrn->depth == 30 ?
- GBM_FORMAT_ARGB2101010 : GBM_FORMAT_ARGB8888,
+#ifdef GBM_BO_WITH_MODIFIERS
+ uint32_t num_modifiers;
+ uint64_t *modifiers = NULL;
+
+ num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
+ FALSE, TRUE);
+ if (num_modifiers > 0 &&
+ !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
+ bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
+ format, modifiers,
+ num_modifiers);
+ free(modifiers);
+ if (bo->gbm)
+ return TRUE;
+ }
+#endif
+
+ bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
return bo->gbm != NULL;
}
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mai
Daniel Stone
2018-02-28 01:19:38 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

This allows the uses of CCS compressed or tiled pixmaps as BOs when
page-flipping.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 49 ++++++++++++++++++++++++
hw/xfree86/drivers/modesetting/drmmode_display.h | 4 ++
hw/xfree86/drivers/modesetting/pageflip.c | 16 ++++----
3 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 8674c2c16..ee9f4d724 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -39,6 +39,8 @@
#include "micmap.h"
#include "xf86cmap.h"
#include "xf86DDC.h"
+#include <drm_fourcc.h>
+#include <drm_mode.h>

#include <xf86drm.h>
#include "xf86Crtc.h"
@@ -376,10 +378,57 @@ drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
return bo->dumb->ptr;
}

+int
+drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+ uint32_t *fb_id)
+{
+#ifdef GBM_BO_WITH_MODIFIERS
+ if (bo->gbm &&
+ gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
+ int num_fds;
+
+ num_fds = gbm_bo_get_plane_count(bo->gbm);
+ if (num_fds > 0) {
+ int i;
+ uint32_t format;
+ uint32_t handles[4];
+ uint32_t strides[4];
+ uint32_t offsets[4];
+ uint64_t modifiers[4];
+
+ memset(handles, 0, sizeof(handles));
+ memset(strides, 0, sizeof(strides));
+ memset(offsets, 0, sizeof(offsets));
+ memset(modifiers, 0, sizeof(modifiers));
+
+ format = gbm_bo_get_format(bo->gbm);
+ for (i = 0; i < num_fds; i++) {
+ handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
+ strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
+ offsets[i] = gbm_bo_get_offset(bo->gbm, i);
+ modifiers[i] = gbm_bo_get_modifier(bo->gbm);
+ }
+
+ return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
+ format, handles, strides,
+ offsets, modifiers, fb_id,
+ DRM_MODE_FB_MODIFIERS);
+ }
+ }
+#endif
+ return drmModeAddFB(drmmode->fd, bo->width, bo->height,
+ drmmode->scrn->depth, drmmode->scrn->bitsPerPixel,
+ drmmode_bo_get_pitch(bo),
+ drmmode_bo_get_handle(bo), fb_id);
+}
+
static Bool
drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
unsigned width, unsigned height, unsigned bpp)
{
+ bo->width = width;
+ bo->height = height;
+
#ifdef GLAMOR_HAS_GBM
if (drmmode->glamor) {
bo->gbm = gbm_bo_create(drmmode->gbm, width, height,
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 1f24c3a5b..177ccabd7 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -53,6 +53,8 @@ enum drmmode_plane_type {
};

typedef struct {
+ uint32_t width;
+ uint32_t height;
struct dumb_bo *dumb;
#ifdef GLAMOR_HAS_GBM
struct gbm_bo *gbm;
@@ -202,6 +204,8 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec;

#define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))

+int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
+ uint32_t *fb_id);
int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo);
uint32_t drmmode_bo_get_pitch(drmmode_bo *bo);
uint32_t drmmode_bo_get_handle(drmmode_bo *bo);
diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c
index dd296cd12..027ebfe42 100644
--- a/hw/xfree86/drivers/modesetting/pageflip.c
+++ b/hw/xfree86/drivers/modesetting/pageflip.c
@@ -258,6 +258,7 @@ ms_do_pageflip(ScreenPtr screen,

new_front_bo.gbm = glamor_gbm_bo_from_pixmap(screen, new_front);
new_front_bo.dumb = NULL;
+
if (!new_front_bo.gbm) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Failed to get GBM bo for flip to new front.\n");
@@ -288,14 +289,12 @@ ms_do_pageflip(ScreenPtr screen,

/* Create a new handle for the back buffer */
flipdata->old_fb_id = ms->drmmode.fb_id;
- if (drmModeAddFB(ms->fd, scrn->virtualX, scrn->virtualY,
- scrn->depth, scrn->bitsPerPixel,
- drmmode_bo_get_pitch(&new_front_bo),
- drmmode_bo_get_handle(&new_front_bo), &ms->drmmode.fb_id)) {
- goto error_out;
- }

- drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+ new_front_bo.width = new_front->drawable.width;
+ new_front_bo.height = new_front->drawable.height;
+ if (drmmode_bo_import(&ms->drmmode, &new_front_bo,
+ &ms->drmmode.fb_id))
+ goto error_out;

flags = DRM_MODE_PAGE_FLIP_EVENT;
if (async)
@@ -323,6 +322,8 @@ ms_do_pageflip(ScreenPtr screen,
}
}

+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
+
/*
* Do we have more than our local reference,
* if so and no errors, then drop our local
@@ -348,6 +349,7 @@ error_undo:
error_out:
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
strerror(errno));
+ drmmode_bo_destroy(&ms->drmmode, &new_front_bo);
/* if only the local reference - free the structure,
* else drop the local reference and return */
if (flipdata->flip_count == 1)
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/list
Daniel Stone
2018-02-28 01:19:42 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Add support for 'check_flip2' so that the present core can know
why it is impossible to flip in that scenario. The core can then
let know the client that the buffer format/modifier is suboptimal.

v2: No longer need to implement 'check_flip'

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
hw/xfree86/drivers/modesetting/drmmode_display.c | 42 ++++++++++++++++++++++++
hw/xfree86/drivers/modesetting/drmmode_display.h | 2 ++
hw/xfree86/drivers/modesetting/present.c | 30 ++++++++++++++---
3 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index bfde3fabf..785849ef9 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -73,6 +73,48 @@ modifiers_ptr(struct drm_format_modifier_blob *blob)

#endif

+Bool
+drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c, i, j;
+
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ Bool found = FALSE;
+
+ if (!crtc->enabled)
+ continue;
+
+ for (i = 0; i < drmmode_crtc->num_formats; i++) {
+ drmmode_format_ptr iter = &drmmode_crtc->formats[i];
+
+ if (iter->format != format)
+ continue;
+
+ if (modifier == 0) {
+ found = TRUE;
+ break;
+ }
+
+ for (j = 0; j < iter->num_modifiers; j++) {
+ if (iter->modifiers[j] == modifier) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ if (!found)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
#ifdef GBM_BO_WITH_MODIFIERS
static uint32_t
get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index 75e4b8499..607fe8179 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -241,6 +241,8 @@ extern DevPrivateKeyRec msPixmapPrivateKeyRec;

#define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))

+Bool drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format,
+ uint64_t modifier);
int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
uint32_t *fb_id);
int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo);
diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c
index 4a01d19ea..71ef2f7f1 100644
--- a/hw/xfree86/drivers/modesetting/present.c
+++ b/hw/xfree86/drivers/modesetting/present.c
@@ -214,7 +214,8 @@ static Bool
ms_present_check_flip(RRCrtcPtr crtc,
WindowPtr window,
PixmapPtr pixmap,
- Bool sync_flip)
+ Bool sync_flip,
+ PresentFlipReason *reason)
{
ScreenPtr screen = window->drawable.pScreen;
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
@@ -222,6 +223,9 @@ ms_present_check_flip(RRCrtcPtr crtc,
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int num_crtcs_on = 0;
int i;
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+ struct gbm_bo *gbm;
+#endif

if (!ms->drmmode.pageflip)
return FALSE;
@@ -252,6 +256,23 @@ ms_present_check_flip(RRCrtcPtr crtc,
pixmap->devKind != drmmode_bo_get_pitch(&ms->drmmode.front_bo))
return FALSE;

+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+ /* Check if buffer format/modifier is supported by all active CRTCs */
+ gbm = glamor_gbm_bo_from_pixmap(screen, pixmap);
+ if (gbm) {
+ uint32_t format;
+ uint64_t modifier;
+
+ format = gbm_bo_get_format(gbm);
+ modifier = gbm_bo_get_modifier(gbm);
+ if (!drmmode_is_format_supported(scrn, format, modifier)) {
+ if (reason)
+ *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT;
+ return FALSE;
+ }
+ }
+#endif
+
/* Make sure there's a bo we can get to */
/* XXX: actually do this. also...is it sufficient?
* if (!glamor_get_pixmap_private(pixmap))
@@ -280,7 +301,7 @@ ms_present_flip(RRCrtcPtr crtc,
Bool ret;
struct ms_present_vblank_event *event;

- if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip))
+ if (!ms_present_check_flip(crtc, screen->root, pixmap, sync_flip, NULL))
return FALSE;

event = calloc(1, sizeof(struct ms_present_vblank_event));
@@ -323,7 +344,7 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id)
event->event_id = event_id;
event->unflip = TRUE;

- if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE) &&
+ if (ms_present_check_flip(NULL, screen->root, pixmap, TRUE, NULL) &&
ms_do_pageflip(screen, pixmap, event, -1, FALSE,
ms_present_flip_handler, ms_present_flip_abort)) {
return;
@@ -368,7 +389,8 @@ static present_screen_info_rec ms_present_screen_info = {

.capabilities = PresentCapabilityNone,
#ifdef GLAMOR_HAS_GBM
- .check_flip = ms_present_check_flip,
+ .check_flip = NULL,
+ .check_flip2 = ms_present_check_flip,
.flip = ms_present_flip,
.unflip = ms_present_unflip,
#endif
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listin
Daniel Stone
2018-02-28 01:19:33 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

DRI3 version 1.2 adds support for explicit format modifiers,
including multi-planar buffers.

Signed-off-by: Daniel Stone <***@collabora.com>
Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
---
dri3proto.pc.in | 2 +-
dri3proto.txt | 319 +++++++++++++++++++++++++++++++++++--
include/X11/extensions/dri3proto.h | 86 +++++++++-
meson.build | 2 +-
4 files changed, 396 insertions(+), 13 deletions(-)

diff --git a/dri3proto.pc.in b/dri3proto.pc.in
index 6d81d07..e42d60e 100644
--- a/dri3proto.pc.in
+++ b/dri3proto.pc.in
@@ -5,5 +5,5 @@ includedir=@includedir@

Name: DRI3Proto
Description: DRI3 extension headers
-Version: 1.0
+Version: 1.2
Cflags: -I${includedir}
diff --git a/dri3proto.txt b/dri3proto.txt
index dac11d3..94322e7 100644
--- a/dri3proto.txt
+++ b/dri3proto.txt
@@ -1,16 +1,22 @@
The DRI3 Extension
- Version 1.0
- 2013-6-4
-
+ Version 1.2
+ 2018-02-28
+
Keith Packard
***@keithp.com
Intel Corporation

+ Daniel Stone
+ ***@collabora.com
+ Collabora
+
+
1. Introduction

The DRI3 extension provides mechanisms to translate between direct
rendered buffers and X pixmaps. When combined with the Present extension,
-a complete direct rendering solution for OpenGL is provided.
+a complete direct rendering solution for hardware-accelerated devices
+such as GPUs is provided.

The direct rendered buffers are passed across the protocol via
standard POSIX file descriptor passing mechanisms. On Linux, these
@@ -25,8 +31,9 @@ which can be used to serialize access to shared render buffers.
Eric Anholt <***@anholt.net>
Dave Airlie <***@redhat.com>
Kristian Høgsberg <***@bitplanet.net>
-James Jones <***@nvidia.com>
+James Jones <***@nvidia.com>
Arthur Huillet <***@free.fr>
+Louis-Francis Ratté-Boulianne <***@collabora.com>

❄ ❄ ❄ ❄ ❄ ❄ ❄

@@ -117,9 +124,10 @@ The name of this extension is "DRI3"
Errors: Alloc, Drawable, IDChoice, Value, Match

Creates a pixmap for the direct rendering object associated
- with 'buffer'. Changes to pixmap will be visible in that
- direct rendered object and changes to the direct rendered
- object will be visible in the pixmap.
+ with 'buffer' and the screen associated with 'drawable'.
+ Changes to pixmap will be visible in that direct rendered
+ object and changes to the direct rendered object will be
+ visible in the pixmap.

'size' specifies the total size of the buffer bytes. 'width',
'height' describe the geometry (in pixels) of the underlying
@@ -137,6 +145,9 @@ The name of this extension is "DRI3"
If depth or bpp are not supported by the screen, a Value error
is returned.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3BufferFromPixmap
pixmap: PIXMAP
@@ -167,6 +178,9 @@ The name of this extension is "DRI3"
If buffer cannot be used with the screen associated with
drawable, a Match error is returned.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3FenceFromFD
drawable: DRAWABLE
@@ -182,6 +196,9 @@ The name of this extension is "DRI3"
Details about the mechanism used with this file descriptor are
outside the scope of the DRI3 extension.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
┌───
DRI3FDFromFence
drawable: DRAWABLE
@@ -199,8 +216,163 @@ The name of this extension is "DRI3"
associated with a direct rendering device that 'fence' can
work with, otherwise a Match error results.

+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.

- ❄ ❄ ❄ ❄ ❄ ❄ ❄
+┌───
+ DRI3GetSupportedModifiers
+ window: WINDOW
+ depth: CARD8
+ bpp: CARD8
+ ▶
+ num_window_modifiers: CARD32
+ num_screen_modifiers: CARD32
+ window_modifiers: ListOfCARD64
+ screen_modifiers: ListOfCARD64
+└───
+ Errors: Window, Match
+
+ Return supported DRM FourCC modifiers for the specified
+ 'window'.
+
+ The first list of 'window_modifiers' contains a set of
+ modifiers which the server considers optimal for the window's
+ current configuration. Using these modifiers to allocate, even
+ if locally suboptimal to the client driver, may result in a
+ more optimal display pipeline, e.g. by avoiding composition.
+
+ The second list of 'screen_modifiers', is the total set of
+ modifiers which are acceptable for use on the Screen associated
+ with 'window'. This set of modifiers will not change over the
+ lifetime of the client. Using this set of modifiers to allocate
+ may not result in a globally optimal pipeline, if separate
+ 'window_modifiers' are available.
+
+ It is expected that a client calling this request will obtain
+ the modifiers for a particular window, allocate buffers using
+ the preferred modifier set as described above, create a Pixmap
+ referring to the storage of those buffers using the
+ DRI3BuffersFromPixmap request, then make the content visible
+ in the storage of those buffers visible with a request such as
+ the Present extension's PresentPixmap.
+
+ The meaning of any modifier is canonically defined in
+ drm_fourcc.h.
+
+┌───
+ DRI3PixmapFromBuffers
+ pixmap: PIXMAP
+ window: WINDOW
+ num_buffers: CARD8
+ width, height: CARD16
+ stride0, offset0: CARD32
+ stride1, offset1: CARD32
+ stride2, offset2: CARD32
+ stride3, offset3: CARD32
+ depth, bpp: CARD8
+ modifier: CARD64
+ buffers: ListOfFD
+└───
+ Errors: Alloc, Window, IDChoice, Value, Match
+
+ Creates a pixmap for the direct rendering object associated
+ with 'buffers' and the screen associated with 'window'.
+ Changes to pixmap will be visible in that direct rendered
+ object and changes to the direct rendered object will be
+ visible in the pixmap. The pixmap will be available for
+ presentation to the window.
+
+ In contrast to PixmapFromBuffer, multiple buffers may be
+ combined to specify a single logical source for pixel
+ sampling: 'num_buffers' may be set from 1 (single buffer,
+ akin to PixmapFromBuffer) to 4. This is the number of file
+ descriptors which will be sent with this request; one per
+ buffer.
+
+ Modifiers allow explicit specification of non-linear sources,
+ such as tiled or compressed buffers. The combination of bpp,
+ depth, and modifier allows unambiguous declaration of the
+ buffer layout in a manner defined by the DRM tokens.
+
+ If 'modifier' is DRM_FORMAT_MOD_INVALID, the client does
+ not have information on the buffer layout. In this case, the
+ buffer may only have a single plane. The driver may make its
+ own inference through unspecified means to determine the exact
+ buffer layout, however this is neither required nor defined
+ by the specification, and is considered an implementation
+ detail of the particular driver.
+
+ 'width' and 'height' describe the geometry (in pixels) of the
+ logical pixel-sample source.
+
+ 'strideN' and 'offsetN' define the number of bytes per logical
+ scanline, and the distance in bytes from the beginning of the
+ buffer passed for that plane until the start of the sample
+ source for that plane, respectively for plane N. If the plane
+ is not used according to the format and modifier specification,
+ both values for that plane must be zero.
+
+ Precisely how any additional information about the buffer (such
+ as memory placement) is shared is outside the scope of this
+ extension.
+
+ If the buffer(s) cannot be used with the screen associated with
+ 'window', a Match error is returned.
+
+ If the bpp, depth, and modifier combination is not supported by
+ the screen, a Value error is returned.
+
+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
+┌───
+ DRI3BuffersFromPixmap
+ pixmap: PIXMAP
+ ▶
+ nfd: CARD8
+ width, height: CARD16
+ depth, bpp: CARD8
+ modifier: CARD64
+ strides: ListOfCARD32
+ offsets: ListOfCARD32
+ buffers: ListOfFD
+└───
+ Errors: Pixmap, Match
+
+ Returns direct rendering objects associated with 'pixmap'.
+ Changes to 'pixmap' will be visible in the direct rendered
+ objects and changes to the direct rendered objects will be
+ visible in 'pixmap' after flushing and synchronization.
+
+ 'width' and 'height' describe the geometry (in pixels) of the
+ logical pixel-sample source from combining the direct rendering
+ objects.
+
+ See PixmapFromBuffers for more details on DRM modifiers usage.
+
+ 'nfd' describes the number of buffers returned for the pixmap,
+ which must be combined together according to 'depth', 'bpp', and
+ 'modifier'.
+
+ For each buffer, there is an entry in the 'strides',
+ 'offsets', and 'buffers' list. 'buffer' contains a single file
+ descriptor referring to the buffer. 'stride' specifies the
+ number of bytes per logical scanline for this plane, and
+ 'offset' specifies the distance in bytes from the beginning
+ of 'buffer' until the start of the sample source for that
+ plane.
+
+ Precisely how any additional information about the buffer is
+ shared is outside the scope of this extension.
+
+ If buffers cannot be exported from the the screen associated
+ with 'pixmap', a Match error is returned.
+
+ For information on synchronization of buffer access between
+ the client and the X server, please see section 12.
+
+
+ ❄ ❄ ❄ ❄ ❄ ❄ ❄

9. Extension Events

@@ -214,6 +386,11 @@ The DRI3 extension is adapted from the DRI2 extension.

1.0: First published version

+ 1.1: Cosmetic changes
+
+ 1.2: Add GetSupportedModifiers,
+ PixmapFromBuffers, and BuffersFromPixmap requests.
+
❄ ❄ ❄ ❄ ❄ ❄ ❄


@@ -249,6 +426,57 @@ objects from the X server.

❄ ❄ ❄ ❄ ❄ ❄ ❄

+12. Synchronization
+
+Synchronization of access to buffers shared between processes is not
+currently explicitly controlled by this protocol.
+
+Without the use of additional extensions not defined by the DRI3
+protocol as of version 1.2, synchronization between multiple
+processes and contexts is considered to follow the implicit model.
+
+In this model, the driver is required to have a global view of
+access requests issued by all processes with a reference to the
+buffer, and control scheduling of all operations on that buffer,
+whether performed by the CPU or auxiliary hardware.
+
+The driver is responsible for enforcing a strict ordering to protect
+against write-after-read or read-after-write hazards, such that any
+reads requested by one process or context, are fulfilled before any
+writes requested by another process or context, as long as that read
+was definitively submitted before the write.
+
+A similar dependency exists for reads submitted after writes: the
+driver must ensure that the write is fully visible and coherent to
+the read request.
+
+As a purely illustrative example, if two processes share a buffer,
+where one process reads from a buffer using an OpenGL texture
+sampler and submits this work by calling 'glFlush', and the other
+process submits work to the driver to write to that buffer, the
+driver is responsible for ensuring that the results of the latter
+write are not visible to the texture sampler.
+
+The Sync fences provided by DRI3 control only this submission of
+work and ensuing global visibility of the requests, rather than the
+completion of the work within any hardware. To further the example
+above, a fence used to prevent any writes to the buffer before the
+sampler had completed access, the fence would be signaled when
+'glFlush' had been called, at which point the request has become
+globally visible to the driver's request-scheduling and
+synchronization mechanisms. The logical ordering of requests made
+by software has been preserved, and the driver then takes care
+to ensure that these requests are scheduled such they do not
+observe effects from requests made later in time.
+
+This presents a fully coherent in-order FIFO-like model across
+processes, where synchronzation is handled externally to the DRI3
+client with no explicit intervention.
+
+This restriction also applies for cross-device usage.
+
+ ❄ ❄ ❄ ❄ ❄ ❄ ❄
+
Appendix A. Protocol Encoding

Syntactic Conventions
@@ -367,6 +595,79 @@ A.2 Protocol Requests
0 FD fence fd
└───

+┌───
+ DRI3GetSupportedModifiers
+ 1 CARD8 major opcode
+ 1 7 DRI3 opcode
+ 2 3 length
+ 4 Window window
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 2 unused
+ ▶
+ 1 1 Reply
+ 1 0 unused
+ 2 CARD16 sequence number
+ 4 CARD32 reply length
+ 4 CARD32 num_window_modifiers
+ 4 CARD32 num_screen_modifiers
+ 16 unused
+
+ 4 ListOfCARD64 window_modifiers[num_window_modifiers]
+ 4 ListOfCARD64 screen_modifiers[num_screen_modifiers]
+└───
+
+┌───
+ DRI3PixmapFromBuffers
+ 1 CARD8 major opcode
+ 1 8 DRI3 opcode
+ 2 8 length
+ 4 Pixmap pixmap
+ 4 Window window
+ 1 CARD8 num_buffers
+ 3 unused
+ 2 CARD16 width
+ 2 CARD16 height
+ 4 CARD32 stride0
+ 4 CARD32 offset0
+ 4 CARD32 stride1
+ 4 CARD32 offset1
+ 4 CARD32 stride2
+ 4 CARD32 offset2
+ 4 CARD32 stride3
+ 4 CARD32 offset3
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 2 unused
+ 8 CARD64 modifier
+
+ 0 ListOfFD buffers[num_buffers]
+└───
+
+┌───
+ DRI3BuffersFromPixmap
+ 1 CARD8 major opcode
+ 1 9 DRI3 opcode
+ 2 2 length
+ 4 Pixmap pixmap
+ ▶
+ 1 1 Reply
+ 1 CARD8 nfd
+ 2 CARD16 sequence number
+ 4 CARD32 reply length
+ 2 CARD16 width
+ 2 CARD16 height
+ 4 CARD8 unused
+ 8 CARD64 modifier
+ 1 CARD8 depth
+ 1 CARD8 bpp
+ 6 unused
+
+ 0 ListOfFD buffer[nfd]
+ 4 ListOfCARD32 strides[nfd]
+ 4 ListOfCARD32 offsets[nfd]
+└───
+
A.3 Protocol Events

The DRI3 extension defines no events.
diff --git a/include/X11/extensions/dri3proto.h b/include/X11/extensions/dri3proto.h
index ceddee8..51b825d 100644
--- a/include/X11/extensions/dri3proto.h
+++ b/include/X11/extensions/dri3proto.h
@@ -25,7 +25,7 @@

#define DRI3_NAME "DRI3"
#define DRI3_MAJOR 1
-#define DRI3_MINOR 0
+#define DRI3_MINOR 2

#define DRI3NumberErrors 0
#define DRI3NumberEvents 0
@@ -37,7 +37,12 @@
#define X_DRI3FenceFromFD 4
#define X_DRI3FDFromFence 5

-#define DRI3NumberRequests 6
+/* v1.2 */
+#define xDRI3GetSupportedModifiers 6
+#define xDRI3PixmapFromBuffers 7
+#define xDRI3BuffersFromPixmap 8
+
+#define DRI3NumberRequests 9

typedef struct {
CARD8 reqType;
@@ -164,4 +169,81 @@ typedef struct {

#define sz_xDRI3FDFromFenceReply 32

+/* v1.2 */
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 window B32;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad10 B16;
+} xDRI3GetSupportedModifiersReq;
+#define sz_xDRI3GetSupportedModifiersReq 12
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ CARD8 pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 numWindowModifiers B32;
+ CARD32 numScreenModifiers B32;
+ CARD32 pad16 B32;
+ CARD32 pad20 B32;
+ CARD32 pad24 B32;
+ CARD32 pad28 B32;
+} xDRI3GetSupportedModifiersReply;
+#define sz_xDRI3GetSupportedModifiersReply 32
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 pixmap B32;
+ CARD32 window B32;
+ CARD8 num_buffers; /* Number of file descriptors passed */
+ CARD8 pad13;
+ CARD16 pad14 B16;
+ CARD16 width B16;
+ CARD16 height B16;
+ CARD32 stride0 B32;
+ CARD32 offset0 B32;
+ CARD32 stride1 B32;
+ CARD32 offset1 B32;
+ CARD32 stride2 B32;
+ CARD32 offset2 B32;
+ CARD32 stride3 B32;
+ CARD32 offset3 B32;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad54 B16;
+ CARD64 modifier;
+} xDRI3PixmapFromBuffersReq;
+#define sz_xDRI3PixmapFromBuffersReq 64
+
+typedef struct {
+ CARD8 reqType;
+ CARD8 dri3ReqType;
+ CARD16 length B16;
+ CARD32 pixmap B32;
+} xDRI3BuffersFromPixmapReq;
+#define sz_xDRI3BuffersFromPixmapReq 8
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ CARD8 nfd; /* Number of file descriptors returned */
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD16 width B16;
+ CARD16 height B16;
+ CARD32 pad12 B32;
+ CARD64 modifier;
+ CARD8 depth;
+ CARD8 bpp;
+ CARD16 pad26 B16;
+ CARD32 pad28 B32;
+} xDRI3BuffersFromPixmapReply;
+#define sz_xDRI3BuffersFromPixmapReply 32
+
#endif
diff --git a/meson.build b/meson.build
index 9511029..cb92280 100644
--- a/meson.build
+++ b/meson.build
@@ -30,7 +30,7 @@ pcs = [
['damageproto', '1.2.1'],
['dmxproto', '2.3.1'],
['dri2proto', '2.8'],
- ['dri3proto', '1.0'],
+ ['dri3proto', '1.2'],
['fixesproto', '5.0'],
['fontsproto', '2.1.3'],
['glproto', '1.4.17'],
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http
Daniel Stone
2018-02-28 01:19:40 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

Retrieve IN_FORMATS property from the plane. It gives the
allowed formats and modifiers for BO allocation.

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 4 +
hw/xfree86/drivers/modesetting/drmmode_display.c | 114 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 9 ++
include/dix-config.h.in | 3 +
include/meson.build | 2 +
5 files changed, 128 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 46662867f..283d8e20c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2112,6 +2112,10 @@ if test "x$GLAMOR" = xyes; then
PKG_CHECK_EXISTS(libdrm >= 2.4.74,
[AC_DEFINE(GLAMOR_HAS_DRM_NAME_FROM_FD_2, 1, [Have GLAMOR_HAS_DRM_NAME_FROM_FD_2])],
[])
+
+ PKG_CHECK_EXISTS(libdrm >= 2.4.83,
+ [AC_DEFINE(GLAMOR_HAS_DRM_MODIFIERS, 1, [Have GLAMOR_HAS_DRM_MODIFIERS])],
+ [])
fi
AM_CONDITIONAL([GLAMOR_EGL], [test "x$GBM" = xyes])

diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 3e3613a98..7af805da2 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -56,6 +56,23 @@ static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
int depth, int bitsPerPixel, int devKind,
void *pPixData);
+
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+
+static inline uint32_t *
+formats_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (uint32_t *)(((char *)blob) + blob->formats_offset);
+}
+
+static inline struct drm_format_modifier *
+modifiers_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
+}
+
+#endif
+
static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
{
@@ -1532,15 +1549,76 @@ is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
return FALSE;
}

+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+/**
+ * Populates the formats array, and the modifiers of each format for a drm_plane.
+ */
+static Bool
+populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
+ uint32_t blob_id)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ unsigned i, j;
+ drmModePropertyBlobRes *blob;
+ struct drm_format_modifier_blob *fmt_mod_blob;
+ uint32_t *blob_formats;
+ struct drm_format_modifier *blob_modifiers;
+
+ blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
+ if (!blob)
+ return FALSE;
+
+ fmt_mod_blob = blob->data;
+ blob_formats = formats_ptr(fmt_mod_blob);
+ blob_modifiers = modifiers_ptr(fmt_mod_blob);
+
+ assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
+
+ for (i = 0; i < fmt_mod_blob->count_formats; i++) {
+ uint32_t num_modifiers = 0;
+ uint64_t *modifiers = NULL;
+ uint64_t *tmp;
+
+ for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
+ struct drm_format_modifier *mod = &blob_modifiers[j];
+
+ if ((i < mod->offset) || (i > mod->offset + 63))
+ continue;
+ if (!(mod->formats & (1 << (i - mod->offset))))
+ continue;
+
+ num_modifiers++;
+ tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
+ if (!tmp) {
+ free(modifiers);
+ drmModeFreePropertyBlob(blob);
+ return FALSE;
+ }
+ modifiers = tmp;
+ modifiers[num_modifiers - 1] = mod->modifier;
+ }
+
+ drmmode_crtc->formats[i].format = blob_formats[i];
+ drmmode_crtc->formats[i].modifiers = modifiers;
+ drmmode_crtc->formats[i].num_modifiers = num_modifiers;
+ }
+
+ drmModeFreePropertyBlob(blob);
+
+ return TRUE;
+}
+#endif
+
static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmModePlaneRes *kplane_res;
- drmModePlane *kplane;
+ drmModePlane *kplane, *best_kplane = NULL;
drmModeObjectProperties *props;
- uint32_t i, type;
+ uint32_t i, type, blob_id;
int current_crtc, best_plane = 0;

static drmmode_prop_enum_info_rec plane_type_enums[] = {
@@ -1562,6 +1640,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
},
[DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
[DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
+ [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
[DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
[DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
[DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
@@ -1602,13 +1681,13 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
}

plane_id = kplane->plane_id;
- drmModeFreePlane(kplane);

props = drmModeObjectGetProperties(drmmode->fd, plane_id,
DRM_MODE_OBJECT_PLANE);
if (!props) {
xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
"couldn't get plane properties\n");
+ drmModeFreePlane(kplane);
continue;
}

@@ -1618,6 +1697,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
props, DRMMODE_PLANE_TYPE__COUNT);
if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
+ drmModeFreePlane(kplane);
drmModeFreeObjectProperties(props);
continue;
}
@@ -1626,9 +1706,14 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
props, 0);
if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
- if (best_plane)
+ if (best_plane) {
+ drmModeFreePlane(best_kplane);
drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
+ }
best_plane = plane_id;
+ best_kplane = kplane;
+ blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+ props, 0);
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
DRMMODE_PLANE__COUNT, 1);
drmModeFreeObjectProperties(props);
@@ -1637,14 +1722,35 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)

if (!best_plane) {
best_plane = plane_id;
+ best_kplane = kplane;
+ blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
+ props, 0);
drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
DRMMODE_PLANE__COUNT, 1);
+ } else {
+ drmModeFreePlane(kplane);
}

drmModeFreeObjectProperties(props);
}

drmmode_crtc->plane_id = best_plane;
+ if (best_kplane) {
+ drmmode_crtc->num_formats = best_kplane->count_formats;
+ drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
+ best_kplane->count_formats);
+#ifdef GLAMOR_HAS_DRM_MODIFIERS
+ if (blob_id) {
+ populate_format_modifiers(crtc, best_kplane, blob_id);
+ }
+ else
+#endif
+ {
+ for (i = 0; i < best_kplane->count_formats; i++)
+ drmmode_crtc->formats[i].format = best_kplane->formats[i];
+ }
+ drmModeFreePlane(best_kplane);
+ }

drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
drmModeFreePlaneResources(kplane_res);
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h
index e5f3542c5..75e4b8499 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.h
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.h
@@ -39,6 +39,7 @@ struct gbm_device;
enum drmmode_plane_property {
DRMMODE_PLANE_TYPE = 0,
DRMMODE_PLANE_FB_ID,
+ DRMMODE_PLANE_IN_FORMATS,
DRMMODE_PLANE_CRTC_ID,
DRMMODE_PLANE_SRC_X,
DRMMODE_PLANE_SRC_Y,
@@ -142,6 +143,12 @@ typedef struct {
struct xorg_list entry;
} drmmode_mode_rec, *drmmode_mode_ptr;

+typedef struct {
+ uint32_t format;
+ uint32_t num_modifiers;
+ uint64_t *modifiers;
+} drmmode_format_rec, *drmmode_format_ptr;
+
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
@@ -155,6 +162,8 @@ typedef struct {
drmmode_prop_info_rec props_plane[DRMMODE_PLANE__COUNT];
uint32_t plane_id;
drmmode_mode_ptr current_mode;
+ uint32_t num_formats;
+ drmmode_format_rec *formats;

drmmode_bo rotate_bo;
unsigned rotate_fb_id;
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 9f8dc913f..65d655ca8 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -494,6 +494,9 @@
/* Glamor should use atomic DRM API */
#undef GLAMOR_HAS_DRM_ATOMIC

+/* Glamor can retrieve supported DRM formats/modifiers */
+#undef GLAMOR_HAS_DRM_MODIFIERS
+
/* byte order */
#undef X_BYTE_ORDER

diff --git a/include/meson.build b/include/meson.build
index dceca2b7d..bbb7d14e8 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -78,6 +78,8 @@ conf_data.set('GLAMOR_HAS_DRM_ATOMIC',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.62'))
conf_data.set('GLAMOR_HAS_DRM_NAME_FROM_FD_2',
libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.74'))
+conf_data.set('GLAMOR_HAS_DRM_MODIFIERS',
+ libdrm_dep.found() and libdrm_dep.version().version_compare('>= 2.4.83'))
conf_data.set('GLXEXT', build_glx)
conf_data.set('GLAMOR', build_glamor)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists
Daniel Stone
2018-02-28 01:19:43 UTC
Permalink
From: Louis-Francis Ratté-Boulianne <***@collabora.com>

It relies on GBM >= 17.1.0 where we can import BO with multiple
planes and a format modifier (GBM_BO_IMPORT_FD_MODIFIER).

v2: Properly free fds in Xwayland

Signed-off-by: Louis-Francis Ratté-Boulianne <***@collabora.com>
Reviewed-by: Daniel Stone <***@collabora.com>
---
configure.ac | 4 +
glamor/glamor.c | 37 ++++---
glamor/glamor.h | 65 +++++++------
glamor/glamor_egl.c | 136 ++++++++++++++++++++++----
glamor/glamor_egl.h | 1 +
glamor/glamor_egl_ext.h | 65 +++++++++++++
glamor/glamor_egl_stubs.c | 16 ++-
hw/xwayland/.gitignore | 2 +
hw/xwayland/Makefile.am | 10 +-
hw/xwayland/meson.build | 5 +-
hw/xwayland/xwayland-glamor.c | 219 ++++++++++++++++++++++++++++++++----------
hw/xwayland/xwayland.c | 6 +-
hw/xwayland/xwayland.h | 10 +-
include/dix-config.h.in | 3 +
include/meson.build | 2 +
15 files changed, 461 insertions(+), 120 deletions(-)
create mode 100644 glamor/glamor_egl_ext.h

diff --git a/configure.ac b/configure.ac
index 283d8e20c..392511541 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2100,6 +2100,10 @@ if test "x$GLAMOR" = xyes; then
[AC_DEFINE(GLAMOR_HAS_GBM_LINEAR, 1, [Have GBM_BO_USE_LINEAR])], [],
[#include <stdlib.h>
#include <gbm.h>])
+ dnl 17.1.0 is required for gbm_bo_create_with_modifiers
+ PKG_CHECK_EXISTS(gbm >= 17.1.0,
+ [AC_DEFINE(GBM_BO_WITH_MODIFIERS, 1, [Have gbm_bo_create_with_modifiers])],
+ [])
else
if test "x$XORG" = xyes; then
AC_MSG_ERROR([Glamor for Xorg requires $LIBGBM])
diff --git a/glamor/glamor.c b/glamor/glamor.c
index d61e27563..c890d0ce0 100644
--- a/glamor/glamor.c
+++ b/glamor/glamor.c
@@ -32,6 +32,7 @@
*/

#include <stdlib.h>
+#include <unistd.h>

#include "glamor_priv.h"
#include "mipict.h"
@@ -793,8 +794,9 @@ glamor_supports_pixmap_import_export(ScreenPtr screen)
}

_X_EXPORT int
-glamor_fd_from_pixmap(ScreenPtr screen,
- PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
+glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+ uint32_t *strides, uint32_t *offsets,
+ uint64_t *modifier)
{
glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
glamor_screen_private *glamor_priv =
@@ -808,10 +810,9 @@ glamor_fd_from_pixmap(ScreenPtr screen,
if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
GL_RGB10_A2 : GL_RGBA, 0))
return -1;
- return glamor_egl_dri3_fd_name_from_tex(screen,
- pixmap,
- pixmap_priv->fbo->tex,
- FALSE, stride, size);
+ return glamor_egl_fds_from_pixmap(screen, pixmap, fds,
+ strides, offsets,
+ modifier);
default:
break;
}
@@ -824,6 +825,9 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen,
{
unsigned orig_usage_hint = pixmap->usage_hint;
int ret;
+ int fds[4];
+ uint32_t strides[4], offsets[4];
+ uint64_t modifier;

/*
* The actual difference between a sharable and non sharable buffer
@@ -832,7 +836,20 @@ glamor_shareable_fd_from_pixmap(ScreenPtr screen,
* 2 of those calls are also exported API, so we cannot just add a flag.
*/
pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED;
- ret = glamor_fd_from_pixmap(screen, pixmap, stride, size);
+ ret = glamor_fds_from_pixmap(screen, pixmap, fds, strides, offsets,
+ &modifier);
+
+ /* Pixmaps with multi-planes/modifier are not shareable */
+ if (ret > 1) {
+ while (ret > 0)
+ close(fds[--ret]);
+ return -1;
+ }
+
+ ret = fds[0];
+ *stride = strides[0];
+ *size = pixmap->drawable.height * *stride;
+
pixmap->usage_hint = orig_usage_hint;

return ret;
@@ -849,10 +866,8 @@ glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
GL_RGB10_A2 : GL_RGBA, 0))
return -1;
- return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen,
- pixmap,
- pixmap_priv->fbo->tex,
- TRUE, stride, size);
+ return glamor_egl_fd_name_from_pixmap(pixmap->drawable.pScreen,
+ pixmap, stride, size);
default:
break;
}
diff --git a/glamor/glamor.h b/glamor/glamor.h
index 5b15a46e5..8f8c31b45 100644
--- a/glamor/glamor.h
+++ b/glamor/glamor.h
@@ -138,15 +138,17 @@ extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front,

/* The DDX is not supposed to call these three functions */
extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen);
-extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr,
- unsigned int, Bool,
- CARD16 *, CARD32 *);
+extern _X_EXPORT int glamor_egl_fds_from_pixmap(ScreenPtr, PixmapPtr, int *,
+ uint32_t *, uint32_t *,
+ uint64_t *);
+extern _X_EXPORT int glamor_egl_fd_name_from_pixmap(ScreenPtr, PixmapPtr,
+ CARD16 *, CARD32 *);

extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen);

/* @glamor_supports_pixmap_import_export: Returns whether
- * glamor_fd_from_pixmap(), glamor_name_from_pixmap(), and
- * glamor_pixmap_from_fd() are supported.
+ * glamor_fds_from_pixmap(), glamor_name_from_pixmap(), and
+ * glamor_pixmap_from_fds() are supported.
*
* @screen: Current screen pointer.
*
@@ -159,20 +161,22 @@ extern _X_EXPORT struct gbm_device *glamor_egl_get_gbm_device(ScreenPtr screen);
* */
extern _X_EXPORT Bool glamor_supports_pixmap_import_export(ScreenPtr screen);

-/* @glamor_fd_from_pixmap: Get a dma-buf fd from a pixmap.
+/* @glamor_fds_from_pixmap: Get a dma-buf fd from a pixmap.
*
* @screen: Current screen pointer.
* @pixmap: The pixmap from which we want the fd.
- * @stride, @size: Pointers to fill the stride and size of the
- * buffer associated to the fd.
+ * @fds, @strides, @offsets: Pointers to fill info of each plane.
+ * @modifier: Pointer to fill the modifier of the buffer.
*
- * the pixmap and the buffer associated by the fd will share the same
- * content.
- * Returns the fd on success, -1 on error.
+ * the pixmap and the buffer associated by the fds will share the same
+ * content. The caller is responsible to close the returned file descriptors.
+ * Returns the number of planes, -1 on error.
* */
-extern _X_EXPORT int glamor_fd_from_pixmap(ScreenPtr screen,
- PixmapPtr pixmap,
- CARD16 *stride, CARD32 *size);
+extern _X_EXPORT int glamor_fds_from_pixmap(ScreenPtr screen,
+ PixmapPtr pixmap,
+ int *fds,
+ uint32_t *strides, uint32_t *offsets,
+ uint64_t *modifier);

/* @glamor_shareable_fd_from_pixmap: Get a dma-buf fd suitable for sharing
* with other GPUs from a pixmap.
@@ -224,25 +228,30 @@ extern _X_EXPORT int glamor_name_from_pixmap(PixmapPtr pixmap,
extern _X_EXPORT struct gbm_bo *glamor_gbm_bo_from_pixmap(ScreenPtr screen,
PixmapPtr pixmap);

-/* @glamor_pixmap_from_fd: Creates a pixmap to wrap a dma-buf fd.
+/* @glamor_pixmap_from_fds: Creates a pixmap to wrap a dma-buf fds.
*
* @screen: Current screen pointer.
- * @fd: The dma-buf fd to import.
- * @width: The width of the buffer.
- * @height: The height of the buffer.
- * @stride: The stride of the buffer.
- * @depth: The depth of the buffer.
- * @bpp: The number of bpp of the buffer.
+ * @num_fds: Number of fds to import
+ * @fds: The dma-buf fds to import.
+ * @width: The width of the buffers.
+ * @height: The height of the buffers.
+ * @stride: The stride of the buffers.
+ * @depth: The depth of the buffers.
+ * @bpp: The bpp of the buffers.
+ * @modifier: The modifier of the buffers.
*
* Returns a valid pixmap if the import succeeded, else NULL.
* */
-extern _X_EXPORT PixmapPtr glamor_pixmap_from_fd(ScreenPtr screen,
- int fd,
- CARD16 width,
- CARD16 height,
- CARD16 stride,
- CARD8 depth,
- CARD8 bpp);
+extern _X_EXPORT PixmapPtr glamor_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds,
+ int *fds,
+ CARD16 width,
+ CARD16 height,
+ CARD32 *strides,
+ CARD32 *offsets,
+ CARD8 depth,
+ CARD8 bpp,
+ uint64_t modifier);

/* @glamor_back_pixmap_from_fd: Backs an existing pixmap with a dma-buf fd.
*
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
index eb5e68b8e..cf2513491 100644
--- a/glamor/glamor_egl.c
+++ b/glamor/glamor_egl.c
@@ -56,6 +56,7 @@ struct glamor_egl_screen_private {
CloseScreenProcPtr CloseScreen;
int fd;
struct gbm_device *gbm;
+ int dmabuf_capable;

CloseScreenProcPtr saved_close_screen;
DestroyPixmapProcPtr saved_destroy_pixmap;
@@ -330,10 +331,51 @@ glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap)
}

int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
- PixmapPtr pixmap,
- unsigned int tex,
- Bool want_name, CARD16 *stride, CARD32 *size)
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+ uint32_t *strides, uint32_t *offsets,
+ uint64_t *modifier)
+{
+#ifdef GLAMOR_HAS_GBM
+ struct gbm_bo *bo;
+ int num_fds;
+#ifdef GBM_BO_WITH_MODIFIERS
+ int i;
+#endif
+
+ if (!glamor_make_pixmap_exportable(pixmap))
+ return 0;
+
+ bo = glamor_gbm_bo_from_pixmap(screen, pixmap);
+ if (!bo)
+ return 0;
+
+#ifdef GBM_BO_WITH_MODIFIERS
+ num_fds = gbm_bo_get_plane_count(bo);
+ for (i = 0; i < num_fds; i++) {
+ fds[i] = gbm_bo_get_fd(bo);
+ strides[i] = gbm_bo_get_stride_for_plane(bo, i);
+ offsets[i] = gbm_bo_get_offset(bo, i);
+ }
+ *modifier = gbm_bo_get_modifier(bo);
+#else
+ num_fds = 1;
+ fds[0] = gbm_bo_get_fd(bo);
+ strides[0] = gbm_bo_get_stride(bo);
+ offsets[0] = 0;
+ *modifier = DRM_FORMAT_MOD_INVALID;
+#endif
+
+ gbm_bo_destroy(bo);
+ return num_fds;
+#else
+ return 0;
+#endif
+}
+
+int
+glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
+ PixmapPtr pixmap,
+ CARD16 *stride, CARD32 *size)
{
struct glamor_egl_screen_private *glamor_egl;
struct gbm_bo *bo;
@@ -347,12 +389,7 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,

pixmap->devKind = gbm_bo_get_stride(bo);

- if (want_name) {
- glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
- }
- else {
- fd = gbm_bo_get_fd(bo);
- }
+ glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
*stride = pixmap->devKind;
*size = pixmap->devKind * gbm_bo_get_height(bo);

@@ -399,19 +436,68 @@ 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;
+ default:
+ ErrorF("unexpected depth: %d\n", depth);
+ case 32:
+ return GBM_FORMAT_ARGB8888;
+ }
+}
+
_X_EXPORT PixmapPtr
-glamor_pixmap_from_fd(ScreenPtr screen,
- int fd,
- CARD16 width,
- CARD16 height,
- CARD16 stride, CARD8 depth, CARD8 bpp)
+glamor_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp,
+ uint64_t modifier)
{
PixmapPtr pixmap;
- Bool ret;
+ struct glamor_egl_screen_private *glamor_egl;
+ Bool ret = FALSE;
+ int i;
+
+ glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen));

pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
- ret = glamor_back_pixmap_from_fd(pixmap, fd, width, height,
- stride, depth, bpp);
+
+#ifdef GBM_BO_WITH_MODIFIERS
+ if (glamor_egl->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
+ struct gbm_import_fd_modifier_data import_data = { 0 };
+ struct gbm_bo *bo;
+
+ import_data.width = width;
+ import_data.height = height;
+ import_data.num_fds = num_fds;
+ import_data.modifier = modifier;
+ for (i = 0; i < num_fds; i++) {
+ import_data.fds[i] = fds[i];
+ 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);
+ ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
+ gbm_bo_destroy(bo);
+ }
+ } else
+#endif
+ {
+ if (num_fds == 1) {
+ ret = glamor_back_pixmap_from_fd(pixmap, fds[0], width, height,
+ strides[0], depth, bpp);
+ }
+ }
+
if (ret == FALSE) {
screen->DestroyPixmap(pixmap);
return NULL;
@@ -536,10 +622,10 @@ glamor_dri3_open_client(ClientPtr client,
}

static dri3_screen_info_rec glamor_dri3_info = {
- .version = 1,
+ .version = 2,
.open_client = glamor_dri3_open_client,
- .pixmap_from_fd = glamor_pixmap_from_fd,
- .fd_from_pixmap = glamor_fd_from_pixmap,
+ .pixmap_from_fds = glamor_pixmap_from_fds,
+ .fds_from_pixmap = glamor_egl_fds_from_pixmap,
};
#endif /* DRI3 */

@@ -737,6 +823,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
xf86DrvMsg(scrn->scrnIndex, X_INFO, "glamor X acceleration enabled on %s\n",
glGetString(GL_RENDERER));

+#ifdef GBM_BO_WITH_MODIFIERS
+ if (epoxy_has_egl_extension(glamor_egl->display,
+ "EGL_EXT_image_dma_buf_import") &&
+ epoxy_has_egl_extension(glamor_egl->display,
+ "EGL_EXT_image_dma_buf_import_modifiers"))
+ glamor_egl->dmabuf_capable = TRUE;
+#endif
+
glamor_egl->saved_free_screen = scrn->FreeScreen;
scrn->FreeScreen = glamor_egl_free_screen;
return TRUE;
diff --git a/glamor/glamor_egl.h b/glamor/glamor_egl.h
index 6bb1185bf..2f7566b24 100644
--- a/glamor/glamor_egl.h
+++ b/glamor/glamor_egl.h
@@ -30,6 +30,7 @@
#define MESA_EGL_NO_X11_HEADERS
#include <epoxy/gl.h>
#include <epoxy/egl.h>
+#include <glamor_egl_ext.h>

/*
* Create an EGLDisplay from a native display type. This is a little quirky
diff --git a/glamor/glamor_egl_ext.h b/glamor/glamor_egl_ext.h
new file mode 100644
index 000000000..436e52137
--- /dev/null
+++ b/glamor/glamor_egl_ext.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, 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.
+ */
+/* Extensions used by Glamor, copied from Mesa's eglmesaext.h, */
+
+#ifndef GLAMOR_EGL_EXT_H
+#define GLAMOR_EGL_EXT_H
+
+/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
+ * here to avoid having to add ifdefs everywhere.*/
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#endif
+
+/* Define tokens from EGL_EXT_image_dma_buf_import_modifiers */
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_EXT_image_dma_buf_import_modifiers 1
+#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#endif
+
+#endif /* GLAMOR_EGL_EXT_H */
diff --git a/glamor/glamor_egl_stubs.c b/glamor/glamor_egl_stubs.c
index 40f7fcc01..aae909e9f 100644
--- a/glamor/glamor_egl_stubs.c
+++ b/glamor/glamor_egl_stubs.c
@@ -36,10 +36,18 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx)
}

int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
- PixmapPtr pixmap,
- unsigned int tex,
- Bool want_name, CARD16 *stride, CARD32 *size)
+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;
}
diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore
index 38ada56d1..c0320b555 100644
--- a/hw/xwayland/.gitignore
+++ b/hw/xwayland/.gitignore
@@ -5,3 +5,5 @@ pointer-constraints-unstable-v1-client-protocol.h
pointer-constraints-unstable-v1-protocol.c
relative-pointer-unstable-v1-client-protocol.h
relative-pointer-unstable-v1-protocol.c
+linux-dmabuf-unstable-v1-client-protocol.h
+linux-dmabuf-unstable-v1-protocol.c
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 173686e31..f44a7ded3 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -62,8 +62,9 @@ Xwayland_built_sources += \
xwayland-keyboard-grab-unstable-v1-protocol.c \
xwayland-keyboard-grab-unstable-v1-client-protocol.h \
xdg-output-unstable-v1-protocol.c \
- xdg-output-unstable-v1-client-protocol.h
-
+ xdg-output-unstable-v1-client-protocol.h \
+ linux-dmabuf-unstable-v1-client-protocol.h \
+ linux-dmabuf-unstable-v1-protocol.c

nodist_Xwayland_SOURCES = $(Xwayland_built_sources)
CLEANFILES = $(Xwayland_built_sources)
@@ -100,6 +101,11 @@ xdg-output-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-ou
xdg-output-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@

+linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
+ $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
+linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
+ $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+
%-protocol.c : %.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@

diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index f6f75001c..7e24c5d63 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -12,7 +12,7 @@ srcs = [
scanner_dep = dependency('wayland-scanner', native: true)
scanner = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner'))

-protocols_dep = dependency('wayland-protocols')
+protocols_dep = dependency('wayland-protocols', version: '>= 1.8')
protodir = protocols_dep.get_pkgconfig_variable('pkgdatadir')

pointer_xml = join_paths(protodir, 'unstable', 'pointer-constraints', 'pointer-constraints-unstable-v1.xml')
@@ -20,6 +20,7 @@ relative_xml = join_paths(protodir, 'unstable', 'relative-pointer', 'relative-po
tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml')
kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml')
xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml')
+dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')

client_header = generator(scanner,
output : '@BASENAME@-client-protocol.h',
@@ -34,11 +35,13 @@ srcs += client_header.process(pointer_xml)
srcs += client_header.process(tablet_xml)
srcs += client_header.process(kbgrab_xml)
srcs += client_header.process(xdg_output_xml)
+srcs += client_header.process(dmabuf_xml)
srcs += code.process(relative_xml)
srcs += code.process(pointer_xml)
srcs += code.process(tablet_xml)
srcs += code.process(kbgrab_xml)
srcs += code.process(xdg_output_xml)
+srcs += code.process(dmabuf_xml)

xwayland_glamor = []
if gbm_dep.found()
diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c
index 0933e9411..774a18893 100644
--- a/hw/xwayland/xwayland-glamor.c
+++ b/hw/xwayland/xwayland-glamor.c
@@ -28,6 +28,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <xf86drm.h>
+#include <drm_fourcc.h>

#define MESA_EGL_NO_X11_HEADERS
#include <gbm.h>
@@ -158,25 +159,65 @@ xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap)
struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
int prime_fd;
+ int num_planes;
+ uint32_t strides[4];
+ uint32_t offsets[4];
+ uint64_t modifier;
+ int i;

if (xwl_pixmap->buffer)
return xwl_pixmap->buffer;

+ if (!xwl_pixmap->bo)
+ return NULL;
+
prime_fd = gbm_bo_get_fd(xwl_pixmap->bo);
if (prime_fd == -1)
return NULL;

- xwl_pixmap->buffer =
- wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
- pixmap->drawable.width,
- pixmap->drawable.height,
- wl_drm_format_for_depth(pixmap->drawable.depth),
- 0, gbm_bo_get_stride(xwl_pixmap->bo),
- 0, 0,
- 0, 0);
+#ifdef GBM_BO_WITH_MODIFIERS
+ num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo);
+ modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+ for (i = 0; i < num_planes; i++) {
+ strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+ offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+ }
+#else
+ num_planes = 1;
+ modifier = DRM_FORMAT_MOD_INVALID;
+ strides[0] = gbm_go_get_stride(xwl_pixmap->bo);
+ offsets[0] = 0;
+#endif

- close(prime_fd);
+ if (xwl_screen->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) {
+ struct zwp_linux_buffer_params_v1 *params;
+
+ params = zwp_linux_dmabuf_v1_create_params(xwl_screen->dmabuf);
+ for (i = 0; i < num_planes; i++) {
+ zwp_linux_buffer_params_v1_add(params, prime_fd, i,
+ offsets[i], strides[i],
+ modifier >> 32, modifier & 0xffffffff);
+ }
+
+ xwl_pixmap->buffer =
+ zwp_linux_buffer_params_v1_create_immed(params,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ wl_drm_format_for_depth(pixmap->drawable.depth),
+ 0);
+ zwp_linux_buffer_params_v1_destroy(params);
+ } else if (num_planes == 1) {
+ xwl_pixmap->buffer =
+ wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ wl_drm_format_for_depth(pixmap->drawable.depth),
+ 0, gbm_bo_get_stride(xwl_pixmap->bo),
+ 0, 0,
+ 0, 0);
+ }

+ close(prime_fd);
return xwl_pixmap->buffer;
}

@@ -213,7 +254,8 @@ xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
wl_buffer_destroy(xwl_pixmap->buffer);

eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
- gbm_bo_destroy(xwl_pixmap->bo);
+ if (xwl_pixmap->bo)
+ gbm_bo_destroy(xwl_pixmap->bo);
free(xwl_pixmap);
}

@@ -282,8 +324,6 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
if (xwl_screen->egl_display)
return;

- xwl_screen->expecting_event--;
-
xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd);
if (xwl_screen->gbm == NULL) {
ErrorF("couldn't get display device\n");
@@ -327,6 +367,12 @@ xwl_drm_init_egl(struct xwl_screen *xwl_screen)
return;
}

+ if (epoxy_has_egl_extension(xwl_screen->egl_display,
+ "EXT_image_dma_buf_import") &&
+ epoxy_has_egl_extension(xwl_screen->egl_display,
+ "EXT_image_dma_buf_import_modifiers"))
+ xwl_screen->dmabuf_capable = TRUE;
+
return;
}

@@ -347,12 +393,14 @@ xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
return;
}

+ xwl_screen->expecting_event--;
+
if (is_fd_render_node(xwl_screen->drm_fd)) {
xwl_screen->fd_render_node = 1;
- xwl_drm_init_egl(xwl_screen);
} else {
drmGetMagic(xwl_screen->drm_fd, &magic);
wl_drm_authenticate(xwl_screen->drm, magic);
+ xwl_screen->expecting_event++; /* wait for 'authenticated' */
}
}

@@ -379,8 +427,8 @@ xwl_drm_handle_authenticated(void *data, struct wl_drm *drm)
{
struct xwl_screen *xwl_screen = data;

- if (!xwl_screen->egl_display)
- xwl_drm_init_egl(xwl_screen);
+ xwl_screen->drm_authenticated = 1;
+ xwl_screen->expecting_event--;
}

static void
@@ -399,8 +447,8 @@ static const struct wl_drm_listener xwl_drm_listener = {
};

Bool
-xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
- uint32_t id, uint32_t version)
+xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
+ uint32_t id, uint32_t version)
{
if (version < 2)
return FALSE;
@@ -413,11 +461,23 @@ xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
return TRUE;
}

+Bool
+xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
+ uint32_t id, uint32_t version)
+{
+ if (version < 3)
+ return FALSE;
+
+ xwl_screen->dmabuf =
+ wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+
+ return TRUE;
+}
+
int
-glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
- PixmapPtr pixmap,
- unsigned int tex,
- Bool want_name, CARD16 *stride, CARD32 *size)
+glamor_egl_fd_name_from_pixmap(ScreenPtr screen,
+ PixmapPtr pixmap,
+ CARD16 *stride, CARD32 *size)
{
return 0;
}
@@ -518,58 +578,111 @@ xwl_dri3_open_client(ClientPtr client,
return Success;
}

-static PixmapPtr
-xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd,
- CARD16 width, CARD16 height, CARD16 stride,
- CARD8 depth, CARD8 bpp)
+_X_EXPORT PixmapPtr
+glamor_pixmap_from_fds(ScreenPtr screen,
+ CARD8 num_fds, int *fds,
+ CARD16 width, CARD16 height,
+ CARD32 *strides, CARD32 *offsets,
+ CARD8 depth, CARD8 bpp, uint64_t modifier)
{
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
- struct gbm_import_fd_data data;
- struct gbm_bo *bo;
+ struct gbm_bo *bo = NULL;
PixmapPtr pixmap;
+ int i;
+
+ if (width == 0 || height == 0 || num_fds == 0 ||
+ depth < 15 || bpp != BitsPerPixel(depth) ||
+ strides[0] < width * bpp / 8)
+ goto error;
+
+ if (xwl_screen->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) {
+#ifdef GBM_BO_WITH_MODIFIERS
+ struct gbm_import_fd_modifier_data data;
+
+ data.width = width;
+ data.height = height;
+ data.num_fds = num_fds;
+ data.format = gbm_format_for_depth(depth);
+ data.modifier = modifier;
+ for (i = 0; i < num_fds; i++) {
+ data.fds[i] = fds[i];
+ data.strides[i] = strides[i];
+ data.offsets[i] = offsets[i];
+ }
+ bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
+#endif
+ } else if (num_fds == 1) {
+ struct gbm_import_fd_data data;
+
+ data.fd = fds[0];
+ data.width = width;
+ data.height = height;
+ data.stride = strides[0];
+ data.format = gbm_format_for_depth(depth);
+ bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ } else {
+ goto error;
+ }

- if (width == 0 || height == 0 ||
- depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8)
- return NULL;
-
- data.fd = fd;
- data.width = width;
- data.height = height;
- data.stride = stride;
- data.format = gbm_format_for_depth(depth);
- bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data,
- GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (bo == NULL)
- return NULL;
+ goto error;

pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth);
if (pixmap == NULL) {
- gbm_bo_destroy(bo);
- return NULL;
+ gbm_bo_destroy(bo);
+ goto error;
}

return pixmap;
+
+error:
+ for (i = 0; i < num_fds; i++)
+ close(fds[i]);
+ return NULL;
}

-static int
-xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
- CARD16 *stride, CARD32 *size)
+_X_EXPORT int
+glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
+ uint32_t *strides, uint32_t *offsets,
+ uint64_t *modifier)
{
struct xwl_pixmap *xwl_pixmap;
+#ifdef GBM_BO_WITH_MODIFIERS
+ uint32_t num_fds;
+ int i;
+#endif

xwl_pixmap = xwl_pixmap_get(pixmap);

- *stride = gbm_bo_get_stride(xwl_pixmap->bo);
- *size = pixmap->drawable.width * *stride;
+ if (!xwl_pixmap->bo)
+ return 0;

- return gbm_bo_get_fd(xwl_pixmap->bo);
+#ifdef GBM_BO_WITH_MODIFIERS
+ num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo);
+ *modifier = gbm_bo_get_modifier(xwl_pixmap->bo);
+
+ for (i = 0; i < num_fds; i++) {
+ fds[i] = gbm_bo_get_fd(xwl_pixmap->bo);
+ strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i);
+ offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i);
+ }
+
+ return num_fds;
+#else
+ *modifier = DRM_FORMAT_MOD_INVALID;
+ fds[0] = gbm_bo_get_fd(xwl_pixmap->bo);
+ strides[0] = gbm_bo_get_stride(xwl_pixmap->bo);
+ offsets[0] = 0;
+ return 1;
+#endif
}

static dri3_screen_info_rec xwl_dri3_info = {
- .version = 1,
+ .version = 2,
.open = NULL,
- .pixmap_from_fd = xwl_dri3_pixmap_from_fd,
- .fd_from_pixmap = xwl_dri3_fd_from_pixmap,
+ .pixmap_from_fds = glamor_pixmap_from_fds,
+ .fds_from_pixmap = glamor_fds_from_pixmap,
.open_client = xwl_dri3_open_client,
};

@@ -585,6 +698,12 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
return FALSE;
}

+ if (!xwl_screen->fd_render_node && !xwl_screen->drm_authenticated) {
+ ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n");
+ return FALSE;
+ }
+
+ xwl_drm_init_egl(xwl_screen);
if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
ErrorF("Disabling glamor and dri3, EGL setup failed\n");
return FALSE;
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 73bc47a67..d6a2887ac 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -728,7 +728,11 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
#ifdef GLAMOR_HAS_GBM
else if (xwl_screen->glamor &&
strcmp(interface, "wl_drm") == 0 && version >= 2) {
- xwl_screen_init_glamor(xwl_screen, id, version);
+ xwl_screen_set_drm_interface(xwl_screen, id, version);
+ }
+ else if (xwl_screen->glamor &&
+ strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
+ xwl_screen_set_dmabuf_interface(xwl_screen, id, version);
}
#endif
}
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index ffa0d7297..be95bab55 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -47,6 +47,7 @@
#include "tablet-unstable-v2-client-protocol.h"
#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"

struct xwl_screen {
int width;
@@ -96,12 +97,15 @@ struct xwl_screen {
char *device_name;
int drm_fd;
int fd_render_node;
+ int drm_authenticated;
struct wl_drm *drm;
+ struct zwp_linux_dmabuf_v1 *dmabuf;
uint32_t formats;
uint32_t capabilities;
void *egl_display, *egl_context;
struct gbm_device *gbm;
struct glamor_context *glamor_ctx;
+ int dmabuf_capable;

Atom allow_commits_prop;
};
@@ -326,8 +330,10 @@ struct wl_buffer *xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap);

Bool xwl_glamor_init(struct xwl_screen *xwl_screen);

-Bool xwl_screen_init_glamor(struct xwl_screen *xwl_screen,
- uint32_t id, uint32_t version);
+Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
+ uint32_t id, uint32_t version);
+Bool xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
+ uint32_t id, uint32_t version);
struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);

void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen);
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 65d655ca8..ea932c46d 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -488,6 +488,9 @@
/* Build glamor/gbm has linear support */
#undef GLAMOR_HAS_GBM_LINEAR

+/* GBM has modifiers support */
+#undef GBM_BO_WITH_MODIFIERS
+
/* Build glamor use new drmGetDeviceNameFromFD2 */
#undef GLAMOR_HAS_DRM_NAME_FROM_FD_2

diff --git a/include/meson.build b/include/meson.build
index bbb7d14e8..88ced768f 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -85,6 +85,8 @@ conf_data.set('GLAMOR', build_glamor)
conf_data.set('GLAMOR_HAS_GBM', gbm_dep.found())
conf_data.set('GLAMOR_HAS_GBM_LINEAR',
gbm_dep.found() and gbm_dep.version().version_compare('>= 10.6'))
+conf_data.set('GBM_BO_WITH_MODIFIERS',
+ gbm_dep.found() and gbm_dep.version().version_compare('>= 17.1'))

conf_data.set_quoted('SERVER_MISC_CONFIG_PATH', serverconfigdir)
conf_data.set_quoted('PROJECTROOT', get_option('prefix'))
--
2.14.3

_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinf
Daniel Stone
2018-02-28 01:45:32 UTC
Permalink
Hi,
The major change is that the DRI3 protocol version has been bumped from
1.1 to 1.2, as there was previously a dri3proto-1.1 release, only
carrying a 1.0 protocol version. We bump the version to avoid this,
jumping straight from protocol version 1.0 to 1.2.
Wrong protocol.

Present needed to be bumped to 1.2, and DRI3 should stay at 1.1. I've
made the changes locally.

Cheers,
Daniel
_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://
Adam Jackson
2018-02-28 16:56:11 UTC
Permalink
Post by Daniel Stone
Hi,
The major change is that the DRI3 protocol version has been bumped from
1.1 to 1.2, as there was previously a dri3proto-1.1 release, only
carrying a 1.0 protocol version. We bump the version to avoid this,
jumping straight from protocol version 1.0 to 1.2.
Wrong protocol.
Present needed to be bumped to 1.2, and DRI3 should stay at 1.1. I've
made the changes locally.
Too late. It's fine, integers are cheap.

- ajax
_______________________________________________
xorg-***@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: htt
Keith Packard
2018-02-28 17:08:06 UTC
Permalink
Post by Daniel Stone
DRI3 version 1.2 adds support for explicit format modifiers,
including multi-planar buffers.
Thanks for the awesome writeup on synchronization. It looks good to me.

Reviewed-by: Keith Packard <***@keithp.com>
--
-keith
Loading...