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