xref: /aosp_15_r20/external/mesa3d/src/gallium/winsys/sw/dri/dri_sw_winsys.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2009, VMware, Inc.
4  * All Rights Reserved.
5  * Copyright 2010 George Sapountzis <[email protected]>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #ifdef HAVE_SYS_SHM_H
30 #include <sys/ipc.h>
31 #include <sys/shm.h>
32 #ifdef __FreeBSD__
33 /* sys/ipc.h -> sys/_types.h -> machine/param.h
34  * - defines ALIGN which clashes with our ALIGN
35  */
36 #undef ALIGN
37 #endif
38 #endif
39 
40 #include "util/compiler.h"
41 #include "util/format/u_formats.h"
42 #include "util/detect_os.h"
43 
44 #if DETECT_OS_POSIX
45 # include <sys/stat.h>
46 # include <errno.h>
47 # include <sys/mman.h>
48 #endif
49 
50 #include "pipe/p_state.h"
51 #include "util/u_inlines.h"
52 #include "util/format/u_format.h"
53 #include "util/u_math.h"
54 #include "util/u_memory.h"
55 #include "util/os_file.h"
56 
57 #include "frontend/sw_winsys.h"
58 #include "dri_sw_winsys.h"
59 
60 
61 struct dri_sw_displaytarget
62 {
63    enum pipe_format format;
64    unsigned width;
65    unsigned height;
66    unsigned stride;
67 
68    unsigned map_flags;
69    int shmid;
70    void *data;
71    void *mapped;
72    const void *front_private;
73    /* dmabuf */
74    int fd;
75    int offset;
76    size_t size;
77    bool unbacked;
78 };
79 
80 struct dri_sw_winsys
81 {
82    struct sw_winsys base;
83 
84    const struct drisw_loader_funcs *lf;
85 };
86 
87 static inline struct dri_sw_displaytarget *
dri_sw_displaytarget(struct sw_displaytarget * dt)88 dri_sw_displaytarget( struct sw_displaytarget *dt )
89 {
90    return (struct dri_sw_displaytarget *)dt;
91 }
92 
93 static inline struct dri_sw_winsys *
dri_sw_winsys(struct sw_winsys * ws)94 dri_sw_winsys( struct sw_winsys *ws )
95 {
96    return (struct dri_sw_winsys *)ws;
97 }
98 
99 
100 static bool
dri_sw_is_displaytarget_format_supported(struct sw_winsys * ws,unsigned tex_usage,enum pipe_format format)101 dri_sw_is_displaytarget_format_supported( struct sw_winsys *ws,
102                                           unsigned tex_usage,
103                                           enum pipe_format format )
104 {
105    /* TODO: check visuals or other sensible thing here */
106    return true;
107 }
108 
109 #ifdef HAVE_SYS_SHM_H
110 static char *
alloc_shm(struct dri_sw_displaytarget * dri_sw_dt,unsigned size)111 alloc_shm(struct dri_sw_displaytarget *dri_sw_dt, unsigned size)
112 {
113    char *addr;
114 
115    /* 0600 = user read+write */
116    dri_sw_dt->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
117    if (dri_sw_dt->shmid < 0)
118       return NULL;
119 
120    addr = (char *) shmat(dri_sw_dt->shmid, NULL, 0);
121    /* mark the segment immediately for deletion to avoid leaks */
122    shmctl(dri_sw_dt->shmid, IPC_RMID, NULL);
123 
124    if (addr == (char *) -1)
125       return NULL;
126 
127    return addr;
128 }
129 #endif
130 
131 static struct sw_displaytarget *
dri_sw_displaytarget_create(struct sw_winsys * winsys,unsigned tex_usage,enum pipe_format format,unsigned width,unsigned height,unsigned alignment,const void * front_private,unsigned * stride)132 dri_sw_displaytarget_create(struct sw_winsys *winsys,
133                             unsigned tex_usage,
134                             enum pipe_format format,
135                             unsigned width, unsigned height,
136                             unsigned alignment,
137                             const void *front_private,
138                             unsigned *stride)
139 {
140    UNUSED struct dri_sw_winsys *ws = dri_sw_winsys(winsys);
141    struct dri_sw_displaytarget *dri_sw_dt;
142    unsigned nblocksy, size, format_stride;
143 
144    dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget);
145    if(!dri_sw_dt)
146       goto no_dt;
147 
148    dri_sw_dt->format = format;
149    dri_sw_dt->width = width;
150    dri_sw_dt->height = height;
151    dri_sw_dt->front_private = front_private;
152 
153    format_stride = util_format_get_stride(format, width);
154    dri_sw_dt->stride = align(format_stride, alignment);
155 
156    nblocksy = util_format_get_nblocksy(format, height);
157    size = dri_sw_dt->stride * nblocksy;
158    dri_sw_dt->size = size;
159 
160    dri_sw_dt->shmid = -1;
161    dri_sw_dt->fd = -1;
162 
163 #ifdef HAVE_SYS_SHM_H
164    if (ws->lf->put_image_shm)
165       dri_sw_dt->data = alloc_shm(dri_sw_dt, size);
166 #endif
167 
168    if(!dri_sw_dt->data)
169       dri_sw_dt->data = align_malloc(size, alignment);
170 
171    if(!dri_sw_dt->data)
172       goto no_data;
173 
174    *stride = dri_sw_dt->stride;
175    return (struct sw_displaytarget *)dri_sw_dt;
176 
177 no_data:
178    FREE(dri_sw_dt);
179 no_dt:
180    return NULL;
181 }
182 
183 static struct sw_displaytarget *
dri_sw_displaytarget_create_mapped(struct sw_winsys * winsys,unsigned tex_usage,enum pipe_format format,unsigned width,unsigned height,unsigned stride,void * data)184 dri_sw_displaytarget_create_mapped(struct sw_winsys *winsys,
185                                    unsigned tex_usage,
186                                    enum pipe_format format,
187                                    unsigned width, unsigned height,
188                                    unsigned stride,
189                                    void *data)
190 {
191    UNUSED struct dri_sw_winsys *ws = dri_sw_winsys(winsys);
192    struct dri_sw_displaytarget *dri_sw_dt;
193    unsigned nblocksy, size;
194 
195    dri_sw_dt = CALLOC_STRUCT(dri_sw_displaytarget);
196    if(!dri_sw_dt)
197       return NULL;
198 
199    dri_sw_dt->format = format;
200    dri_sw_dt->width = width;
201    dri_sw_dt->height = height;
202 
203    dri_sw_dt->stride = stride;
204 
205    nblocksy = util_format_get_nblocksy(format, height);
206    size = dri_sw_dt->stride * nblocksy;
207    dri_sw_dt->size = size;
208 
209    dri_sw_dt->shmid = -1;
210    dri_sw_dt->fd = -1;
211    dri_sw_dt->unbacked = true;
212 
213    dri_sw_dt->data = data;
214    dri_sw_dt->mapped = data;
215 
216    return (struct sw_displaytarget *)dri_sw_dt;
217 }
218 
219 static void
dri_sw_displaytarget_destroy(struct sw_winsys * ws,struct sw_displaytarget * dt)220 dri_sw_displaytarget_destroy(struct sw_winsys *ws,
221                              struct sw_displaytarget *dt)
222 {
223    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
224 
225    if (dri_sw_dt->unbacked) {}
226    else if (dri_sw_dt->fd >= 0) {
227       if (dri_sw_dt->mapped)
228          ws->displaytarget_unmap(ws, dt);
229       close(dri_sw_dt->fd);
230    } else if (dri_sw_dt->shmid >= 0) {
231 #ifdef HAVE_SYS_SHM_H
232       shmdt(dri_sw_dt->data);
233       shmctl(dri_sw_dt->shmid, IPC_RMID, NULL);
234 #endif
235    } else {
236       align_free(dri_sw_dt->data);
237    }
238 
239    FREE(dri_sw_dt);
240 }
241 
242 static void *
dri_sw_displaytarget_map(struct sw_winsys * ws,struct sw_displaytarget * dt,unsigned flags)243 dri_sw_displaytarget_map(struct sw_winsys *ws,
244                          struct sw_displaytarget *dt,
245                          unsigned flags)
246 {
247    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
248    dri_sw_dt->map_flags = flags;
249    if (dri_sw_dt->unbacked)
250       return dri_sw_dt->mapped;
251 #if DETECT_OS_POSIX
252    if (dri_sw_dt->fd > -1) {
253       bool success = false;
254       if (!success) {
255          /* if this fails, it's a dmabuf that wasn't exported by us,
256           * so it doesn't have the header that we're looking for
257           */
258          off_t size = lseek(dri_sw_dt->fd, 0, SEEK_END);
259          lseek(dri_sw_dt->fd, 0, SEEK_SET);
260          if (size < 1) {
261             fprintf(stderr, "dmabuf import failed: fd has no data\n");
262             return NULL;
263          }
264          unsigned prot = 0;
265          if (flags & PIPE_MAP_READ)
266             prot |= PROT_READ;
267          if (flags & PIPE_MAP_WRITE)
268             prot |= PROT_WRITE;
269          dri_sw_dt->size = size;
270          dri_sw_dt->data = mmap(NULL, dri_sw_dt->size, prot, MAP_SHARED, dri_sw_dt->fd, 0);
271          if (dri_sw_dt->data == MAP_FAILED) {
272             dri_sw_dt->data = NULL;
273             fprintf(stderr, "dmabuf import failed to mmap: %s\n", strerror(errno));
274          } else
275             dri_sw_dt->mapped = ((uint8_t*)dri_sw_dt->data) + dri_sw_dt->offset;
276       } else
277          dri_sw_dt->mapped = ((uint8_t*)dri_sw_dt->data) + dri_sw_dt->offset;
278    } else
279 #endif
280    if (dri_sw_dt->front_private && (flags & PIPE_MAP_READ)) {
281       struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
282       dri_sw_ws->lf->get_image((void *)dri_sw_dt->front_private, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride, dri_sw_dt->data);
283       dri_sw_dt->mapped = dri_sw_dt->data;
284    } else {
285       dri_sw_dt->mapped = dri_sw_dt->data;
286    }
287    return dri_sw_dt->mapped;
288 }
289 
290 static void
dri_sw_displaytarget_unmap(struct sw_winsys * ws,struct sw_displaytarget * dt)291 dri_sw_displaytarget_unmap(struct sw_winsys *ws,
292                            struct sw_displaytarget *dt)
293 {
294    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
295 
296    if (dri_sw_dt->unbacked) {
297       dri_sw_dt->map_flags = 0;
298       return;
299    }
300 #if DETECT_OS_POSIX
301    if (dri_sw_dt->fd > -1) {
302       munmap(dri_sw_dt->data, dri_sw_dt->size);
303       dri_sw_dt->data = NULL;
304    } else
305 #endif
306    if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_MAP_WRITE)) {
307       struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
308       dri_sw_ws->lf->put_image2((void *)dri_sw_dt->front_private, dri_sw_dt->data, 0, 0, dri_sw_dt->width, dri_sw_dt->height, dri_sw_dt->stride);
309    }
310    dri_sw_dt->map_flags = 0;
311    dri_sw_dt->mapped = NULL;
312 }
313 
314 static struct sw_displaytarget *
dri_sw_displaytarget_from_handle(struct sw_winsys * winsys,const struct pipe_resource * templ,struct winsys_handle * whandle,unsigned * stride)315 dri_sw_displaytarget_from_handle(struct sw_winsys *winsys,
316                                  const struct pipe_resource *templ,
317                                  struct winsys_handle *whandle,
318                                  unsigned *stride)
319 {
320 #if DETECT_OS_POSIX
321    int fd = os_dupfd_cloexec(whandle->handle);
322    struct sw_displaytarget *sw = dri_sw_displaytarget_create(winsys, templ->usage, templ->format, templ->width0, templ->height0, 64, NULL, stride);
323    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(sw);
324    dri_sw_dt->fd = fd;
325    dri_sw_dt->offset = whandle->offset;
326    return sw;
327 #else
328    assert(0);
329    return NULL;
330 #endif
331 }
332 
333 static bool
dri_sw_displaytarget_get_handle(struct sw_winsys * winsys,struct sw_displaytarget * dt,struct winsys_handle * whandle)334 dri_sw_displaytarget_get_handle(struct sw_winsys *winsys,
335                                 struct sw_displaytarget *dt,
336                                 struct winsys_handle *whandle)
337 {
338    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
339 
340    if (whandle->type == WINSYS_HANDLE_TYPE_SHMID) {
341       if (dri_sw_dt->shmid < 0)
342          return false;
343       whandle->handle = dri_sw_dt->shmid;
344       return true;
345    }
346 
347    return false;
348 }
349 
350 static void
dri_sw_displaytarget_display(struct sw_winsys * ws,struct sw_displaytarget * dt,void * context_private,unsigned nboxes,struct pipe_box * box)351 dri_sw_displaytarget_display(struct sw_winsys *ws,
352                              struct sw_displaytarget *dt,
353                              void *context_private,
354                              unsigned nboxes,
355                              struct pipe_box *box)
356 {
357    struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
358    struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
359    struct dri_drawable *dri_drawable = (struct dri_drawable *)context_private;
360    unsigned width, height;
361    unsigned blsize = util_format_get_blocksize(dri_sw_dt->format);
362    bool is_shm = dri_sw_dt->shmid != -1;
363    /* Set the width to 'stride / cpp'.
364     *
365     * PutImage correctly clips to the width of the dst drawable.
366     */
367    width = dri_sw_dt->stride / blsize;
368    height = dri_sw_dt->height;
369    if (is_shm)
370       dri_sw_ws->lf->put_image_shm(dri_drawable, dri_sw_dt->shmid, dri_sw_dt->data, 0, 0,
371             0, 0, width, height, dri_sw_dt->stride);
372    else
373       dri_sw_ws->lf->put_image(dri_drawable, dri_sw_dt->data, width, height);
374    return;
375 }
376 
377 static void
dri_destroy_sw_winsys(struct sw_winsys * winsys)378 dri_destroy_sw_winsys(struct sw_winsys *winsys)
379 {
380    FREE(winsys);
381 }
382 
383 struct sw_winsys *
dri_create_sw_winsys(const struct drisw_loader_funcs * lf)384 dri_create_sw_winsys(const struct drisw_loader_funcs *lf)
385 {
386    struct dri_sw_winsys *ws;
387 
388    ws = CALLOC_STRUCT(dri_sw_winsys);
389    if (!ws)
390       return NULL;
391 
392    ws->lf = lf;
393    ws->base.destroy = dri_destroy_sw_winsys;
394 
395    ws->base.is_displaytarget_format_supported = dri_sw_is_displaytarget_format_supported;
396 
397    /* screen texture functions */
398    ws->base.displaytarget_create = dri_sw_displaytarget_create;
399    ws->base.displaytarget_create_mapped = dri_sw_displaytarget_create_mapped;
400    ws->base.displaytarget_destroy = dri_sw_displaytarget_destroy;
401    ws->base.displaytarget_from_handle = dri_sw_displaytarget_from_handle;
402    ws->base.displaytarget_get_handle = dri_sw_displaytarget_get_handle;
403 
404    /* texture functions */
405    ws->base.displaytarget_map = dri_sw_displaytarget_map;
406    ws->base.displaytarget_unmap = dri_sw_displaytarget_unmap;
407 
408    ws->base.displaytarget_display = dri_sw_displaytarget_display;
409 
410    return &ws->base;
411 }
412 
413 /* vim: set sw=3 ts=8 sts=3 expandtab: */
414