xref: /aosp_15_r20/external/mesa3d/src/gallium/winsys/svga/drm/vmw_screen_dri.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2009-2024 Broadcom. All Rights Reserved.
3  * The term “Broadcom” refers to Broadcom Inc.
4  * and/or its subsidiaries.
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #include "util/compiler.h"
9 #include "util/u_inlines.h"
10 #include "util/u_memory.h"
11 #include "util/format/u_format.h"
12 
13 #include "vmw_context.h"
14 #include "vmw_screen.h"
15 #include "vmw_surface.h"
16 #include "vmw_buffer.h"
17 #include "svga_drm_public.h"
18 #include "svga3d_surfacedefs.h"
19 
20 #include "frontend/drm_driver.h"
21 
22 #include "vmwgfx_drm.h"
23 #include <xf86drm.h>
24 
25 #include <stdio.h>
26 #include <fcntl.h>
27 
28 struct dri1_api_version {
29    int major;
30    int minor;
31    int patch_level;
32 };
33 
34 static struct svga_winsys_surface *
35 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
36 			    struct winsys_handle *whandle,
37 			    SVGA3dSurfaceFormat *format);
38 
39 static struct svga_winsys_surface *
40 vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
41                                struct winsys_handle *whandle,
42                                SVGA3dSurfaceFormat *format);
43 static bool
44 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
45 			   struct svga_winsys_surface *surface,
46 			   unsigned stride,
47 			   struct winsys_handle *whandle);
48 
49 static struct dri1_api_version drm_required = { 2, 1, 0 };
50 static struct dri1_api_version drm_compat = { 2, 0, 0 };
51 
52 static bool
vmw_dri1_check_version(const struct dri1_api_version * cur,const struct dri1_api_version * required,const struct dri1_api_version * compat,const char component[])53 vmw_dri1_check_version(const struct dri1_api_version *cur,
54 		       const struct dri1_api_version *required,
55 		       const struct dri1_api_version *compat,
56 		       const char component[])
57 {
58    if (cur->major > required->major && cur->major <= compat->major)
59       return true;
60    if (cur->major == required->major && cur->minor >= required->minor)
61       return true;
62 
63    vmw_error("%s version failure.\n", component);
64    vmw_error("%s version is %d.%d.%d and this driver can only work\n"
65              "with versions %d.%d.x through %d.x.x.\n",
66              component,
67              cur->major, cur->minor, cur->patch_level,
68              required->major, required->minor, compat->major);
69    return false;
70 }
71 
72 /* This is actually the entrypoint to the entire driver,
73  * called by the target bootstrap code.
74  */
75 struct svga_winsys_screen *
svga_drm_winsys_screen_create(int fd)76 svga_drm_winsys_screen_create(int fd)
77 {
78    struct vmw_winsys_screen *vws;
79    struct dri1_api_version drm_ver;
80    drmVersionPtr ver;
81 
82    ver = drmGetVersion(fd);
83    if (ver == NULL)
84       return NULL;
85 
86    drm_ver.major = ver->version_major;
87    drm_ver.minor = ver->version_minor;
88    drm_ver.patch_level = 0; /* ??? */
89 
90    drmFreeVersion(ver);
91    if (!vmw_dri1_check_version(&drm_ver, &drm_required,
92 			       &drm_compat, "vmwgfx drm driver"))
93       return NULL;
94 
95    vws = vmw_winsys_create(fd);
96    if (!vws)
97       goto out_no_vws;
98 
99    /* XXX do this properly */
100    vws->base.surface_from_handle = vws->base.have_gb_objects ?
101       vmw_drm_gb_surface_from_handle : vmw_drm_surface_from_handle;
102    vws->base.surface_get_handle = vmw_drm_surface_get_handle;
103 
104    return &vws->base;
105 
106 out_no_vws:
107    return NULL;
108 }
109 
110 /**
111  * vmw_drm_gb_surface_from_handle - Create a shared surface
112  *
113  * @sws: Screen to register the surface with.
114  * @whandle: struct winsys_handle identifying the kernel surface object
115  * @format: On successful return points to a value describing the
116  * surface format.
117  *
118  * Returns a refcounted pointer to a struct svga_winsys_surface
119  * embedded in a struct vmw_svga_winsys_surface on success or NULL
120  * on failure.
121  */
122 static struct svga_winsys_surface *
vmw_drm_gb_surface_from_handle(struct svga_winsys_screen * sws,struct winsys_handle * whandle,SVGA3dSurfaceFormat * format)123 vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws,
124                                struct winsys_handle *whandle,
125                                SVGA3dSurfaceFormat *format)
126 {
127     struct vmw_svga_winsys_surface *vsrf;
128     struct svga_winsys_surface *ssrf;
129     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
130     SVGA3dSurfaceAllFlags flags;
131     uint32_t mip_levels;
132     struct vmw_buffer_desc desc;
133     struct pb_manager *provider = vws->pools.dma_base;
134     struct pb_buffer *pb_buf;
135     uint32_t handle;
136     int ret;
137 
138     if (whandle->offset != 0) {
139        fprintf(stderr, "Attempt to import unsupported winsys offset %u\n",
140                whandle->offset);
141        return NULL;
142     }
143 
144     ret = vmw_ioctl_gb_surface_ref(vws, whandle, &flags, format,
145                                    &mip_levels, &handle, &desc.region);
146 
147     if (ret) {
148 	fprintf(stderr, "Failed referencing shared surface. SID %d.\n"
149 		"Error %d (%s).\n",
150 		whandle->handle, ret, strerror(-ret));
151 	return NULL;
152     }
153 
154     if (mip_levels != 1) {
155        fprintf(stderr, "Incorrect number of mipmap levels on shared surface."
156                " SID %d, levels %d\n",
157                whandle->handle, mip_levels);
158        goto out_mip;
159     }
160 
161     vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
162     if (!vsrf)
163 	goto out_mip;
164 
165     pipe_reference_init(&vsrf->refcnt, 1);
166     p_atomic_set(&vsrf->validated, 0);
167     vsrf->screen = vws;
168     vsrf->sid = handle;
169     vsrf->size = vmw_region_size(desc.region);
170 
171     /*
172      * Synchronize backing buffers of shared surfaces using the
173      * kernel, since we don't pass fence objects around between
174      * processes.
175      */
176     desc.pb_desc.alignment = 4096;
177     desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED | VMW_BUFFER_USAGE_SYNC;
178     pb_buf = provider->create_buffer(provider, vsrf->size, &desc.pb_desc);
179     vsrf->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
180     if (!vsrf->buf)
181        goto out_no_buf;
182     ssrf = svga_winsys_surface(vsrf);
183 
184     return ssrf;
185 
186 out_no_buf:
187     FREE(vsrf);
188 out_mip:
189     vmw_ioctl_region_destroy(desc.region);
190     vmw_ioctl_surface_destroy(vws, whandle->handle);
191     return NULL;
192 }
193 
194 static struct svga_winsys_surface *
vmw_drm_surface_from_handle(struct svga_winsys_screen * sws,struct winsys_handle * whandle,SVGA3dSurfaceFormat * format)195 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws,
196                             struct winsys_handle *whandle,
197 			    SVGA3dSurfaceFormat *format)
198 {
199     struct vmw_svga_winsys_surface *vsrf;
200     struct svga_winsys_surface *ssrf;
201     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
202     union drm_vmw_surface_reference_arg arg;
203     struct drm_vmw_surface_arg *req = &arg.req;
204     struct drm_vmw_surface_create_req *rep = &arg.rep;
205     uint32_t handle = 0;
206     struct drm_vmw_size size;
207     SVGA3dSize base_size;
208     int ret;
209     int i;
210 
211     if (whandle->offset != 0) {
212        fprintf(stderr, "Attempt to import unsupported winsys offset %u\n",
213                whandle->offset);
214        return NULL;
215     }
216 
217     switch (whandle->type) {
218     case WINSYS_HANDLE_TYPE_SHARED:
219     case WINSYS_HANDLE_TYPE_KMS:
220        handle = whandle->handle;
221        break;
222     case WINSYS_HANDLE_TYPE_FD:
223        ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle,
224                                 &handle);
225        if (ret) {
226 	  vmw_error("Failed to get handle from prime fd %d.\n",
227 		    (int) whandle->handle);
228 	  return NULL;
229        }
230        break;
231     default:
232        vmw_error("Attempt to import unsupported handle type %d.\n",
233                  whandle->type);
234        return NULL;
235     }
236 
237     memset(&arg, 0, sizeof(arg));
238     req->sid = handle;
239     rep->size_addr = (unsigned long)&size;
240 
241     ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE,
242 			      &arg, sizeof(arg));
243 
244     /*
245      * Need to close the handle we got from prime.
246      */
247     if (whandle->type == WINSYS_HANDLE_TYPE_FD)
248        vmw_ioctl_surface_destroy(vws, handle);
249 
250     if (ret) {
251        /*
252         * Any attempt to share something other than a surface, like a dumb
253         * kms buffer, should fail here.
254         */
255        vmw_error("Failed referencing shared surface. SID %d.\n"
256                  "Error %d (%s).\n",
257                  handle, ret, strerror(-ret));
258        return NULL;
259     }
260 
261     if (rep->mip_levels[0] != 1) {
262         vmw_error("Incorrect number of mipmap levels on shared surface."
263                   " SID %d, levels %d\n",
264                   handle, rep->mip_levels[0]);
265 	goto out_mip;
266     }
267 
268     for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
269 	if (rep->mip_levels[i] != 0) {
270             vmw_error("Incorrect number of faces levels on shared surface."
271                       " SID %d, face %d present.\n",
272                       handle, i);
273 	    goto out_mip;
274 	}
275    }
276 
277     vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface);
278     if (!vsrf)
279 	goto out_mip;
280 
281     pipe_reference_init(&vsrf->refcnt, 1);
282     p_atomic_set(&vsrf->validated, 0);
283     vsrf->screen = vws;
284     vsrf->sid = handle;
285     ssrf = svga_winsys_surface(vsrf);
286     *format = rep->format;
287 
288     /* Estimate usage, for early flushing. */
289 
290     base_size.width = size.width;
291     base_size.height = size.height;
292     base_size.depth = size.depth;
293     vsrf->size = svga3dsurface_get_serialized_size(rep->format, base_size,
294                                                    rep->mip_levels[0],
295                                                    false);
296 
297     return ssrf;
298 
299 out_mip:
300     vmw_ioctl_surface_destroy(vws, handle);
301 
302     return NULL;
303 }
304 
305 static bool
vmw_drm_surface_get_handle(struct svga_winsys_screen * sws,struct svga_winsys_surface * surface,unsigned stride,struct winsys_handle * whandle)306 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws,
307 			   struct svga_winsys_surface *surface,
308 			   unsigned stride,
309 			   struct winsys_handle *whandle)
310 {
311     struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
312     struct vmw_svga_winsys_surface *vsrf;
313     int ret;
314 
315     if (!surface)
316 	return false;
317 
318     vsrf = vmw_svga_winsys_surface(surface);
319     whandle->handle = vsrf->sid;
320     whandle->stride = stride;
321     whandle->offset = 0;
322 
323     switch (whandle->type) {
324     case WINSYS_HANDLE_TYPE_SHARED:
325     case WINSYS_HANDLE_TYPE_KMS:
326        whandle->handle = vsrf->sid;
327        break;
328     case WINSYS_HANDLE_TYPE_FD:
329        ret = drmPrimeHandleToFD(vws->ioctl.drm_fd, vsrf->sid, DRM_CLOEXEC,
330 				(int *)&whandle->handle);
331        if (ret) {
332 	  vmw_error("Failed to get file descriptor from prime.\n");
333 	  return false;
334        }
335        break;
336     default:
337        vmw_error("Attempt to export unsupported handle type %d.\n",
338 		 whandle->type);
339        return false;
340     }
341 
342     return true;
343 }
344