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 #include "dri3_priv.h"
24 #include <syncsdk.h>
25 #include <misync.h>
26 #include <misyncshm.h>
27 #include <randrstr.h>
28 #include <drm_fourcc.h>
29 #include <unistd.h>
30
31 int
dri3_open(ClientPtr client,ScreenPtr screen,RRProviderPtr provider,int * fd)32 dri3_open(ClientPtr client, ScreenPtr screen, RRProviderPtr provider, int *fd)
33 {
34 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
35 const dri3_screen_info_rec *info = ds->info;
36
37 if (info == NULL)
38 return BadMatch;
39
40 if (info->version >= 1 && info->open_client != NULL)
41 return (*info->open_client) (client, screen, provider, fd);
42 if (info->open != NULL)
43 return (*info->open) (screen, provider, fd);
44
45 return BadMatch;
46 }
47
48 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)49 dri3_pixmap_from_fds(PixmapPtr *ppixmap, ScreenPtr screen,
50 CARD8 num_fds, const int *fds,
51 CARD16 width, CARD16 height,
52 const CARD32 *strides, const CARD32 *offsets,
53 CARD8 depth, CARD8 bpp, CARD64 modifier)
54 {
55 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
56 const dri3_screen_info_rec *info = ds->info;
57 PixmapPtr pixmap;
58
59 if (!info)
60 return BadImplementation;
61
62 if (info->version >= 2 && info->pixmap_from_fds != NULL) {
63 pixmap = (*info->pixmap_from_fds) (screen, num_fds, fds, width, height,
64 strides, offsets, depth, bpp, modifier);
65 } else if (info->pixmap_from_fd != NULL && num_fds == 1) {
66 pixmap = (*info->pixmap_from_fd) (screen, fds[0], width, height,
67 strides[0], depth, bpp);
68 } else {
69 return BadImplementation;
70 }
71
72 if (!pixmap)
73 return BadAlloc;
74
75 *ppixmap = pixmap;
76 return Success;
77 }
78
79 int
dri3_fds_from_pixmap(PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)80 dri3_fds_from_pixmap(PixmapPtr pixmap, int *fds,
81 uint32_t *strides, uint32_t *offsets,
82 uint64_t *modifier)
83 {
84 ScreenPtr screen = pixmap->drawable.pScreen;
85 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
86 const dri3_screen_info_rec *info = ds->info;
87
88 if (!info)
89 return 0;
90
91 if (info->version >= 2 && info->fds_from_pixmap != NULL) {
92 return (*info->fds_from_pixmap)(screen, pixmap, fds, strides, offsets,
93 modifier);
94 } else if (info->fd_from_pixmap != NULL) {
95 CARD16 stride;
96 CARD32 size;
97
98 fds[0] = (*info->fd_from_pixmap)(screen, pixmap, &stride, &size);
99 if (fds[0] < 0)
100 return 0;
101
102 strides[0] = stride;
103 offsets[0] = 0;
104 *modifier = DRM_FORMAT_MOD_INVALID;
105 return 1;
106 } else {
107 return 0;
108 }
109 }
110
111 int
dri3_fd_from_pixmap(PixmapPtr pixmap,CARD16 * stride,CARD32 * size)112 dri3_fd_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
113 {
114 ScreenPtr screen = pixmap->drawable.pScreen;
115 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
116 const dri3_screen_info_rec *info = ds->info;
117 uint32_t strides[4];
118 uint32_t offsets[4];
119 uint64_t modifier;
120 int fds[4];
121 int num_fds;
122
123 if (!info)
124 return -1;
125
126 /* Preferentially use the old interface, allowing the implementation to
127 * ensure the buffer is in a single-plane format which doesn't need
128 * modifiers. */
129 if (info->fd_from_pixmap != NULL)
130 return (*info->fd_from_pixmap)(screen, pixmap, stride, size);
131
132 if (info->version < 2 || info->fds_from_pixmap == NULL)
133 return -1;
134
135 /* If using the new interface, make sure that it's a single plane starting
136 * at 0 within the BO. We don't check the modifier, as the client may
137 * have an auxiliary mechanism for determining the modifier itself. */
138 num_fds = info->fds_from_pixmap(screen, pixmap, fds, strides, offsets,
139 &modifier);
140 if (num_fds != 1 || offsets[0] != 0) {
141 int i;
142 for (i = 0; i < num_fds; i++)
143 close(fds[i]);
144 return -1;
145 }
146
147 *stride = strides[0];
148 *size = size[0];
149 return fds[0];
150 }
151
152 static int
cache_formats_and_modifiers(ScreenPtr screen)153 cache_formats_and_modifiers(ScreenPtr screen)
154 {
155 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
156 const dri3_screen_info_rec *info = ds->info;
157 CARD32 num_formats;
158 CARD32 *formats;
159 uint32_t num_modifiers;
160 uint64_t *modifiers;
161 int i;
162
163 if (ds->formats_cached)
164 return Success;
165
166 if (!info)
167 return BadImplementation;
168
169 if (info->version < 2 || !info->get_formats || !info->get_modifiers) {
170 ds->formats = NULL;
171 ds->num_formats = 0;
172 ds->formats_cached = TRUE;
173 return Success;
174 }
175
176 if (!info->get_formats(screen, &num_formats, &formats))
177 return BadAlloc;
178
179 if (!num_formats) {
180 ds->num_formats = 0;
181 ds->formats_cached = TRUE;
182 return Success;
183 }
184
185 ds->formats = calloc(num_formats, sizeof(dri3_dmabuf_format_rec));
186 if (!ds->formats)
187 return BadAlloc;
188
189 for (i = 0; i < num_formats; i++) {
190 dri3_dmabuf_format_ptr iter = &ds->formats[i];
191
192 if (!info->get_modifiers(screen, formats[i],
193 &num_modifiers,
194 &modifiers))
195 continue;
196
197 if (!num_modifiers)
198 continue;
199
200 iter->format = formats[i];
201 iter->num_modifiers = num_modifiers;
202 iter->modifiers = modifiers;
203 }
204
205 ds->num_formats = i;
206 ds->formats_cached = TRUE;
207
208 return Success;
209 }
210
211 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)212 dri3_get_supported_modifiers(ScreenPtr screen, DrawablePtr drawable,
213 CARD8 depth, CARD8 bpp,
214 CARD32 *num_intersect_modifiers,
215 CARD64 **intersect_modifiers,
216 CARD32 *num_screen_modifiers,
217 CARD64 **screen_modifiers)
218 {
219 dri3_screen_priv_ptr ds = dri3_screen_priv(screen);
220 const dri3_screen_info_rec *info = ds->info;
221 int i, j;
222 int ret;
223 uint32_t num_drawable_mods;
224 uint64_t *drawable_mods;
225 CARD64 *intersect_mods = NULL;
226 CARD64 *screen_mods = NULL;
227 CARD32 format;
228 dri3_dmabuf_format_ptr screen_format = NULL;
229
230 ret = cache_formats_and_modifiers(screen);
231 if (ret != Success)
232 return ret;
233
234 format = drm_format_for_depth(depth, bpp);
235 if (format == 0)
236 return BadValue;
237
238 /* Find screen-global modifiers from cache
239 */
240 for (i = 0; i < ds->num_formats; i++) {
241 if (ds->formats[i].format == format) {
242 screen_format = &ds->formats[i];
243 break;
244 }
245 }
246 if (screen_format == NULL)
247 return BadMatch;
248
249 if (screen_format->num_modifiers == 0) {
250 *num_screen_modifiers = 0;
251 *num_intersect_modifiers = 0;
252 return Success;
253 }
254
255 if (!info->get_drawable_modifiers ||
256 !info->get_drawable_modifiers(drawable, format,
257 &num_drawable_mods,
258 &drawable_mods)) {
259 num_drawable_mods = 0;
260 drawable_mods = NULL;
261 }
262
263 /* We're allocating slightly more memory than necessary but it reduces
264 * the complexity of finding the intersection set.
265 */
266 screen_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
267 if (!screen_mods)
268 return BadAlloc;
269 if (num_drawable_mods > 0) {
270 intersect_mods = malloc(screen_format->num_modifiers * sizeof(CARD64));
271 if (!intersect_mods) {
272 free(screen_mods);
273 return BadAlloc;
274 }
275 }
276
277 *num_screen_modifiers = 0;
278 *num_intersect_modifiers = 0;
279 for (i = 0; i < screen_format->num_modifiers; i++) {
280 CARD64 modifier = screen_format->modifiers[i];
281 Bool intersect = FALSE;
282
283 for (j = 0; j < num_drawable_mods; j++) {
284 if (drawable_mods[j] == modifier) {
285 intersect = TRUE;
286 break;
287 }
288 }
289
290 if (intersect) {
291 intersect_mods[*num_intersect_modifiers] = modifier;
292 *num_intersect_modifiers += 1;
293 } else {
294 screen_mods[*num_screen_modifiers] = modifier;
295 *num_screen_modifiers += 1;
296 }
297 }
298
299 assert(*num_intersect_modifiers + *num_screen_modifiers == screen_format->num_modifiers);
300
301 *intersect_modifiers = intersect_mods;
302 *screen_modifiers = screen_mods;
303 free(drawable_mods);
304
305 return Success;
306 }
307