1 /*
2  * Copyright © 2013 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #endif
26 
27 #include "dri3_priv.h"
28 #include <syncsdk.h>
29 #include <misync.h>
30 #include <misyncshm.h>
31 #include <randrstr.h>
32 #include <drm_fourcc.h>
33 #include <unistd.h>
34 
35 int
dri3_open(ClientPtr client,ScreenPtr screen,RRProviderPtr provider,int * fd)36 dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
37 {
38     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
39     const dri3_screen_info_rec *info = ds->info;
40 
41     if (info == NULL)
42         return BadMatch;
43 
44     if (info->version >= 1 && info->open_client != NULL)
45         return (*info->open_client) (client, screen, provider, fd);
46     if (info->open != NULL)
47         return (*info->open) (screen, provider, fd);
48 
49     return BadMatch;
50 }
51 
52 int
dri3_pixmap_from_fds(PixmapPtr * ppixmap,ScreenPtr screen,CARD8 num_fds,const int * fds,CARD16 width,CARD16 height,const CARD32 * strides,const CARD32 * offsets,CARD8 depth,CARD8 bpp,CARD64 modifier)53 dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
54                      CARD8 num_fds, const int *fds,
55                      CARD16 width, CARD16 height,
56                      const CARD32 *strides, const CARD32 *offsets,
57                      CARD8 depth, CARD8 bpp, CARD64 modifier)
58 {
59     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
60     const dri3_screen_info_rec *info = ds->info;
61     PixmapPtr                   pixmap;
62 
63     if (!info)
64         return BadImplementation;
65 
66     if (info->version >= 2 && info->pixmap_from_fds != NULL) {
67         pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
68                                            strides, offsets, depth, bpp, modifier);
69     } else if (info->pixmap_from_fd != NULL && num_fds == 1) {
70         pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
71                                           strides[0], depth, bpp);
72     } else {
73         return BadImplementation;
74     }
75 
76     if (!pixmap)
77         return BadAlloc;
78 
79     *ppixmap = pixmap;
80     return Success;
81 }
82 
83 int
dri3_fds_from_pixmap(PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)84 dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
85                      uint32_t *strides, uint32_t *offsets,
86                      uint64_t *modifier)
87 {
88     ScreenPtr                   screen = pixmap->drawable.pScreen;
89     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
90     const dri3_screen_info_rec *info = ds->info;
91 
92     if (!info)
93         return 0;
94 
95     if (info->version >= 2 && info->fds_from_pixmap != NULL) {
96         return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
97                                         modifier);
98     } else if (info->fd_from_pixmap != NULL) {
99         CARD16 stride;
100         CARD32 size;
101 
102         fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
103         if (fds[0] < 0)
104             return 0;
105 
106         strides[0] = stride;
107         offsets[0] = 0;
108         *modifier = DRM_FORMAT_MOD_INVALID;
109         return 1;
110     } else {
111         return 0;
112     }
113 }
114 
115 int
dri3_fd_from_pixmap(PixmapPtr pixmap,CARD16 * stride,CARD32 * size)116 dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
117 {
118     ScreenPtr                   screen = pixmap->drawable.pScreen;
119     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
120     const dri3_screen_info_rec  *info = ds->info;
121     uint32_t                    strides[4];
122     uint32_t                    offsets[4];
123     uint64_t                    modifier;
124     int                         fds[4];
125     int                         num_fds;
126 
127     if (!info)
128         return -1;
129 
130     /* Preferentially use the old interface, allowing the implementation to
131      * ensure the buffer is in a single-plane format which doesn't need
132      * modifiers. */
133     if (info->fd_from_pixmap != NULL)
134         return (*info->fd_from_pixmap)(screen, pixmap, stride, size);
135 
136     if (info->version < 2 || info->fds_from_pixmap == NULL)
137         return -1;
138 
139     /* If using the new interface, make sure that it's a single plane starting
140      * at 0 within the BO. We don't check the modifier, as the client may
141      * have an auxiliary mechanism for determining the modifier itself. */
142     num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets,
143                                     &modifier);
144     if (num_fds != 1 || offsets[0] != 0) {
145         int i;
146         for (i = 0; i < num_fds; i++)
147             close(fds[i]);
148         return -1;
149     }
150 
151     *stride = strides[0];
152     *size = size[0];
153     return fds[0];
154 }
155 
156 static int
cache_formats_and_modifiers(ScreenPtr screen)157 cache_formats_and_modifiers(ScreenPtr screen)
158 {
159     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
160     const dri3_screen_info_rec *info = ds->info;
161     CARD32                      num_formats;
162     CARD32                     *formats;
163     uint32_t                    num_modifiers;
164     uint64_t                   *modifiers;
165     int                         i;
166 
167     if (ds->formats_cached)
168         return Success;
169 
170     if (!info)
171         return BadImplementation;
172 
173     if (info->version < 2 || !info->get_formats || !info->get_modifiers) {
174         ds->formats = NULL;
175         ds->num_formats = 0;
176         ds->formats_cached = TRUE;
177         return Success;
178     }
179 
180     if (!info->get_formats(screen, &num_formats, &formats))
181         return BadAlloc;
182 
183     if (!num_formats) {
184         ds->num_formats = 0;
185         ds->formats_cached = TRUE;
186         return Success;
187     }
188 
189     ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec));
190     if (!ds->formats)
191         return BadAlloc;
192 
193     for (i = 0; i < num_formats; i++) {
194         dri3_dmabuf_format_ptr iter = &ds->formats[i];
195 
196         if (!info->get_modifiers(screen, formats[i],
197                                  &num_modifiers,
198                                  &modifiers))
199             continue;
200 
201         if (!num_modifiers)
202             continue;
203 
204         iter->format = formats[i];
205         iter->num_modifiers = num_modifiers;
206         iter->modifiers = modifiers;
207     }
208 
209     ds->num_formats = i;
210     ds->formats_cached = TRUE;
211 
212     return Success;
213 }
214 
215 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)216 dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
217                              CARD8 depth, CARD8 bpp,
218                              CARD32 *num_intersect_modifiers,
219                              CARD64 **intersect_modifiers,
220                              CARD32 *num_screen_modifiers,
221                              CARD64 **screen_modifiers)
222 {
223     dri3_screen_priv_ptr        ds = dri3_screen_priv(screen);
224     const dri3_screen_info_rec *info = ds->info;
225     int                         i, j;
226     int                         ret;
227     uint32_t                    num_drawable_mods;
228     uint64_t                   *drawable_mods;
229     CARD64                     *intersect_mods = NULL;
230     CARD64                     *screen_mods = NULL;
231     CARD32                      format;
232     dri3_dmabuf_format_ptr      screen_format = NULL;
233 
234     ret = cache_formats_and_modifiers(screen);
235     if (ret != Success)
236         return ret;
237 
238     format = drm_format_for_depth(depth, bpp);
239     if (format == 0)
240         return BadValue;
241 
242     /* Find screen-global modifiers from cache
243      */
244     for (i = 0; i < ds->num_formats; i++) {
245         if (ds->formats[i].format == format) {
246             screen_format = &ds->formats[i];
247             break;
248         }
249     }
250     if (screen_format == NULL)
251         return BadMatch;
252 
253     if (screen_format->num_modifiers == 0) {
254         *num_screen_modifiers = 0;
255         *num_intersect_modifiers = 0;
256         return Success;
257     }
258 
259     if (!info->get_drawable_modifiers ||
260         !info->get_drawable_modifiers(drawable, format,
261                                       &num_drawable_mods,
262                                       &drawable_mods)) {
263         num_drawable_mods = 0;
264         drawable_mods = NULL;
265     }
266 
267     /* We're allocating slightly more memory than necessary but it reduces
268      * the complexity of finding the intersection set.
269      */
270     screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
271     if (!screen_mods)
272         return BadAlloc;
273     if (num_drawable_mods > 0) {
274         intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
275         if (!intersect_mods) {
276             free(screen_mods);
277             return BadAlloc;
278         }
279     }
280 
281     *num_screen_modifiers = 0;
282     *num_intersect_modifiers = 0;
283     for (i = 0; i < screen_format->num_modifiers; i++) {
284         CARD64 modifier = screen_format->modifiers[i];
285         Bool intersect = FALSE;
286 
287         for (j = 0; j < num_drawable_mods; j++) {
288             if (drawable_mods[j] == modifier) {
289                 intersect = TRUE;
290                 break;
291             }
292         }
293 
294         if (intersect) {
295             intersect_mods[*num_intersect_modifiers] = modifier;
296             *num_intersect_modifiers += 1;
297         } else {
298             screen_mods[*num_screen_modifiers] = modifier;
299             *num_screen_modifiers += 1;
300         }
301     }
302 
303     assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
304 
305     *intersect_modifiers = intersect_mods;
306     *screen_modifiers = screen_mods;
307     free(drawable_mods);
308 
309     return Success;
310 }
311