On Wed, Jun 18, 2014 at 11:27 PM, Axel Davy <axel.d...@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.d...@ens.fr> > Reviewed-by: Marek Olšák<marek.ol...@amd.com> > > Previous patches were: > Signed-off-by: Ben Skeggs <bske...@redhat.com> > Signed-off-by: Keith Packard <kei...@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);
I believe the expectation is that before you create resources with a certain format/bind combo, you need to check first with ->is_format_supported. For example pre-NVA0 nv50 cards don't support Z16. > + 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@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev