[Mesa-dev] [PATCH 01/11] gallium: Add __DRIimageDriverExtension support to gallium
Ben Skeggs
skeggsb at gmail.com
Wed Jun 18 20:34:35 PDT 2014
On Thu, Jun 19, 2014 at 1:27 PM, Axel Davy <axel.davy at ens.fr> wrote:
> __DRIimageDriverExtension is used by GLX DRI3 and Wayland.
>
> This patch is a rewrite of
> http://lists.freedesktop.org/archives/mesa-dev/2014-May/060318.html
> and
> http://lists.freedesktop.org/archives/mesa-dev/2014-May/060317.html
>
> Signed-off-by: Axel Davy <axel.davy at ens.fr>
> Reviewed-by: Marek Olšák<marek.olsak at amd.com>
Good timing, I did the exact same thing myself a couple of hours ago :P
Reviewed-by: Ben Skeggs <bskeggs at redhat.com>
>
> Previous patches were:
> Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
> Signed-off-by: Keith Packard <keithp at keithp.com>
> ---
> src/gallium/state_trackers/dri/drm/dri2.c | 469 ++++++++++++++++++------------
> 1 file changed, 286 insertions(+), 183 deletions(-)
>
> diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c
> index 7dccc5e..124d91b 100644
> --- a/src/gallium/state_trackers/dri/drm/dri2.c
> +++ b/src/gallium/state_trackers/dri/drm/dri2.c
> @@ -201,32 +201,192 @@ dri2_drawable_get_buffers(struct dri_drawable *drawable,
> return buffers;
> }
>
> -/**
> - * Process __DRIbuffer and convert them into pipe_resources.
> +static bool
> +dri_image_drawable_get_buffers(struct dri_drawable *drawable,
> + struct __DRIimageList *images,
> + const enum st_attachment_type *statts,
> + unsigned statts_count)
> +{
> + __DRIdrawable *dPriv = drawable->dPriv;
> + __DRIscreen *sPriv = drawable->sPriv;
> + unsigned int image_format = __DRI_IMAGE_FORMAT_NONE;
> + enum pipe_format pf;
> + uint32_t buffer_mask = 0;
> + unsigned i, bind;
> +
> + for (i = 0; i < statts_count; i++) {
> + dri_drawable_get_format(drawable, statts[i], &pf, &bind);
> + if (pf == PIPE_FORMAT_NONE)
> + continue;
> +
> + switch (statts[i]) {
> + case ST_ATTACHMENT_FRONT_LEFT:
> + buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
> + break;
> + case ST_ATTACHMENT_BACK_LEFT:
> + buffer_mask |= __DRI_IMAGE_BUFFER_BACK;
> + break;
> + default:
> + continue;
> + }
> +
> + switch (pf) {
> + case PIPE_FORMAT_B5G6R5_UNORM:
> + image_format = __DRI_IMAGE_FORMAT_RGB565;
> + break;
> + case PIPE_FORMAT_B8G8R8X8_UNORM:
> + image_format = __DRI_IMAGE_FORMAT_XRGB8888;
> + break;
> + case PIPE_FORMAT_B8G8R8A8_UNORM:
> + image_format = __DRI_IMAGE_FORMAT_ARGB8888;
> + break;
> + case PIPE_FORMAT_R8G8B8A8_UNORM:
> + image_format = __DRI_IMAGE_FORMAT_ABGR8888;
> + break;
> + default:
> + image_format = __DRI_IMAGE_FORMAT_NONE;
> + break;
> + }
> + }
> +
> + return (*sPriv->image.loader->getBuffers) (dPriv, image_format,
> + (uint32_t *) &drawable->base.stamp,
> + dPriv->loaderPrivate, buffer_mask,
> + images);
> +}
> +
> +static __DRIbuffer *
> +dri2_allocate_buffer(__DRIscreen *sPriv,
> + unsigned attachment, unsigned format,
> + int width, int height)
> +{
> + struct dri_screen *screen = dri_screen(sPriv);
> + struct dri2_buffer *buffer;
> + struct pipe_resource templ;
> + enum pipe_format pf;
> + unsigned bind = 0;
> + struct winsys_handle whandle;
> +
> + switch (attachment) {
> + case __DRI_BUFFER_FRONT_LEFT:
> + case __DRI_BUFFER_FAKE_FRONT_LEFT:
> + bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
> + break;
> + case __DRI_BUFFER_BACK_LEFT:
> + bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
> + break;
> + case __DRI_BUFFER_DEPTH:
> + case __DRI_BUFFER_DEPTH_STENCIL:
> + case __DRI_BUFFER_STENCIL:
> + bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
> + break;
> + }
> +
> + /* because we get the handle and stride */
> + bind |= PIPE_BIND_SHARED;
> +
> + switch (format) {
> + case 32:
> + pf = PIPE_FORMAT_B8G8R8A8_UNORM;
> + break;
> + case 24:
> + pf = PIPE_FORMAT_B8G8R8X8_UNORM;
> + break;
> + case 16:
> + pf = PIPE_FORMAT_Z16_UNORM;
> + break;
> + default:
> + return NULL;
> + }
> +
> + buffer = CALLOC_STRUCT(dri2_buffer);
> + if (!buffer)
> + return NULL;
> +
> + memset(&templ, 0, sizeof(templ));
> + templ.bind = bind;
> + templ.format = pf;
> + templ.target = PIPE_TEXTURE_2D;
> + templ.last_level = 0;
> + templ.width0 = width;
> + templ.height0 = height;
> + templ.depth0 = 1;
> + templ.array_size = 1;
> +
> + buffer->resource =
> + screen->base.screen->resource_create(screen->base.screen, &templ);
> + if (!buffer->resource) {
> + FREE(buffer);
> + return NULL;
> + }
> +
> + memset(&whandle, 0, sizeof(whandle));
> + whandle.type = DRM_API_HANDLE_TYPE_SHARED;
> + screen->base.screen->resource_get_handle(screen->base.screen,
> + buffer->resource, &whandle);
> +
> + buffer->base.attachment = attachment;
> + buffer->base.name = whandle.handle;
> + buffer->base.cpp = util_format_get_blocksize(pf);
> + buffer->base.pitch = whandle.stride;
> +
> + return &buffer->base;
> +}
> +
> +static void
> +dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
> +{
> + struct dri2_buffer *buffer = dri2_buffer(bPriv);
> +
> + pipe_resource_reference(&buffer->resource, NULL);
> + FREE(buffer);
> +}
> +
> +/*
> + * Backend functions for st_framebuffer interface.
> */
> +
> static void
> -dri2_drawable_process_buffers(struct dri_context *ctx,
> - struct dri_drawable *drawable,
> - __DRIbuffer *buffers, unsigned buffer_count,
> - const enum st_attachment_type *atts,
> - unsigned att_count)
> +dri2_allocate_textures(struct dri_context *ctx,
> + struct dri_drawable *drawable,
> + const enum st_attachment_type *statts,
> + unsigned statts_count)
> {
> - struct dri_screen *screen = dri_screen(drawable->sPriv);
> + __DRIscreen *sPriv = drawable->sPriv;
> __DRIdrawable *dri_drawable = drawable->dPriv;
> + struct dri_screen *screen = dri_screen(sPriv);
> struct pipe_resource templ;
> - struct winsys_handle whandle;
> boolean alloc_depthstencil = FALSE;
> unsigned i, j, bind;
> + const __DRIimageLoaderExtension *image = sPriv->image.loader;
> + /* Image specific variables */
> + struct __DRIimageList images;
> + /* Dri2 specific variables */
> + __DRIbuffer *buffers;
> + struct winsys_handle whandle;
> + unsigned num_buffers = statts_count;
>
> - if (drawable->old_num == buffer_count &&
> - drawable->old_w == dri_drawable->w &&
> - drawable->old_h == dri_drawable->h &&
> - memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * buffer_count) == 0)
> - return;
> + /* First get the buffers from the loader */
> + if (image) {
> + if (!dri_image_drawable_get_buffers(drawable, &images,
> + statts, statts_count))
> + return;
> + }
> + else {
> + buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
> + if (!buffers || (drawable->old_num == num_buffers &&
> + drawable->old_w == dri_drawable->w &&
> + drawable->old_h == dri_drawable->h &&
> + memcmp(drawable->old, buffers,
> + sizeof(__DRIbuffer) * num_buffers) == 0))
> + return;
> + }
> +
> + /* Second clean useless resources*/
>
> /* See if we need a depth-stencil buffer. */
> - for (i = 0; i < att_count; i++) {
> - if (atts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
> + for (i = 0; i < statts_count; i++) {
> + if (statts[i] == ST_ATTACHMENT_DEPTH_STENCIL) {
> alloc_depthstencil = TRUE;
> break;
> }
> @@ -255,8 +415,8 @@ dri2_drawable_process_buffers(struct dri_context *ctx,
>
> /* Don't delete MSAA resources for the attachments which are enabled,
> * we can reuse them. */
> - for (j = 0; j < att_count; j++) {
> - if (i == atts[j]) {
> + for (j = 0; j < statts_count; j++) {
> + if (i == statts[j]) {
> del = FALSE;
> break;
> }
> @@ -268,80 +428,115 @@ dri2_drawable_process_buffers(struct dri_context *ctx,
> }
> }
>
> + /* Third use the buffers retrieved to fill the drawable info */
> +
> memset(&templ, 0, sizeof(templ));
> templ.target = screen->target;
> templ.last_level = 0;
> - templ.width0 = dri_drawable->w;
> - templ.height0 = dri_drawable->h;
> templ.depth0 = 1;
> templ.array_size = 1;
>
> - memset(&whandle, 0, sizeof(whandle));
> + if (image) {
> + if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) {
> + struct pipe_resource **buf =
> + &drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
> + struct pipe_resource *texture = images.front->texture;
>
> - /* Process DRI-provided buffers and get pipe_resources. */
> - for (i = 0; i < buffer_count; i++) {
> - __DRIbuffer *buf = &buffers[i];
> - enum st_attachment_type statt;
> - enum pipe_format format;
> + dri_drawable->w = texture->width0;
> + dri_drawable->h = texture->height0;
>
> - switch (buf->attachment) {
> - case __DRI_BUFFER_FRONT_LEFT:
> - if (!screen->auto_fake_front) {
> - continue; /* invalid attachment */
> - }
> - /* fallthrough */
> - case __DRI_BUFFER_FAKE_FRONT_LEFT:
> - statt = ST_ATTACHMENT_FRONT_LEFT;
> - break;
> - case __DRI_BUFFER_BACK_LEFT:
> - statt = ST_ATTACHMENT_BACK_LEFT;
> - break;
> - default:
> - continue; /* invalid attachment */
> + pipe_resource_reference(buf, texture);
> }
>
> - dri_drawable_get_format(drawable, statt, &format, &bind);
> - if (format == PIPE_FORMAT_NONE)
> - continue;
> + if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) {
> + struct pipe_resource **buf =
> + &drawable->textures[ST_ATTACHMENT_BACK_LEFT];
> + struct pipe_resource *texture = images.back->texture;
>
> - templ.format = format;
> - templ.bind = bind;
> - whandle.type = DRM_API_HANDLE_TYPE_SHARED;
> - whandle.handle = buf->name;
> - whandle.stride = buf->pitch;
> + dri_drawable->w = texture->width0;
> + dri_drawable->h = texture->height0;
> +
> + pipe_resource_reference(buf, texture);
> + }
> +
> + /* Note: if there is both a back and a front buffer,
> + * then they have the same size.
> + */
> + templ.width0 = dri_drawable->w;
> + templ.height0 = dri_drawable->h;
> + }
> + else {
> + memset(&whandle, 0, sizeof(whandle));
> +
> + /* Process DRI-provided buffers and get pipe_resources. */
> + for (i = 0; i < num_buffers; i++) {
> + __DRIbuffer *buf = &buffers[i];
> + enum st_attachment_type statt;
> + enum pipe_format format;
> +
> + switch (buf->attachment) {
> + case __DRI_BUFFER_FRONT_LEFT:
> + if (!screen->auto_fake_front) {
> + continue; /* invalid attachment */
> + }
> + /* fallthrough */
> + case __DRI_BUFFER_FAKE_FRONT_LEFT:
> + statt = ST_ATTACHMENT_FRONT_LEFT;
> + break;
> + case __DRI_BUFFER_BACK_LEFT:
> + statt = ST_ATTACHMENT_BACK_LEFT;
> + break;
> + default:
> + continue; /* invalid attachment */
> + }
> +
> + dri_drawable_get_format(drawable, statt, &format, &bind);
> + if (format == PIPE_FORMAT_NONE)
> + continue;
>
> - drawable->textures[statt] =
> - screen->base.screen->resource_from_handle(screen->base.screen,
> - &templ, &whandle);
> - assert(drawable->textures[statt]);
> + /* dri2_drawable_get_buffers has already filled dri_drawable->w
> + * and dri_drawable->h */
> + templ.width0 = dri_drawable->w;
> + templ.height0 = dri_drawable->h;
> + templ.format = format;
> + templ.bind = bind;
> + whandle.type = DRM_API_HANDLE_TYPE_SHARED;
> + whandle.handle = buf->name;
> + whandle.stride = buf->pitch;
> +
> + drawable->textures[statt] =
> + screen->base.screen->resource_from_handle(screen->base.screen,
> + &templ, &whandle);
> + assert(drawable->textures[statt]);
> + }
> }
>
> /* Allocate private MSAA colorbuffers. */
> if (drawable->stvis.samples > 1) {
> - for (i = 0; i < att_count; i++) {
> - enum st_attachment_type att = atts[i];
> + for (i = 0; i < statts_count; i++) {
> + enum st_attachment_type statt = statts[i];
>
> - if (att == ST_ATTACHMENT_DEPTH_STENCIL)
> + if (statt == ST_ATTACHMENT_DEPTH_STENCIL)
> continue;
>
> - if (drawable->textures[att]) {
> - templ.format = drawable->textures[att]->format;
> - templ.bind = drawable->textures[att]->bind;
> + if (drawable->textures[statt]) {
> + templ.format = drawable->textures[statt]->format;
> + templ.bind = drawable->textures[statt]->bind;
> templ.nr_samples = drawable->stvis.samples;
>
> /* Try to reuse the resource.
> * (the other resource parameters should be constant)
> */
> - if (!drawable->msaa_textures[att] ||
> - drawable->msaa_textures[att]->width0 != templ.width0 ||
> - drawable->msaa_textures[att]->height0 != templ.height0) {
> + if (!drawable->msaa_textures[statt] ||
> + drawable->msaa_textures[statt]->width0 != templ.width0 ||
> + drawable->msaa_textures[statt]->height0 != templ.height0) {
> /* Allocate a new one. */
> - pipe_resource_reference(&drawable->msaa_textures[att], NULL);
> + pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
>
> - drawable->msaa_textures[att] =
> + drawable->msaa_textures[statt] =
> screen->base.screen->resource_create(screen->base.screen,
> &templ);
> - assert(drawable->msaa_textures[att]);
> + assert(drawable->msaa_textures[statt]);
>
> /* If there are any MSAA resources, we should initialize them
> * such that they contain the same data as the single-sample
> @@ -354,24 +549,24 @@ dri2_drawable_process_buffers(struct dri_context *ctx,
> *
> */
> dri_pipe_blit(ctx->st->pipe,
> - drawable->msaa_textures[att],
> - drawable->textures[att]);
> + drawable->msaa_textures[statt],
> + drawable->textures[statt]);
> }
> }
> else {
> - pipe_resource_reference(&drawable->msaa_textures[att], NULL);
> + pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
> }
> }
> }
>
> /* Allocate a private depth-stencil buffer. */
> if (alloc_depthstencil) {
> - enum st_attachment_type att = ST_ATTACHMENT_DEPTH_STENCIL;
> + enum st_attachment_type statt = ST_ATTACHMENT_DEPTH_STENCIL;
> struct pipe_resource **zsbuf;
> enum pipe_format format;
> unsigned bind;
>
> - dri_drawable_get_format(drawable, att, &format, &bind);
> + dri_drawable_get_format(drawable, statt, &format, &bind);
>
> if (format) {
> templ.format = format;
> @@ -379,11 +574,11 @@ dri2_drawable_process_buffers(struct dri_context *ctx,
>
> if (drawable->stvis.samples > 1) {
> templ.nr_samples = drawable->stvis.samples;
> - zsbuf = &drawable->msaa_textures[att];
> + zsbuf = &drawable->msaa_textures[statt];
> }
> else {
> templ.nr_samples = 0;
> - zsbuf = &drawable->textures[att];
> + zsbuf = &drawable->textures[statt];
> }
>
> /* Try to reuse the resource.
> @@ -400,121 +595,24 @@ dri2_drawable_process_buffers(struct dri_context *ctx,
> }
> }
> else {
> - pipe_resource_reference(&drawable->msaa_textures[att], NULL);
> - pipe_resource_reference(&drawable->textures[att], NULL);
> + pipe_resource_reference(&drawable->msaa_textures[statt], NULL);
> + pipe_resource_reference(&drawable->textures[statt], NULL);
> }
> }
>
> - drawable->old_num = buffer_count;
> - drawable->old_w = dri_drawable->w;
> - drawable->old_h = dri_drawable->h;
> - memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * buffer_count);
> -}
> -
> -static __DRIbuffer *
> -dri2_allocate_buffer(__DRIscreen *sPriv,
> - unsigned attachment, unsigned format,
> - int width, int height)
> -{
> - struct dri_screen *screen = dri_screen(sPriv);
> - struct dri2_buffer *buffer;
> - struct pipe_resource templ;
> - enum pipe_format pf;
> - unsigned bind = 0;
> - struct winsys_handle whandle;
> -
> - switch (attachment) {
> - case __DRI_BUFFER_FRONT_LEFT:
> - case __DRI_BUFFER_FAKE_FRONT_LEFT:
> - bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
> - break;
> - case __DRI_BUFFER_BACK_LEFT:
> - bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
> - break;
> - case __DRI_BUFFER_DEPTH:
> - case __DRI_BUFFER_DEPTH_STENCIL:
> - case __DRI_BUFFER_STENCIL:
> - bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
> - break;
> - }
> -
> - /* because we get the handle and stride */
> - bind |= PIPE_BIND_SHARED;
> -
> - switch (format) {
> - case 32:
> - pf = PIPE_FORMAT_B8G8R8A8_UNORM;
> - break;
> - case 24:
> - pf = PIPE_FORMAT_B8G8R8X8_UNORM;
> - break;
> - case 16:
> - pf = PIPE_FORMAT_Z16_UNORM;
> - break;
> - default:
> - return NULL;
> - }
> -
> - buffer = CALLOC_STRUCT(dri2_buffer);
> - if (!buffer)
> - return NULL;
> -
> - memset(&templ, 0, sizeof(templ));
> - templ.bind = bind;
> - templ.format = pf;
> - templ.target = PIPE_TEXTURE_2D;
> - templ.last_level = 0;
> - templ.width0 = width;
> - templ.height0 = height;
> - templ.depth0 = 1;
> - templ.array_size = 1;
> -
> - buffer->resource =
> - screen->base.screen->resource_create(screen->base.screen, &templ);
> - if (!buffer->resource) {
> - FREE(buffer);
> - return NULL;
> + /* For DRI2, we may get the same buffers again from the server.
> + * To prevent useless imports of gem names, drawable->old* is used
> + * to bypass the import if we get the same buffers. This doesn't apply
> + * to DRI3/Wayland, users of image.loader, since the buffer is managed
> + * by the client (no import), and the back buffer is going to change
> + * at every redraw.
> + */
> + if (!image) {
> + drawable->old_num = num_buffers;
> + drawable->old_w = dri_drawable->w;
> + drawable->old_h = dri_drawable->h;
> + memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * num_buffers);
> }
> -
> - memset(&whandle, 0, sizeof(whandle));
> - whandle.type = DRM_API_HANDLE_TYPE_SHARED;
> - screen->base.screen->resource_get_handle(screen->base.screen,
> - buffer->resource, &whandle);
> -
> - buffer->base.attachment = attachment;
> - buffer->base.name = whandle.handle;
> - buffer->base.cpp = util_format_get_blocksize(pf);
> - buffer->base.pitch = whandle.stride;
> -
> - return &buffer->base;
> -}
> -
> -static void
> -dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
> -{
> - struct dri2_buffer *buffer = dri2_buffer(bPriv);
> -
> - pipe_resource_reference(&buffer->resource, NULL);
> - FREE(buffer);
> -}
> -
> -/*
> - * Backend functions for st_framebuffer interface.
> - */
> -
> -static void
> -dri2_allocate_textures(struct dri_context *ctx,
> - struct dri_drawable *drawable,
> - const enum st_attachment_type *statts,
> - unsigned statts_count)
> -{
> - __DRIbuffer *buffers;
> - unsigned num_buffers = statts_count;
> -
> - buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
> - if (buffers)
> - dri2_drawable_process_buffers(ctx, drawable, buffers, num_buffers,
> - statts, statts_count);
> }
>
> static void
> @@ -523,6 +621,7 @@ dri2_flush_frontbuffer(struct dri_context *ctx,
> enum st_attachment_type statt)
> {
> __DRIdrawable *dri_drawable = drawable->dPriv;
> + const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
> const __DRIdri2LoaderExtension *loader = drawable->sPriv->dri2.loader;
> struct pipe_context *pipe = ctx->st->pipe;
>
> @@ -542,7 +641,10 @@ dri2_flush_frontbuffer(struct dri_context *ctx,
>
> pipe->flush(pipe, NULL, 0);
>
> - if (loader->flushFrontBuffer) {
> + if (image) {
> + image->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
> + }
> + else if (loader->flushFrontBuffer) {
> loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
> }
> }
> @@ -1171,6 +1273,7 @@ const struct __DriverAPIRec driDriverAPI = {
> /* This is the table of extensions that the loader will dlsym() for. */
> PUBLIC const __DRIextension *__driDriverExtensions[] = {
> &driCoreExtension.base,
> + &driImageDriverExtension.base,
> &driDRI2Extension.base,
> &gallium_config_options.base,
> NULL
> --
> 1.9.1
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list