winsys/drisw: implement dmabuf handling

this comes in two variants:
* util/memfd stuff with a header for metadata
* raw fd passing

for imports, both have to be tried since the import might be from a hw
device, but only the latter needs to be handled in winsys here

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27805>
This commit is contained in:
Mike Blumenkrantz 2022-05-04 10:54:17 -04:00 committed by Marge Bot
parent 17abe3ecbd
commit e4ae665f93

View file

@ -39,11 +39,20 @@
#include "util/compiler.h"
#include "util/format/u_formats.h"
#include "util/detect_os.h"
#if DETECT_OS_UNIX
# include <sys/stat.h>
# include <errno.h>
# include <sys/mman.h>
#endif
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/format/u_format.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "util/os_file.h"
#include "frontend/sw_winsys.h"
#include "dri_sw_winsys.h"
@ -61,6 +70,9 @@ struct dri_sw_displaytarget
void *data;
void *mapped;
const void *front_private;
/* dmabuf */
int fd;
int offset;
size_t size;
bool unbacked;
};
@ -146,6 +158,7 @@ dri_sw_displaytarget_create(struct sw_winsys *winsys,
dri_sw_dt->size = size;
dri_sw_dt->shmid = -1;
dri_sw_dt->fd = -1;
#ifdef HAVE_SYS_SHM_H
if (ws->lf->put_image_shm)
@ -194,6 +207,7 @@ dri_sw_displaytarget_create_mapped(struct sw_winsys *winsys,
dri_sw_dt->size = size;
dri_sw_dt->shmid = -1;
dri_sw_dt->fd = -1;
dri_sw_dt->unbacked = true;
dri_sw_dt->data = data;
@ -209,7 +223,11 @@ dri_sw_displaytarget_destroy(struct sw_winsys *ws,
struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
if (dri_sw_dt->unbacked) {}
else if (dri_sw_dt->shmid >= 0) {
else if (dri_sw_dt->fd >= 0) {
if (dri_sw_dt->mapped)
ws->displaytarget_unmap(ws, dt);
close(dri_sw_dt->fd);
} else if (dri_sw_dt->shmid >= 0) {
#ifdef HAVE_SYS_SHM_H
shmdt(dri_sw_dt->data);
shmctl(dri_sw_dt->shmid, IPC_RMID, NULL);
@ -227,15 +245,45 @@ dri_sw_displaytarget_map(struct sw_winsys *ws,
unsigned flags)
{
struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
dri_sw_dt->map_flags = flags;
if (dri_sw_dt->unbacked)
return dri_sw_dt->mapped;
dri_sw_dt->mapped = dri_sw_dt->data;
#if DETECT_OS_UNIX
if (dri_sw_dt->fd > -1) {
bool success = false;
if (!success) {
/* if this fails, it's a dmabuf that wasn't exported by us,
* so it doesn't have the header that we're looking for
*/
off_t size = lseek(dri_sw_dt->fd, 0, SEEK_END);
lseek(dri_sw_dt->fd, 0, SEEK_SET);
if (size < 1) {
fprintf(stderr, "dmabuf import failed: fd has no data\n");
return NULL;
}
unsigned prot = 0;
if (flags & PIPE_MAP_READ)
prot |= PROT_READ;
if (flags & PIPE_MAP_WRITE)
prot |= PROT_WRITE;
dri_sw_dt->size = size;
dri_sw_dt->data = mmap(NULL, dri_sw_dt->size, prot, MAP_SHARED, dri_sw_dt->fd, 0);
if (dri_sw_dt->data == MAP_FAILED) {
dri_sw_dt->data = NULL;
fprintf(stderr, "dmabuf import failed to mmap: %s\n", strerror(errno));
} else
dri_sw_dt->mapped = ((uint8_t*)dri_sw_dt->data) + dri_sw_dt->offset;
} else
dri_sw_dt->mapped = ((uint8_t*)dri_sw_dt->data) + dri_sw_dt->offset;
} else
#endif
if (dri_sw_dt->front_private && (flags & PIPE_MAP_READ)) {
struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
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);
dri_sw_dt->mapped = dri_sw_dt->data;
} else {
dri_sw_dt->mapped = dri_sw_dt->data;
}
dri_sw_dt->map_flags = flags;
return dri_sw_dt->mapped;
}
@ -245,8 +293,16 @@ dri_sw_displaytarget_unmap(struct sw_winsys *ws,
{
struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(dt);
if (dri_sw_dt->unbacked)
if (dri_sw_dt->unbacked) {
dri_sw_dt->map_flags = 0;
return;
}
#if DETECT_OS_UNIX
if (dri_sw_dt->fd > -1) {
munmap(dri_sw_dt->data, dri_sw_dt->size);
dri_sw_dt->data = NULL;
} else
#endif
if (dri_sw_dt->front_private && (dri_sw_dt->map_flags & PIPE_MAP_WRITE)) {
struct dri_sw_winsys *dri_sw_ws = dri_sw_winsys(ws);
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);
@ -261,8 +317,17 @@ dri_sw_displaytarget_from_handle(struct sw_winsys *winsys,
struct winsys_handle *whandle,
unsigned *stride)
{
#if DETECT_OS_UNIX
int fd = os_dupfd_cloexec(whandle->handle);
struct sw_displaytarget *sw = dri_sw_displaytarget_create(winsys, templ->usage, templ->format, templ->width0, templ->height0, 64, NULL, stride);
struct dri_sw_displaytarget *dri_sw_dt = dri_sw_displaytarget(sw);
dri_sw_dt->fd = fd;
dri_sw_dt->offset = whandle->offset;
return sw;
#else
assert(0);
return NULL;
#endif
}
static bool