diff --git a/src/gallium/winsys/sw/dri/dri_sw_winsys.c b/src/gallium/winsys/sw/dri/dri_sw_winsys.c index 9b3265a18ef..4c015543aba 100644 --- a/src/gallium/winsys/sw/dri/dri_sw_winsys.c +++ b/src/gallium/winsys/sw/dri/dri_sw_winsys.c @@ -39,11 +39,20 @@ #include "util/compiler.h" #include "util/format/u_formats.h" +#include "util/detect_os.h" + +#if DETECT_OS_UNIX +# include +# include +# include +#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