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