1 /*
2 * Copyright (c) 2020, Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_DIX_CONFIG_H
16 #include "dix-config.h"
17 #endif
18
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <drm_fourcc.h>
22
23 #include "xf86.h"
24
25 #include "dri3.h"
26 #include "driver.h"
27
28 /* Based on glamor/glamor_egl.c#glamor_dri3_open_client */
29 static int
ms_exa_dri3_open_client(ClientPtr client,ScreenPtr screen,RRProviderPtr provider,int * fdp)30 ms_exa_dri3_open_client(ClientPtr client,
31 ScreenPtr screen,
32 RRProviderPtr provider,
33 int *fdp)
34 {
35 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
36 modesettingPtr ms = modesettingPTR(scrn);
37 int fd;
38 drm_magic_t magic;
39
40 fd = open(ms->drmmode.dri3_device_name, O_RDWR|O_CLOEXEC);
41 if (fd < 0)
42 return BadAlloc;
43
44 /* Before FD passing in the X protocol with DRI3 (and increased
45 * security of rendering with per-process address spaces on the
46 * GPU), the kernel had to come up with a way to have the server
47 * decide which clients got to access the GPU, which was done by
48 * each client getting a unique (magic) number from the kernel,
49 * passing it to the server, and the server then telling the
50 * kernel which clients were authenticated for using the device.
51 *
52 * Now that we have FD passing, the server can just set up the
53 * authentication on its own and hand the prepared FD off to the
54 * client.
55 */
56 if (drmGetMagic(fd, &magic) < 0) {
57 if (errno == EACCES) {
58 /* Assume that we're on a render node, and the fd is
59 * already as authenticated as it should be.
60 */
61 *fdp = fd;
62 return Success;
63 } else {
64 close(fd);
65 return BadMatch;
66 }
67 }
68
69 if (drmAuthMagic(ms->drmmode.fd, magic) < 0) {
70 close(fd);
71 return BadMatch;
72 }
73
74 *fdp = fd;
75 return Success;
76 }
77
78 static PixmapPtr
ms_exa_pixmap_from_fds(ScreenPtr screen,CARD8 num_fds,const int * fds,CARD16 width,CARD16 height,const CARD32 * strides,const CARD32 * offsets,CARD8 depth,CARD8 bpp,uint64_t modifier)79 ms_exa_pixmap_from_fds(ScreenPtr screen,
80 CARD8 num_fds, const int *fds,
81 CARD16 width, CARD16 height,
82 const CARD32 *strides, const CARD32 *offsets,
83 CARD8 depth, CARD8 bpp,
84 uint64_t modifier)
85 {
86 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
87 modesettingPtr ms = modesettingPTR(scrn);
88 PixmapPtr pixmap;
89 struct dumb_bo *bo;
90
91 if (num_fds != 1 || offsets[0] || modifier != DRM_FORMAT_MOD_INVALID)
92 return NULL;
93
94 pixmap = drmmode_create_pixmap_header(screen, width, height,
95 depth, bpp, strides[0], NULL);
96 if (!pixmap)
97 return NULL;
98
99 bo = dumb_get_bo_from_fd(ms->drmmode.fd, fds[0],
100 strides[0], strides[0] * height);
101 if (!bo)
102 goto err_free_pixmap;
103
104 if (!ms_exa_set_pixmap_bo(scrn, pixmap, bo, TRUE))
105 goto err_free_bo;
106
107 return pixmap;
108 err_free_bo:
109 dumb_bo_destroy(ms->drmmode.fd, bo);
110 err_free_pixmap:
111 screen->DestroyPixmap(pixmap);
112 return NULL;
113 }
114
115 static int
ms_exa_egl_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)116 ms_exa_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap,
117 CARD16 *stride, CARD32 *size)
118 {
119 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
120 modesettingPtr ms = modesettingPTR(scrn);
121 struct dumb_bo *bo;
122 int fd;
123
124 bo = ms_exa_bo_from_pixmap(screen, pixmap);
125 if (!bo)
126 return -1;
127
128 fd = dumb_bo_get_fd(ms->drmmode.fd, bo, 0);
129 *stride = bo->pitch;
130 *size = bo->size;
131
132 return fd;
133 }
134
135 static int
ms_exa_egl_fds_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)136 ms_exa_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
137 uint32_t *strides, uint32_t *offsets,
138 uint64_t *modifier)
139 {
140 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
141 modesettingPtr ms = modesettingPTR(scrn);
142 struct dumb_bo *bo;
143
144 bo = ms_exa_bo_from_pixmap(screen, pixmap);
145 if (!bo)
146 return 0;
147
148 fds[0] = dumb_bo_get_fd(ms->drmmode.fd, bo, 0);
149 strides[0] = bo->pitch;
150 offsets[0] = 0;
151 *modifier = DRM_FORMAT_MOD_INVALID;
152
153 return 1;
154 }
155
156 static Bool
ms_exa_get_formats(ScreenPtr screen,CARD32 * num_formats,CARD32 ** formats)157 ms_exa_get_formats(ScreenPtr screen,
158 CARD32 *num_formats, CARD32 **formats)
159 {
160 /* TODO: Return formats */
161 *num_formats = 0;
162 return TRUE;
163 }
164
165 static Bool
ms_exa_get_modifiers(ScreenPtr screen,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)166 ms_exa_get_modifiers(ScreenPtr screen, uint32_t format,
167 uint32_t *num_modifiers, uint64_t **modifiers)
168 {
169 *num_modifiers = 0;
170 return TRUE;
171 }
172
173 static Bool
ms_exa_get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)174 ms_exa_get_drawable_modifiers(DrawablePtr draw, uint32_t format,
175 uint32_t *num_modifiers, uint64_t **modifiers)
176 {
177 *num_modifiers = 0;
178 return TRUE;
179 }
180
181 static const dri3_screen_info_rec ms_exa_dri3_info = {
182 .version = 2,
183 .open_client = ms_exa_dri3_open_client,
184 .pixmap_from_fds = ms_exa_pixmap_from_fds,
185 .fd_from_pixmap = ms_exa_egl_fd_from_pixmap,
186 .fds_from_pixmap = ms_exa_egl_fds_from_pixmap,
187 .get_formats = ms_exa_get_formats,
188 .get_modifiers = ms_exa_get_modifiers,
189 .get_drawable_modifiers = ms_exa_get_drawable_modifiers,
190 };
191
192 Bool
ms_exa_dri3_init(ScreenPtr screen)193 ms_exa_dri3_init(ScreenPtr screen)
194 {
195 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
196 modesettingPtr ms = modesettingPTR(scrn);
197 ms->drmmode.dri3_device_name = drmGetDeviceNameFromFd2(ms->drmmode.fd);
198
199 return dri3_screen_init(screen, &ms_exa_dri3_info);
200 }
201