dri3_screen.c revision 1b5d61b8
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
35int
36dri3_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
52int
53dri3_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
83int
84dri3_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
115int
116dri3_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
156static int
157cache_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
215int
216dri3_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