X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fstate_trackers%2Fdri%2Fdri2.c;h=5c903983cac29ce51e7b7fd80221c4c9d1c4bb8e;hb=67174d40f1ab4376d7dbef1e01eb1866ad332db0;hp=7f0db351c878b5e31c0a2778356e49fef4af8376;hpb=cbf29d90bae9ba415b8158afc3a06a1360ec0bc4;p=mesa.git diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c index 7f0db351c87..5c903983cac 100644 --- a/src/gallium/state_trackers/dri/dri2.c +++ b/src/gallium/state_trackers/dri/dri2.c @@ -29,7 +29,6 @@ */ #include -#include #include "GL/mesa_glinterop.h" #include "util/u_memory.h" #include "util/u_inlines.h" @@ -45,16 +44,67 @@ #include "main/bufferobj.h" #include "main/texobj.h" -#include "dri_screen.h" -#include "dri_context.h" +#include "dri_util.h" + +#include "dri_helpers.h" #include "dri_drawable.h" #include "dri_query_renderer.h" -#include "dri2_buffer.h" + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) +#endif + +struct dri2_buffer +{ + __DRIbuffer base; + struct pipe_resource *resource; +}; + +static inline struct dri2_buffer * +dri2_buffer(__DRIbuffer * driBufferPriv) +{ + return (struct dri2_buffer *) driBufferPriv; +} + +static const int fourcc_formats[] = { + __DRI_IMAGE_FOURCC_ARGB2101010, + __DRI_IMAGE_FOURCC_XRGB2101010, + __DRI_IMAGE_FOURCC_ABGR2101010, + __DRI_IMAGE_FOURCC_XBGR2101010, + __DRI_IMAGE_FOURCC_ARGB8888, + __DRI_IMAGE_FOURCC_ABGR8888, + __DRI_IMAGE_FOURCC_SARGB8888, + __DRI_IMAGE_FOURCC_XRGB8888, + __DRI_IMAGE_FOURCC_XBGR8888, + __DRI_IMAGE_FOURCC_ARGB1555, + __DRI_IMAGE_FOURCC_RGB565, + __DRI_IMAGE_FOURCC_R8, + __DRI_IMAGE_FOURCC_R16, + __DRI_IMAGE_FOURCC_GR88, + __DRI_IMAGE_FOURCC_GR1616, + __DRI_IMAGE_FOURCC_YUV410, + __DRI_IMAGE_FOURCC_YUV411, + __DRI_IMAGE_FOURCC_YUV420, + __DRI_IMAGE_FOURCC_YUV422, + __DRI_IMAGE_FOURCC_YUV444, + __DRI_IMAGE_FOURCC_YVU410, + __DRI_IMAGE_FOURCC_YVU411, + __DRI_IMAGE_FOURCC_YVU420, + __DRI_IMAGE_FOURCC_YVU422, + __DRI_IMAGE_FOURCC_YVU444, + __DRI_IMAGE_FOURCC_NV12, + __DRI_IMAGE_FOURCC_NV16, + __DRI_IMAGE_FOURCC_YUYV +}; static int convert_fourcc(int format, int *dri_components_p) { int dri_components; switch(format) { + case __DRI_IMAGE_FOURCC_ARGB1555: + format = __DRI_IMAGE_FORMAT_ARGB1555; + dri_components = __DRI_IMAGE_COMPONENTS_RGBA; + break; case __DRI_IMAGE_FOURCC_RGB565: format = __DRI_IMAGE_FORMAT_RGB565; dri_components = __DRI_IMAGE_COMPONENTS_RGB; @@ -75,6 +125,57 @@ static int convert_fourcc(int format, int *dri_components_p) format = __DRI_IMAGE_FORMAT_XBGR8888; dri_components = __DRI_IMAGE_COMPONENTS_RGB; break; + case __DRI_IMAGE_FOURCC_ARGB2101010: + format = __DRI_IMAGE_FORMAT_ARGB2101010; + dri_components = __DRI_IMAGE_COMPONENTS_RGBA; + break; + case __DRI_IMAGE_FOURCC_XRGB2101010: + format = __DRI_IMAGE_FORMAT_XRGB2101010; + dri_components = __DRI_IMAGE_COMPONENTS_RGB; + break; + case __DRI_IMAGE_FOURCC_ABGR2101010: + format = __DRI_IMAGE_FORMAT_ABGR2101010; + dri_components = __DRI_IMAGE_COMPONENTS_RGBA; + break; + case __DRI_IMAGE_FOURCC_XBGR2101010: + format = __DRI_IMAGE_FORMAT_XBGR2101010; + dri_components = __DRI_IMAGE_COMPONENTS_RGB; + break; + case __DRI_IMAGE_FOURCC_R8: + format = __DRI_IMAGE_FORMAT_R8; + dri_components = __DRI_IMAGE_COMPONENTS_R; + break; + case __DRI_IMAGE_FOURCC_GR88: + format = __DRI_IMAGE_FORMAT_GR88; + dri_components = __DRI_IMAGE_COMPONENTS_RG; + break; + case __DRI_IMAGE_FOURCC_R16: + format = __DRI_IMAGE_FORMAT_R16; + dri_components = __DRI_IMAGE_COMPONENTS_R; + break; + case __DRI_IMAGE_FOURCC_GR1616: + format = __DRI_IMAGE_FORMAT_GR1616; + dri_components = __DRI_IMAGE_COMPONENTS_RG; + break; + case __DRI_IMAGE_FOURCC_YUYV: + format = __DRI_IMAGE_FORMAT_YUYV; + dri_components = __DRI_IMAGE_COMPONENTS_Y_XUXV; + break; + /* + * For multi-planar YUV formats, we return the format of the first + * plane only. Since there is only one caller which supports multi- + * planar YUV it gets to figure out the remaining planes on it's + * own. + */ + case __DRI_IMAGE_FOURCC_YUV420: + case __DRI_IMAGE_FOURCC_YVU420: + format = __DRI_IMAGE_FORMAT_R8; + dri_components = __DRI_IMAGE_COMPONENTS_Y_U_V; + break; + case __DRI_IMAGE_FOURCC_NV12: + format = __DRI_IMAGE_FORMAT_R8; + dri_components = __DRI_IMAGE_COMPONENTS_Y_UV; + break; default: return -1; } @@ -82,9 +183,17 @@ static int convert_fourcc(int format, int *dri_components_p) return format; } +/* NOTE this probably isn't going to do the right thing for YUV images + * (but I think the same can be said for intel_query_image()). I think + * only needed for exporting dmabuf's, so I think I won't loose much + * sleep over it. + */ static int convert_to_fourcc(int format) { switch(format) { + case __DRI_IMAGE_FORMAT_ARGB1555: + format = __DRI_IMAGE_FOURCC_ARGB1555; + break; case __DRI_IMAGE_FORMAT_RGB565: format = __DRI_IMAGE_FOURCC_RGB565; break; @@ -100,6 +209,24 @@ static int convert_to_fourcc(int format) case __DRI_IMAGE_FORMAT_XBGR8888: format = __DRI_IMAGE_FOURCC_XBGR8888; break; + case __DRI_IMAGE_FORMAT_ARGB2101010: + format = __DRI_IMAGE_FOURCC_ARGB2101010; + break; + case __DRI_IMAGE_FORMAT_XRGB2101010: + format = __DRI_IMAGE_FOURCC_XRGB2101010; + break; + case __DRI_IMAGE_FORMAT_ABGR2101010: + format = __DRI_IMAGE_FOURCC_ABGR2101010; + break; + case __DRI_IMAGE_FORMAT_XBGR2101010: + format = __DRI_IMAGE_FOURCC_XBGR2101010; + break; + case __DRI_IMAGE_FORMAT_R8: + format = __DRI_IMAGE_FOURCC_R8; + break; + case __DRI_IMAGE_FORMAT_GR88: + format = __DRI_IMAGE_FOURCC_GR88; + break; default: return -1; } @@ -111,6 +238,9 @@ static enum pipe_format dri2_format_to_pipe_format (int format) enum pipe_format pf; switch (format) { + case __DRI_IMAGE_FORMAT_ARGB1555: + pf = PIPE_FORMAT_B5G5R5A1_UNORM; + break; case __DRI_IMAGE_FORMAT_RGB565: pf = PIPE_FORMAT_B5G6R5_UNORM; break; @@ -120,9 +250,39 @@ static enum pipe_format dri2_format_to_pipe_format (int format) case __DRI_IMAGE_FORMAT_ARGB8888: pf = PIPE_FORMAT_BGRA8888_UNORM; break; + case __DRI_IMAGE_FORMAT_XBGR8888: + pf = PIPE_FORMAT_RGBX8888_UNORM; + break; case __DRI_IMAGE_FORMAT_ABGR8888: pf = PIPE_FORMAT_RGBA8888_UNORM; break; + case __DRI_IMAGE_FORMAT_XRGB2101010: + pf = PIPE_FORMAT_B10G10R10X2_UNORM; + break; + case __DRI_IMAGE_FORMAT_ARGB2101010: + pf = PIPE_FORMAT_B10G10R10A2_UNORM; + break; + case __DRI_IMAGE_FORMAT_XBGR2101010: + pf = PIPE_FORMAT_R10G10B10X2_UNORM; + break; + case __DRI_IMAGE_FORMAT_ABGR2101010: + pf = PIPE_FORMAT_R10G10B10A2_UNORM; + break; + case __DRI_IMAGE_FORMAT_R8: + pf = PIPE_FORMAT_R8_UNORM; + break; + case __DRI_IMAGE_FORMAT_GR88: + pf = PIPE_FORMAT_RG88_UNORM; + break; + case __DRI_IMAGE_FORMAT_R16: + pf = PIPE_FORMAT_R16_UNORM; + break; + case __DRI_IMAGE_FORMAT_GR1616: + pf = PIPE_FORMAT_R16G16_UNORM; + break; + case __DRI_IMAGE_FORMAT_YUYV: + pf = PIPE_FORMAT_YUYV; + break; default: pf = PIPE_FORMAT_NONE; break; @@ -131,6 +291,82 @@ static enum pipe_format dri2_format_to_pipe_format (int format) return pf; } +static enum pipe_format fourcc_to_pipe_format(int fourcc) +{ + enum pipe_format pf; + + switch (fourcc) { + case __DRI_IMAGE_FOURCC_R8: + pf = PIPE_FORMAT_R8_UNORM; + break; + case __DRI_IMAGE_FOURCC_GR88: + pf = PIPE_FORMAT_RG88_UNORM; + break; + case __DRI_IMAGE_FOURCC_ARGB1555: + pf = PIPE_FORMAT_B5G5R5A1_UNORM; + break; + case __DRI_IMAGE_FOURCC_R16: + pf = PIPE_FORMAT_R16_UNORM; + break; + case __DRI_IMAGE_FOURCC_GR1616: + pf = PIPE_FORMAT_RG1616_UNORM; + break; + case __DRI_IMAGE_FOURCC_RGB565: + pf = PIPE_FORMAT_B5G6R5_UNORM; + break; + case __DRI_IMAGE_FOURCC_ARGB8888: + pf = PIPE_FORMAT_BGRA8888_UNORM; + break; + case __DRI_IMAGE_FOURCC_XRGB8888: + pf = PIPE_FORMAT_BGRX8888_UNORM; + break; + case __DRI_IMAGE_FOURCC_ABGR8888: + pf = PIPE_FORMAT_RGBA8888_UNORM; + break; + case __DRI_IMAGE_FOURCC_XBGR8888: + pf = PIPE_FORMAT_RGBX8888_UNORM; + break; + case __DRI_IMAGE_FOURCC_ARGB2101010: + pf = PIPE_FORMAT_B10G10R10A2_UNORM; + break; + case __DRI_IMAGE_FOURCC_XRGB2101010: + pf = PIPE_FORMAT_B10G10R10X2_UNORM; + break; + case __DRI_IMAGE_FOURCC_ABGR2101010: + pf = PIPE_FORMAT_R10G10B10A2_UNORM; + break; + case __DRI_IMAGE_FOURCC_XBGR2101010: + pf = PIPE_FORMAT_R10G10B10X2_UNORM; + break; + + case __DRI_IMAGE_FOURCC_NV12: + pf = PIPE_FORMAT_NV12; + break; + case __DRI_IMAGE_FOURCC_YUYV: + pf = PIPE_FORMAT_YUYV; + break; + case __DRI_IMAGE_FOURCC_YUV420: + case __DRI_IMAGE_FOURCC_YVU420: + pf = PIPE_FORMAT_YV12; + break; + + case __DRI_IMAGE_FOURCC_SARGB8888: + case __DRI_IMAGE_FOURCC_YUV410: + case __DRI_IMAGE_FOURCC_YUV411: + case __DRI_IMAGE_FOURCC_YUV422: + case __DRI_IMAGE_FOURCC_YUV444: + case __DRI_IMAGE_FOURCC_NV16: + case __DRI_IMAGE_FOURCC_YVU410: + case __DRI_IMAGE_FOURCC_YVU411: + case __DRI_IMAGE_FOURCC_YVU422: + case __DRI_IMAGE_FOURCC_YVU444: + default: + pf = PIPE_FORMAT_NONE; + } + + return pf; +} + /** * DRI2 flush extension. */ @@ -147,6 +383,7 @@ dri2_invalidate_drawable(__DRIdrawable *dPriv) dri2InvalidateDrawable(dPriv); drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp; + drawable->texture_mask = 0; p_atomic_inc(&drawable->base.stamp); } @@ -218,10 +455,18 @@ dri2_drawable_get_buffers(struct dri_drawable *drawable, * may occur as the stvis->color_format. */ switch(format) { + case PIPE_FORMAT_B10G10R10A2_UNORM: + case PIPE_FORMAT_R10G10B10A2_UNORM: case PIPE_FORMAT_BGRA8888_UNORM: + case PIPE_FORMAT_RGBA8888_UNORM: depth = 32; break; + case PIPE_FORMAT_R10G10B10X2_UNORM: + case PIPE_FORMAT_B10G10R10X2_UNORM: + depth = 30; + break; case PIPE_FORMAT_BGRX8888_UNORM: + case PIPE_FORMAT_RGBX8888_UNORM: depth = 24; break; case PIPE_FORMAT_B5G6R5_UNORM: @@ -288,6 +533,9 @@ dri_image_drawable_get_buffers(struct dri_drawable *drawable, } switch (pf) { + case PIPE_FORMAT_B5G5R5A1_UNORM: + image_format = __DRI_IMAGE_FORMAT_ARGB1555; + break; case PIPE_FORMAT_B5G6R5_UNORM: image_format = __DRI_IMAGE_FORMAT_RGB565; break; @@ -297,9 +545,24 @@ dri_image_drawable_get_buffers(struct dri_drawable *drawable, case PIPE_FORMAT_BGRA8888_UNORM: image_format = __DRI_IMAGE_FORMAT_ARGB8888; break; + case PIPE_FORMAT_RGBX8888_UNORM: + image_format = __DRI_IMAGE_FORMAT_XBGR8888; + break; case PIPE_FORMAT_RGBA8888_UNORM: image_format = __DRI_IMAGE_FORMAT_ABGR8888; break; + case PIPE_FORMAT_B10G10R10X2_UNORM: + image_format = __DRI_IMAGE_FORMAT_XRGB2101010; + break; + case PIPE_FORMAT_B10G10R10A2_UNORM: + image_format = __DRI_IMAGE_FORMAT_ARGB2101010; + break; + case PIPE_FORMAT_R10G10B10X2_UNORM: + image_format = __DRI_IMAGE_FORMAT_XBGR2101010; + break; + case PIPE_FORMAT_R10G10B10A2_UNORM: + image_format = __DRI_IMAGE_FORMAT_ABGR2101010; + break; default: image_format = __DRI_IMAGE_FORMAT_NONE; break; @@ -346,6 +609,9 @@ dri2_allocate_buffer(__DRIscreen *sPriv, case 32: pf = PIPE_FORMAT_BGRA8888_UNORM; break; + case 30: + pf = PIPE_FORMAT_B10G10R10X2_UNORM; + break; case 24: pf = PIPE_FORMAT_BGRX8888_UNORM; break; @@ -379,13 +645,13 @@ dri2_allocate_buffer(__DRIscreen *sPriv, memset(&whandle, 0, sizeof(whandle)); if (screen->can_share_buffer) - whandle.type = DRM_API_HANDLE_TYPE_SHARED; + whandle.type = WINSYS_HANDLE_TYPE_SHARED; else - whandle.type = DRM_API_HANDLE_TYPE_KMS; + whandle.type = WINSYS_HANDLE_TYPE_KMS; - screen->base.screen->resource_get_handle(screen->base.screen, + screen->base.screen->resource_get_handle(screen->base.screen, NULL, buffer->resource, &whandle, - PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ); + PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); buffer->base.attachment = attachment; buffer->base.name = whandle.handle; @@ -565,14 +831,15 @@ dri2_allocate_textures(struct dri_context *ctx, whandle.handle = buf->name; whandle.stride = buf->pitch; whandle.offset = 0; + whandle.modifier = DRM_FORMAT_MOD_INVALID; if (screen->can_share_buffer) - whandle.type = DRM_API_HANDLE_TYPE_SHARED; + whandle.type = WINSYS_HANDLE_TYPE_SHARED; else - whandle.type = DRM_API_HANDLE_TYPE_KMS; + whandle.type = WINSYS_HANDLE_TYPE_KMS; drawable->textures[statt] = screen->base.screen->resource_from_handle(screen->base.screen, &templ, &whandle, - PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ); + PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); assert(drawable->textures[statt]); } } @@ -587,8 +854,10 @@ dri2_allocate_textures(struct dri_context *ctx, if (drawable->textures[statt]) { templ.format = drawable->textures[statt]->format; - templ.bind = drawable->textures[statt]->bind & ~PIPE_BIND_SCANOUT; + templ.bind = drawable->textures[statt]->bind & + ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED); templ.nr_samples = drawable->stvis.samples; + templ.nr_storage_samples = drawable->stvis.samples; /* Try to reuse the resource. * (the other resource parameters should be constant) @@ -636,14 +905,16 @@ dri2_allocate_textures(struct dri_context *ctx, if (format) { templ.format = format; - templ.bind = bind; + templ.bind = bind & ~PIPE_BIND_SHARED; if (drawable->stvis.samples > 1) { templ.nr_samples = drawable->stvis.samples; + templ.nr_storage_samples = drawable->stvis.samples; zsbuf = &drawable->msaa_textures[statt]; } else { templ.nr_samples = 0; + templ.nr_storage_samples = 0; zsbuf = &drawable->textures[statt]; } @@ -715,6 +986,21 @@ dri2_flush_frontbuffer(struct dri_context *ctx, } } +/** + * The struct dri_drawable flush_swapbuffers callback + */ +static void +dri2_flush_swapbuffers(struct dri_context *ctx, + struct dri_drawable *drawable) +{ + __DRIdrawable *dri_drawable = drawable->dPriv; + const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader; + + if (image && image->base.version >= 3 && image->flushSwapBuffers) { + image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate); + } +} + static void dri2_update_tex_buffer(struct dri_drawable *drawable, struct dri_context *ctx, @@ -723,60 +1009,78 @@ dri2_update_tex_buffer(struct dri_drawable *drawable, /* no-op */ } -static __DRIimage * -dri2_lookup_egl_image(struct dri_screen *screen, void *handle) -{ - const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image; - __DRIimage *img; - - if (!loader->lookupEGLImage) - return NULL; - - img = loader->lookupEGLImage(screen->sPriv, - handle, screen->sPriv->loaderPrivate); - - return img; -} - static __DRIimage * dri2_create_image_from_winsys(__DRIscreen *_screen, int width, int height, int format, - struct winsys_handle *whandle, + int num_handles, struct winsys_handle *whandle, void *loaderPrivate) { struct dri_screen *screen = dri_screen(_screen); + struct pipe_screen *pscreen = screen->base.screen; __DRIimage *img; struct pipe_resource templ; - unsigned tex_usage; + unsigned tex_usage = 0; enum pipe_format pf; - - tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + int i; pf = dri2_format_to_pipe_format (format); if (pf == PIPE_FORMAT_NONE) return NULL; + if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0, + PIPE_BIND_RENDER_TARGET)) + tex_usage |= PIPE_BIND_RENDER_TARGET; + if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0, + PIPE_BIND_SAMPLER_VIEW)) + tex_usage |= PIPE_BIND_SAMPLER_VIEW; + img = CALLOC_STRUCT(__DRIimageRec); if (!img) return NULL; memset(&templ, 0, sizeof(templ)); templ.bind = tex_usage; - templ.format = pf; templ.target = screen->target; templ.last_level = 0; - templ.width0 = width; - templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; - whandle->offset = 0; + for (i = num_handles - 1; i >= 0; i--) { + struct pipe_resource *tex; - img->texture = screen->base.screen->resource_from_handle(screen->base.screen, - &templ, whandle, PIPE_HANDLE_USAGE_READ_WRITE); - if (!img->texture) { - FREE(img); - return NULL; + /* TODO: something a lot less ugly */ + switch (i) { + case 0: + templ.width0 = width; + templ.height0 = height; + templ.format = pf; + break; + case 1: + templ.width0 = width / 2; + templ.height0 = height / 2; + templ.format = (num_handles == 2) ? + PIPE_FORMAT_RG88_UNORM : /* NV12, etc */ + PIPE_FORMAT_R8_UNORM; /* I420, etc */ + break; + case 2: + templ.width0 = width / 2; + templ.height0 = height / 2; + templ.format = PIPE_FORMAT_R8_UNORM; + break; + default: + unreachable("too many planes!"); + } + + tex = pscreen->resource_from_handle(pscreen, + &templ, &whandle[i], PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE); + if (!tex) { + pipe_resource_reference(&img->texture, NULL); + FREE(img); + return NULL; + } + + tex->next = img->texture; + img->texture = tex; } img->level = 0; @@ -797,8 +1101,9 @@ dri2_create_image_from_name(__DRIscreen *_screen, enum pipe_format pf; memset(&whandle, 0, sizeof(whandle)); - whandle.type = DRM_API_HANDLE_TYPE_SHARED; + whandle.type = WINSYS_HANDLE_TYPE_SHARED; whandle.handle = name; + whandle.modifier = DRM_FORMAT_MOD_INVALID; pf = dri2_format_to_pipe_format (format); if (pf == PIPE_FORMAT_NONE) @@ -807,45 +1112,88 @@ dri2_create_image_from_name(__DRIscreen *_screen, whandle.stride = pitch * util_format_get_blocksize(pf); return dri2_create_image_from_winsys(_screen, width, height, format, - &whandle, loaderPrivate); + 1, &whandle, loaderPrivate); } static __DRIimage * dri2_create_image_from_fd(__DRIscreen *_screen, - int width, int height, int format, - int fd, int stride, void *loaderPrivate) + int width, int height, int fourcc, + uint64_t modifier, int *fds, int num_fds, + int *strides, int *offsets, unsigned *error, + int *dri_components, void *loaderPrivate) { - struct winsys_handle whandle; + struct winsys_handle whandles[3]; + int format; + __DRIimage *img = NULL; + unsigned err = __DRI_IMAGE_ERROR_SUCCESS; + int expected_num_fds, i; + + switch (fourcc) { + case __DRI_IMAGE_FOURCC_YUV420: + case __DRI_IMAGE_FOURCC_YVU420: + expected_num_fds = 3; + break; + case __DRI_IMAGE_FOURCC_NV12: + expected_num_fds = 2; + break; + default: + expected_num_fds = 1; + break; + } - if (fd < 0) - return NULL; + if (num_fds != expected_num_fds) { + err = __DRI_IMAGE_ERROR_BAD_MATCH; + goto exit; + } - memset(&whandle, 0, sizeof(whandle)); - whandle.type = DRM_API_HANDLE_TYPE_FD; - whandle.handle = (unsigned)fd; - whandle.stride = stride; + format = convert_fourcc(fourcc, dri_components); + if (format == -1) { + err = __DRI_IMAGE_ERROR_BAD_MATCH; + goto exit; + } - return dri2_create_image_from_winsys(_screen, width, height, format, - &whandle, loaderPrivate); -} + memset(whandles, 0, sizeof(whandles)); -static __DRIimage * -dri2_create_image_from_renderbuffer(__DRIcontext *context, - int renderbuffer, void *loaderPrivate) -{ - struct dri_context *ctx = dri_context(context); + for (i = 0; i < num_fds; i++) { + if (fds[i] < 0) { + err = __DRI_IMAGE_ERROR_BAD_ALLOC; + goto exit; + } - if (!ctx->st->get_resource_for_egl_image) - return NULL; + whandles[i].type = WINSYS_HANDLE_TYPE_FD; + whandles[i].handle = (unsigned)fds[i]; + whandles[i].stride = (unsigned)strides[i]; + whandles[i].offset = (unsigned)offsets[i]; + whandles[i].modifier = modifier; + } - /* TODO */ - return NULL; + if (fourcc == __DRI_IMAGE_FOURCC_YVU420) { + /* convert to YUV420 by swapping 2nd and 3rd planes: */ + struct winsys_handle tmp = whandles[1]; + whandles[1] = whandles[2]; + whandles[2] = tmp; + fourcc = __DRI_IMAGE_FOURCC_YUV420; + } + + img = dri2_create_image_from_winsys(_screen, width, height, format, + num_fds, whandles, loaderPrivate); + if(img == NULL) + err = __DRI_IMAGE_ERROR_BAD_ALLOC; + +exit: + if (error) + *error = err; + + return img; } static __DRIimage * -dri2_create_image(__DRIscreen *_screen, - int width, int height, int format, - unsigned int use, void *loaderPrivate) +dri2_create_image_common(__DRIscreen *_screen, + int width, int height, + int format, unsigned int use, + const uint64_t *modifiers, + const unsigned count, + void *loaderPrivate) { struct dri_screen *screen = dri_screen(_screen); __DRIimage *img; @@ -853,7 +1201,13 @@ dri2_create_image(__DRIscreen *_screen, unsigned tex_usage; enum pipe_format pf; + /* createImageWithModifiers doesn't supply usage, and we should not get + * here with both modifiers and a usage flag. + */ + assert(!(use && (modifiers != NULL))); + tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + if (use & __DRI_IMAGE_USE_SCANOUT) tex_usage |= PIPE_BIND_SCANOUT; if (use & __DRI_IMAGE_USE_SHARE) @@ -884,7 +1238,16 @@ dri2_create_image(__DRIscreen *_screen, templ.depth0 = 1; templ.array_size = 1; - img->texture = screen->base.screen->resource_create(screen->base.screen, &templ); + if (modifiers) + img->texture = + screen->base.screen + ->resource_create_with_modifiers(screen->base.screen, + &templ, + modifiers, + count); + else + img->texture = + screen->base.screen->resource_create(screen->base.screen, &templ); if (!img->texture) { FREE(img); return NULL; @@ -900,6 +1263,28 @@ dri2_create_image(__DRIscreen *_screen, return img; } +static __DRIimage * +dri2_create_image(__DRIscreen *_screen, + int width, int height, int format, + unsigned int use, void *loaderPrivate) +{ + return dri2_create_image_common(_screen, width, height, format, use, + NULL /* modifiers */, 0 /* count */, + loaderPrivate); +} + +static __DRIimage * +dri2_create_image_with_modifiers(__DRIscreen *dri_screen, + int width, int height, int format, + const uint64_t *modifiers, + const unsigned count, + void *loaderPrivate) +{ + return dri2_create_image_common(dri_screen, width, height, format, + 0 /* use */, modifiers, count, + loaderPrivate); +} + static GLboolean dri2_query_image(__DRIimage *image, int attrib, int *value) { @@ -907,35 +1292,47 @@ dri2_query_image(__DRIimage *image, int attrib, int *value) unsigned usage; if (image->use & __DRI_IMAGE_USE_BACKBUFFER) - usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ; + usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH; else - usage = PIPE_HANDLE_USAGE_READ_WRITE; + usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE; memset(&whandle, 0, sizeof(whandle)); switch (attrib) { case __DRI_IMAGE_ATTRIB_STRIDE: - whandle.type = DRM_API_HANDLE_TYPE_KMS; - image->texture->screen->resource_get_handle(image->texture->screen, - image->texture, &whandle, usage); + whandle.type = WINSYS_HANDLE_TYPE_KMS; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; *value = whandle.stride; return GL_TRUE; + case __DRI_IMAGE_ATTRIB_OFFSET: + whandle.type = WINSYS_HANDLE_TYPE_KMS; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; + *value = whandle.offset; + return GL_TRUE; case __DRI_IMAGE_ATTRIB_HANDLE: - whandle.type = DRM_API_HANDLE_TYPE_KMS; - image->texture->screen->resource_get_handle(image->texture->screen, - image->texture, &whandle, usage); + whandle.type = WINSYS_HANDLE_TYPE_KMS; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; *value = whandle.handle; return GL_TRUE; case __DRI_IMAGE_ATTRIB_NAME: - whandle.type = DRM_API_HANDLE_TYPE_SHARED; - image->texture->screen->resource_get_handle(image->texture->screen, - image->texture, &whandle, usage); + whandle.type = WINSYS_HANDLE_TYPE_SHARED; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; *value = whandle.handle; return GL_TRUE; case __DRI_IMAGE_ATTRIB_FD: - whandle.type= DRM_API_HANDLE_TYPE_FD; - image->texture->screen->resource_get_handle(image->texture->screen, - image->texture, &whandle, usage); + whandle.type= WINSYS_HANDLE_TYPE_FD; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; + *value = whandle.handle; return GL_TRUE; case __DRI_IMAGE_ATTRIB_FORMAT: @@ -954,10 +1351,30 @@ dri2_query_image(__DRIimage *image, int attrib, int *value) return GL_TRUE; case __DRI_IMAGE_ATTRIB_FOURCC: *value = convert_to_fourcc(image->dri_format); - return GL_TRUE; + return *value != -1; case __DRI_IMAGE_ATTRIB_NUM_PLANES: *value = 1; return GL_TRUE; + case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER: + whandle.type = WINSYS_HANDLE_TYPE_KMS; + whandle.modifier = DRM_FORMAT_MOD_INVALID; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; + if (whandle.modifier == DRM_FORMAT_MOD_INVALID) + return GL_FALSE; + *value = (whandle.modifier >> 32) & 0xffffffff; + return GL_TRUE; + case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER: + whandle.type = WINSYS_HANDLE_TYPE_KMS; + whandle.modifier = DRM_FORMAT_MOD_INVALID; + if (!image->texture->screen->resource_get_handle(image->texture->screen, + NULL, image->texture, &whandle, usage)) + return GL_FALSE; + if (whandle.modifier == DRM_FORMAT_MOD_INVALID) + return GL_FALSE; + *value = whandle.modifier & 0xffffffff; + return GL_TRUE; default: return GL_FALSE; } @@ -987,15 +1404,29 @@ dri2_dup_image(__DRIimage *image, void *loaderPrivate) static GLboolean dri2_validate_usage(__DRIimage *image, unsigned int use) { - /* - * Gallium drivers are bad at adding usages to the resources - * once opened again in another process, which is the main use - * case for this, so we have to lie. + if (!image || !image->texture) + return false; + + struct pipe_screen *screen = image->texture->screen; + if (!screen->check_resource_capability) + return true; + + /* We don't want to check these: + * __DRI_IMAGE_USE_SHARE (all images are shareable) + * __DRI_IMAGE_USE_BACKBUFFER (all images support this) */ - if (image != NULL) - return GL_TRUE; - else - return GL_FALSE; + unsigned bind = 0; + if (use & __DRI_IMAGE_USE_SCANOUT) + bind |= PIPE_BIND_SCANOUT; + if (use & __DRI_IMAGE_USE_LINEAR) + bind |= PIPE_BIND_LINEAR; + if (use & __DRI_IMAGE_USE_CURSOR) + bind |= PIPE_BIND_CURSOR; + + if (!bind) + return true; + + return screen->check_resource_capability(screen, image->texture, bind); } static __DRIimage * @@ -1009,20 +1440,20 @@ dri2_from_names(__DRIscreen *screen, int width, int height, int format, if (num_names != 1) return NULL; - if (offsets[0] != 0) - return NULL; format = convert_fourcc(format, &dri_components); if (format == -1) return NULL; memset(&whandle, 0, sizeof(whandle)); - whandle.type = DRM_API_HANDLE_TYPE_SHARED; + whandle.type = WINSYS_HANDLE_TYPE_SHARED; whandle.handle = names[0]; whandle.stride = strides[0]; + whandle.offset = offsets[0]; + whandle.modifier = DRM_FORMAT_MOD_INVALID; img = dri2_create_image_from_winsys(screen, width, height, format, - &whandle, loaderPrivate); + 1, &whandle, loaderPrivate); if (img == NULL) return NULL; @@ -1045,101 +1476,84 @@ dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate) if (img == NULL) return NULL; + if (img->texture->screen->resource_changed) + img->texture->screen->resource_changed(img->texture->screen, + img->texture); + /* set this to 0 for sub images. */ img->dri_components = 0; return img; } static __DRIimage * -dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture, - int depth, int level, unsigned *error, - void *loaderPrivate) +dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc, + int *fds, int num_fds, int *strides, int *offsets, + void *loaderPrivate) { __DRIimage *img; - struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx; - struct gl_texture_object *obj; - struct pipe_resource *tex; - GLuint face = 0; - - obj = _mesa_lookup_texture(ctx, texture); - if (!obj || obj->Target != target) { - *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; - return NULL; - } - - tex = st_get_texobj_resource(obj); - if (!tex) { - *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; - return NULL; - } - - if (target == GL_TEXTURE_CUBE_MAP) - face = depth; - - _mesa_test_texobj_completeness(ctx, obj); - if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) { - *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; - return NULL; - } - - if (level < obj->BaseLevel || level > obj->_MaxLevel) { - *error = __DRI_IMAGE_ERROR_BAD_MATCH; - return NULL; - } - - if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) { - *error = __DRI_IMAGE_ERROR_BAD_MATCH; - return NULL; - } - - img = CALLOC_STRUCT(__DRIimageRec); - if (!img) { - *error = __DRI_IMAGE_ERROR_BAD_ALLOC; - return NULL; - } - - img->level = level; - img->layer = depth; - img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat); - - img->loader_private = loaderPrivate; + int dri_components; - if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) { - *error = __DRI_IMAGE_ERROR_BAD_PARAMETER; - free(img); + img = dri2_create_image_from_fd(screen, width, height, fourcc, + DRM_FORMAT_MOD_INVALID, fds, num_fds, + strides, offsets, NULL, + &dri_components, loaderPrivate); + if (img == NULL) return NULL; - } - - pipe_resource_reference(&img->texture, tex); - *error = __DRI_IMAGE_ERROR_SUCCESS; + img->dri_components = dri_components; return img; } -static __DRIimage * -dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc, - int *fds, int num_fds, int *strides, int *offsets, - void *loaderPrivate) +static boolean +dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats, + int *count) { - __DRIimage *img; - int format, dri_components; + struct dri_screen *screen = dri_screen(_screen); + struct pipe_screen *pscreen = screen->base.screen; + int i, j; - if (num_fds != 1) - return NULL; - if (offsets[0] != 0) - return NULL; + for (i = 0, j = 0; (i < ARRAY_SIZE(fourcc_formats)) && + (j < max || max == 0); i++) { + enum pipe_format format = fourcc_to_pipe_format(fourcc_formats[i]); - format = convert_fourcc(fourcc, &dri_components); - if (format == -1) - return NULL; + /* The sRGB format is not a real FourCC as defined by drm_fourcc.h, so we + * must not leak it out to clients. + */ + if (fourcc_formats[i] == __DRI_IMAGE_FOURCC_SARGB8888) + continue; - img = dri2_create_image_from_fd(screen, width, height, format, - fds[0], strides[0], loaderPrivate); - if (img == NULL) - return NULL; + if (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, + PIPE_BIND_RENDER_TARGET) || + pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, + PIPE_BIND_SAMPLER_VIEW)) { + if (j < max) + formats[j] = fourcc_formats[i]; + j++; + } + } + *count = j; + return true; +} - img->dri_components = dri_components; - return img; +static boolean +dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max, + uint64_t *modifiers, unsigned int *external_only, + int *count) +{ + struct dri_screen *screen = dri_screen(_screen); + struct pipe_screen *pscreen = screen->base.screen; + enum pipe_format format = fourcc_to_pipe_format(fourcc); + + if (pscreen->query_dmabuf_modifiers != NULL && + (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, + PIPE_BIND_RENDER_TARGET) || + pscreen->is_format_supported(pscreen, format, screen->target, 0, 0, + PIPE_BIND_SAMPLER_VIEW))) { + pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers, + external_only, count); + return true; + } + return false; } static __DRIimage * @@ -1155,25 +1569,45 @@ dri2_from_dma_bufs(__DRIscreen *screen, void *loaderPrivate) { __DRIimage *img; - int format, dri_components; + int dri_components; - if (num_fds != 1 || offsets[0] != 0) { - *error = __DRI_IMAGE_ERROR_BAD_MATCH; + img = dri2_create_image_from_fd(screen, width, height, fourcc, + DRM_FORMAT_MOD_INVALID, fds, num_fds, + strides, offsets, error, + &dri_components, loaderPrivate); + if (img == NULL) return NULL; - } - format = convert_fourcc(fourcc, &dri_components); - if (format == -1) { - *error = __DRI_IMAGE_ERROR_BAD_MATCH; - return NULL; - } + img->yuv_color_space = yuv_color_space; + img->sample_range = sample_range; + img->horizontal_siting = horizontal_siting; + img->vertical_siting = vertical_siting; + img->dri_components = dri_components; - img = dri2_create_image_from_fd(screen, width, height, format, - fds[0], strides[0], loaderPrivate); - if (img == NULL) { - *error = __DRI_IMAGE_ERROR_BAD_ALLOC; + *error = __DRI_IMAGE_ERROR_SUCCESS; + return img; +} + +static __DRIimage * +dri2_from_dma_bufs2(__DRIscreen *screen, + int width, int height, int fourcc, + uint64_t modifier, int *fds, int num_fds, + int *strides, int *offsets, + enum __DRIYUVColorSpace yuv_color_space, + enum __DRISampleRange sample_range, + enum __DRIChromaSiting horizontal_siting, + enum __DRIChromaSiting vertical_siting, + unsigned *error, + void *loaderPrivate) +{ + __DRIimage *img; + int dri_components; + + img = dri2_create_image_from_fd(screen, width, height, fourcc, + modifier, fds, num_fds, strides, offsets, + error, &dri_components, loaderPrivate); + if (img == NULL) return NULL; - } img->yuv_color_space = yuv_color_space; img->sample_range = sample_range; @@ -1227,7 +1661,7 @@ dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src, screen = dri_screen(ctx->sPriv)->base.screen; pipe->flush_resource(pipe, dst->texture); ctx->st->flush(ctx->st, 0, &fence); - (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); + (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE); screen->fence_reference(screen, &fence, NULL); } } @@ -1271,13 +1705,6 @@ dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data) pipe_transfer_unmap(pipe, (struct pipe_transfer *)data); } -static void -dri2_destroy_image(__DRIimage *img) -{ - pipe_resource_reference(&img->texture, NULL); - FREE(img); -} - static int dri2_get_capabilities(__DRIscreen *_screen) { @@ -1288,7 +1715,7 @@ dri2_get_capabilities(__DRIscreen *_screen) /* The extension is modified during runtime if DRI_PRIME is detected */ static __DRIimageExtension dri2ImageExtension = { - .base = { __DRI_IMAGE, 12 }, + .base = { __DRI_IMAGE, 17 }, .createImageFromName = dri2_create_image_from_name, .createImageFromRenderbuffer = dri2_create_image_from_renderbuffer, @@ -1306,156 +1733,12 @@ static __DRIimageExtension dri2ImageExtension = { .getCapabilities = dri2_get_capabilities, .mapImage = dri2_map_image, .unmapImage = dri2_unmap_image, -}; - - -static bool -dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen) -{ - return screen->opencl_dri_event_add_ref && - screen->opencl_dri_event_release && - screen->opencl_dri_event_wait && - screen->opencl_dri_event_get_fence; -} - -static bool -dri2_load_opencl_interop(struct dri_screen *screen) -{ -#if defined(RTLD_DEFAULT) - bool success; - - pipe_mutex_lock(screen->opencl_func_mutex); - - if (dri2_is_opencl_interop_loaded_locked(screen)) { - pipe_mutex_unlock(screen->opencl_func_mutex); - return true; - } - - screen->opencl_dri_event_add_ref = - dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref"); - screen->opencl_dri_event_release = - dlsym(RTLD_DEFAULT, "opencl_dri_event_release"); - screen->opencl_dri_event_wait = - dlsym(RTLD_DEFAULT, "opencl_dri_event_wait"); - screen->opencl_dri_event_get_fence = - dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence"); - - success = dri2_is_opencl_interop_loaded_locked(screen); - pipe_mutex_unlock(screen->opencl_func_mutex); - return success; -#else - return false; -#endif -} - -struct dri2_fence { - struct dri_screen *driscreen; - struct pipe_fence_handle *pipe_fence; - void *cl_event; -}; - -static void * -dri2_create_fence(__DRIcontext *_ctx) -{ - struct pipe_context *ctx = dri_context(_ctx)->st->pipe; - struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence); - - if (!fence) - return NULL; - - ctx->flush(ctx, &fence->pipe_fence, 0); - - if (!fence->pipe_fence) { - FREE(fence); - return NULL; - } - - fence->driscreen = dri_screen(_ctx->driScreenPriv); - return fence; -} - -static void * -dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event) -{ - struct dri_screen *driscreen = dri_screen(_screen); - struct dri2_fence *fence; - - if (!dri2_load_opencl_interop(driscreen)) - return NULL; - - fence = CALLOC_STRUCT(dri2_fence); - if (!fence) - return NULL; - - fence->cl_event = (void*)cl_event; - - if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) { - free(fence); - return NULL; - } - - fence->driscreen = driscreen; - return fence; -} - -static void -dri2_destroy_fence(__DRIscreen *_screen, void *_fence) -{ - struct dri_screen *driscreen = dri_screen(_screen); - struct pipe_screen *screen = driscreen->base.screen; - struct dri2_fence *fence = (struct dri2_fence*)_fence; - - if (fence->pipe_fence) - screen->fence_reference(screen, &fence->pipe_fence, NULL); - else if (fence->cl_event) - driscreen->opencl_dri_event_release(fence->cl_event); - else - assert(0); - - FREE(fence); -} - -static GLboolean -dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags, - uint64_t timeout) -{ - struct dri2_fence *fence = (struct dri2_fence*)_fence; - struct dri_screen *driscreen = fence->driscreen; - struct pipe_screen *screen = driscreen->base.screen; - - /* No need to flush. The context was flushed when the fence was created. */ - - if (fence->pipe_fence) - return screen->fence_finish(screen, fence->pipe_fence, timeout); - else if (fence->cl_event) { - struct pipe_fence_handle *pipe_fence = - driscreen->opencl_dri_event_get_fence(fence->cl_event); - - if (pipe_fence) - return screen->fence_finish(screen, pipe_fence, timeout); - else - return driscreen->opencl_dri_event_wait(fence->cl_event, timeout); - } - else { - assert(0); - return false; - } -} - -static void -dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags) -{ - /* AFAIK, no driver currently supports parallel context execution. */ -} - -static __DRI2fenceExtension dri2FenceExtension = { - .base = { __DRI2_FENCE, 1 }, - - .create_fence = dri2_create_fence, - .get_fence_from_cl_event = dri2_get_fence_from_cl_event, - .destroy_fence = dri2_destroy_fence, - .client_wait_sync = dri2_client_wait_sync, - .server_wait_sync = dri2_server_wait_sync + .createImageWithModifiers = NULL, + .createImageFromDmaBufs2 = NULL, + .queryDmaBufFormats = NULL, + .queryDmaBufModifiers = NULL, + .queryDmaBufFormatModifierAttribs = NULL, + .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2, }; static const __DRIrobustnessExtension dri2Robustness = { @@ -1464,12 +1747,13 @@ static const __DRIrobustnessExtension dri2Robustness = { static int dri2_interop_query_device_info(__DRIcontext *_ctx, - mesa_glinterop_device_info *out) + struct mesa_glinterop_device_info *out) { struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen; - if (!out->struct_version) - return MESA_GLINTEROP_INVALID_VALUE; + /* There is no version 0, thus we do not support it */ + if (out->version == 0) + return MESA_GLINTEROP_INVALID_VERSION; out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP); out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS); @@ -1479,15 +1763,16 @@ dri2_interop_query_device_info(__DRIcontext *_ctx, out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID); out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID); - out->interop_version = 1; + /* Instruct the caller that we support up-to version one of the interface */ + out->version = 1; return MESA_GLINTEROP_SUCCESS; } static int dri2_interop_export_object(__DRIcontext *_ctx, - const mesa_glinterop_export_in *in, - mesa_glinterop_export_out *out) + struct mesa_glinterop_export_in *in, + struct mesa_glinterop_export_out *out) { struct st_context_iface *st = dri_context(_ctx)->st; struct pipe_screen *screen = st->pipe->screen; @@ -1497,8 +1782,9 @@ dri2_interop_export_object(__DRIcontext *_ctx, unsigned target, usage; boolean success; - if (!in->struct_version || !out->struct_version) - return MESA_GLINTEROP_INVALID_VALUE; + /* There is no version 0, thus we do not support it */ + if (in->version == 0 || out->version == 0) + return MESA_GLINTEROP_INVALID_VERSION; /* Validate the target. */ switch (in->target) { @@ -1536,7 +1822,7 @@ dri2_interop_export_object(__DRIcontext *_ctx, return MESA_GLINTEROP_INVALID_MIP_LEVEL; /* Validate the OpenGL object and get pipe_resource. */ - mtx_lock(&ctx->Shared->Mutex); + simple_mtx_lock(&ctx->Shared->Mutex); if (target == GL_ARRAY_BUFFER) { /* Buffer objects. @@ -1552,14 +1838,14 @@ dri2_interop_export_object(__DRIcontext *_ctx, * the size of the buffer is 0." */ if (!buf || buf->Size == 0) { - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_INVALID_OBJECT; } res = st_buffer_object(buf)->buffer; if (!res) { /* this shouldn't happen */ - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_INVALID_OBJECT; } @@ -1580,7 +1866,7 @@ dri2_interop_export_object(__DRIcontext *_ctx, * object or if the width or height of renderbuffer is zero." */ if (!rb || rb->Width == 0 || rb->Height == 0) { - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_INVALID_OBJECT; } @@ -1589,7 +1875,7 @@ dri2_interop_export_object(__DRIcontext *_ctx, * renderbuffer object." */ if (rb->NumSamples > 1) { - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_INVALID_OPERATION; } @@ -1599,7 +1885,7 @@ dri2_interop_export_object(__DRIcontext *_ctx, */ res = st_renderbuffer(rb)->texture; if (!res) { - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_OUT_OF_RESOURCES; } @@ -1629,36 +1915,21 @@ dri2_interop_export_object(__DRIcontext *_ctx, obj->Target != target || !obj->_BaseComplete || (in->miplevel > 0 && !obj->_MipmapComplete)) { - mtx_unlock(&ctx->Shared->Mutex); + simple_mtx_unlock(&ctx->Shared->Mutex); return MESA_GLINTEROP_INVALID_OBJECT; } - /* From OpenCL 2.0 SDK, clCreateFromGLTexture: - * "CL_INVALID_MIP_LEVEL if miplevel is less than the value of - * levelbase (for OpenGL implementations) or zero (for OpenGL ES - * implementations); or greater than the value of q (for both OpenGL - * and OpenGL ES). levelbase and q are defined for the texture in - * section 3.8.10 (Texture Completeness) of the OpenGL 2.1 - * specification and section 3.7.10 of the OpenGL ES 2.0." - */ - if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) { - mtx_unlock(&ctx->Shared->Mutex); - return MESA_GLINTEROP_INVALID_MIP_LEVEL; - } - - if (!st_finalize_texture(ctx, st->pipe, obj)) { - mtx_unlock(&ctx->Shared->Mutex); - return MESA_GLINTEROP_OUT_OF_RESOURCES; - } + if (target == GL_TEXTURE_BUFFER) { + struct st_buffer_object *stBuf = + st_buffer_object(obj->BufferObject); - res = st_get_texobj_resource(obj); - if (!res) { - /* Incomplete texture buffer object? This shouldn't really occur. */ - mtx_unlock(&ctx->Shared->Mutex); - return MESA_GLINTEROP_INVALID_OBJECT; - } + if (!stBuf || !stBuf->buffer) { + /* this shouldn't happen */ + simple_mtx_unlock(&ctx->Shared->Mutex); + return MESA_GLINTEROP_INVALID_OBJECT; + } + res = stBuf->buffer; - if (target == GL_TEXTURE_BUFFER) { out->internal_format = obj->BufferObjectFormat; out->buf_offset = obj->BufferOffset; out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size : @@ -1666,6 +1937,31 @@ dri2_interop_export_object(__DRIcontext *_ctx, obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; } else { + /* From OpenCL 2.0 SDK, clCreateFromGLTexture: + * "CL_INVALID_MIP_LEVEL if miplevel is less than the value of + * levelbase (for OpenGL implementations) or zero (for OpenGL ES + * implementations); or greater than the value of q (for both OpenGL + * and OpenGL ES). levelbase and q are defined for the texture in + * section 3.8.10 (Texture Completeness) of the OpenGL 2.1 + * specification and section 3.7.10 of the OpenGL ES 2.0." + */ + if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) { + simple_mtx_unlock(&ctx->Shared->Mutex); + return MESA_GLINTEROP_INVALID_MIP_LEVEL; + } + + if (!st_finalize_texture(ctx, st->pipe, obj, 0)) { + simple_mtx_unlock(&ctx->Shared->Mutex); + return MESA_GLINTEROP_OUT_OF_RESOURCES; + } + + res = st_get_texobj_resource(obj); + if (!res) { + /* Incomplete texture buffer object? This shouldn't really occur. */ + simple_mtx_unlock(&ctx->Shared->Mutex); + return MESA_GLINTEROP_INVALID_OBJECT; + } + out->internal_format = obj->Image[0][0]->InternalFormat; out->view_minlevel = obj->MinLevel; out->view_numlevels = obj->NumLevels; @@ -1676,24 +1972,23 @@ dri2_interop_export_object(__DRIcontext *_ctx, /* Get the handle. */ switch (in->access) { - case MESA_GLINTEROP_ACCESS_READ_WRITE: - usage = PIPE_HANDLE_USAGE_READ_WRITE; - break; case MESA_GLINTEROP_ACCESS_READ_ONLY: - usage = PIPE_HANDLE_USAGE_READ; + usage = 0; break; + case MESA_GLINTEROP_ACCESS_READ_WRITE: case MESA_GLINTEROP_ACCESS_WRITE_ONLY: - usage = PIPE_HANDLE_USAGE_WRITE; + usage = PIPE_HANDLE_USAGE_SHADER_WRITE; break; default: usage = 0; } memset(&whandle, 0, sizeof(whandle)); - whandle.type = DRM_API_HANDLE_TYPE_FD; + whandle.type = WINSYS_HANDLE_TYPE_FD; - success = screen->resource_get_handle(screen, res, &whandle, usage); - mtx_unlock(&ctx->Shared->Mutex); + success = screen->resource_get_handle(screen, st->pipe, res, &whandle, + usage); + simple_mtx_unlock(&ctx->Shared->Mutex); if (!success) return MESA_GLINTEROP_OUT_OF_HOST_MEMORY; @@ -1704,6 +1999,10 @@ dri2_interop_export_object(__DRIcontext *_ctx, if (res->target == PIPE_BUFFER) out->buf_offset += whandle.offset; + /* Instruct the caller that we support up-to version one of the interface */ + in->version = 1; + out->version = 1; + return MESA_GLINTEROP_SUCCESS; } @@ -1713,6 +2012,69 @@ static const __DRI2interopExtension dri2InteropExtension = { .export_object = dri2_interop_export_object }; +/** + * \brief the DRI2ConfigQueryExtension configQueryb method + */ +static int +dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var, + unsigned char *val) +{ + struct dri_screen *screen = dri_screen(sPriv); + + if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL)) + return dri2ConfigQueryExtension.configQueryb(sPriv, var, val); + + *val = driQueryOptionb(&screen->dev->option_cache, var); + + return 0; +} + +/** + * \brief the DRI2ConfigQueryExtension configQueryi method + */ +static int +dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val) +{ + struct dri_screen *screen = dri_screen(sPriv); + + if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) && + !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM)) + return dri2ConfigQueryExtension.configQueryi(sPriv, var, val); + + *val = driQueryOptioni(&screen->dev->option_cache, var); + + return 0; +} + +/** + * \brief the DRI2ConfigQueryExtension configQueryf method + */ +static int +dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val) +{ + struct dri_screen *screen = dri_screen(sPriv); + + if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT)) + return dri2ConfigQueryExtension.configQueryf(sPriv, var, val); + + *val = driQueryOptionf(&screen->dev->option_cache, var); + + return 0; +} + +/** + * \brief the DRI2ConfigQueryExtension struct. + * + * We first query the driver option cache. Then the dri2 option cache. + */ +static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = { + .base = { __DRI2_CONFIG_QUERY, 1 }, + + .configQueryb = dri2GalliumConfigQueryb, + .configQueryi = dri2GalliumConfigQueryi, + .configQueryf = dri2GalliumConfigQueryf, +}; + /* * Backend function init_screen. */ @@ -1722,10 +2084,11 @@ static const __DRIextension *dri_screen_extensions[] = { &dri2FlushExtension.base, &dri2ImageExtension.base, &dri2RendererQueryExtension.base, - &dri2ConfigQueryExtension.base, + &dri2GalliumConfigQueryExtension.base, &dri2ThrottleExtension.base, &dri2FenceExtension.base, &dri2InteropExtension.base, + &dri2NoErrorExtension.base, NULL }; @@ -1734,11 +2097,12 @@ static const __DRIextension *dri_robust_screen_extensions[] = { &dri2FlushExtension.base, &dri2ImageExtension.base, &dri2RendererQueryExtension.base, - &dri2ConfigQueryExtension.base, + &dri2GalliumConfigQueryExtension.base, &dri2ThrottleExtension.base, &dri2FenceExtension.base, &dri2InteropExtension.base, &dri2Robustness.base, + &dri2NoErrorExtension.base, NULL }; @@ -1755,7 +2119,6 @@ dri2_init_screen(__DRIscreen * sPriv) struct pipe_screen *pscreen = NULL; const struct drm_conf_ret *throttle_ret; const struct drm_conf_ret *dmabuf_ret; - int fd; screen = CALLOC_STRUCT(dri_screen); if (!screen) @@ -1763,15 +2126,15 @@ dri2_init_screen(__DRIscreen * sPriv) screen->sPriv = sPriv; screen->fd = sPriv->fd; - pipe_mutex_init(screen->opencl_func_mutex); + (void) mtx_init(&screen->opencl_func_mutex, mtx_plain); sPriv->driverPrivate = (void *)screen; - if (screen->fd < 0 || (fd = dup(screen->fd)) < 0) - goto free_screen; + if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) { + dri_init_options(screen); - if (pipe_loader_drm_probe_fd(&screen->dev, fd)) pscreen = pipe_loader_create_screen(screen->dev); + } if (!pscreen) goto release_pipe; @@ -1784,6 +2147,10 @@ dri2_init_screen(__DRIscreen * sPriv) screen->default_throttle_frames = throttle_ret->val.val_int; } + if (pscreen->resource_create_with_modifiers) + dri2ImageExtension.createImageWithModifiers = + dri2_create_image_with_modifiers; + if (dmabuf_ret && dmabuf_ret->val.val_bool) { uint64_t cap; @@ -1791,6 +2158,12 @@ dri2_init_screen(__DRIscreen * sPriv) (cap & DRM_PRIME_CAP_IMPORT)) { dri2ImageExtension.createImageFromFds = dri2_from_fds; dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs; + dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2; + if (pscreen->query_dmabuf_modifiers) { + dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats; + dri2ImageExtension.queryDmaBufModifiers = + dri2_query_dma_buf_modifiers; + } } } @@ -1801,7 +2174,7 @@ dri2_init_screen(__DRIscreen * sPriv) else sPriv->extensions = dri_screen_extensions; - configs = dri_init_screen_helper(screen, pscreen, screen->dev->driver_name); + configs = dri_init_screen_helper(screen, pscreen); if (!configs) goto destroy_screen; @@ -1818,10 +2191,7 @@ destroy_screen: release_pipe: if (screen->dev) pipe_loader_release(&screen->dev, 1); - else - close(fd); -free_screen: FREE(screen); return NULL; } @@ -1839,7 +2209,6 @@ dri_kms_init_screen(__DRIscreen * sPriv) struct dri_screen *screen; struct pipe_screen *pscreen = NULL; uint64_t cap; - int fd; screen = CALLOC_STRUCT(dri_screen); if (!screen) @@ -1850,24 +2219,32 @@ dri_kms_init_screen(__DRIscreen * sPriv) sPriv->driverPrivate = (void *)screen; - if (screen->fd < 0 || (fd = dup(screen->fd)) < 0) - goto free_screen; - - if (pipe_loader_sw_probe_kms(&screen->dev, fd)) + if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) { + dri_init_options(screen); pscreen = pipe_loader_create_screen(screen->dev); + } if (!pscreen) goto release_pipe; + if (pscreen->resource_create_with_modifiers) + dri2ImageExtension.createImageWithModifiers = + dri2_create_image_with_modifiers; + if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 && (cap & DRM_PRIME_CAP_IMPORT)) { dri2ImageExtension.createImageFromFds = dri2_from_fds; dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs; + dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2; + if (pscreen->query_dmabuf_modifiers) { + dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats; + dri2ImageExtension.queryDmaBufModifiers = dri2_query_dma_buf_modifiers; + } } sPriv->extensions = dri_screen_extensions; - configs = dri_init_screen_helper(screen, pscreen, "swrast"); + configs = dri_init_screen_helper(screen, pscreen); if (!configs) goto destroy_screen; @@ -1884,10 +2261,7 @@ destroy_screen: release_pipe: if (screen->dev) pipe_loader_release(&screen->dev, 1); - else - close(fd); -free_screen: FREE(screen); #endif // GALLIUM_SOFTPIPE return NULL; @@ -1908,6 +2282,7 @@ dri2_create_buffer(__DRIscreen * sPriv, drawable->allocate_textures = dri2_allocate_textures; drawable->flush_frontbuffer = dri2_flush_frontbuffer; drawable->update_tex_buffer = dri2_update_tex_buffer; + drawable->flush_swapbuffers = dri2_flush_swapbuffers; return TRUE; }