[Mesa-dev] [PATCH] llvmpipe: support rendering to buffer render targets.

Roland Scheidegger sroland at vmware.com
Wed Feb 27 04:52:39 PST 2013


Am 27.02.2013 12:05, schrieb Christoph Bumiller:
> On 27.02.2013 10:44, Jose Fonseca wrote:
>> ----- Original Message -----
>>> What is this good for? Is it for UAVs? (unordered access views)
>> No, it is just a standard D3D10 feature: http://msdn.microsoft.com/en-gb/library/windows/desktop/bb204897.aspx
>>
>> Not sure if there's a particular use case for it (e.g, maybe DirectCompute uses this extensively), or just a matter of symmetry in the API (ie., if one can sample from buffer textures, then why not render into them?)
> I can think of rendering to vertex buffers. It's just annoying that
> there are no alignment restrictions on the range that is bound (worst
> case you have to render to a temporary buffer and copy stuff around);
> but at least it has to be <= 8192 bytes (or elements, not sure) in D3D10.
It is 8192 elements (so same as 1d texture width really).
There is some minimal alignment restriction, the range needs to be
aligned to element width (this follows from specifying the start in
terms of elements directly). Well at least if I understand everything
correctly it doesn't work so well in testing yet :-).
I thought hw would be able to do this without hacks but can't tell for
sure. Note that d3d10 prevents you from having a depth buffer bound at
the same time if you use that feature so it's quite limited (though I
think this follows from the requirement that depth/stencil buffers need
same resource type as rendertargets, and you can't bind buffers as
depth/stencil).
All OpenGL extensions I've seen which allow you to write to some kind of
buffer require some special means to do that, and don't allow buffers to
be bound as ordinary render targets. Might be a mess to specify wrt
framebuffer (completeness requirements etc.) and due to
non-orthogonality (no depth buffer).

Roland



> 
>>> For UAVs, I think there is ARB_shader_storage_buffer_object and
>>> pipe_context::set_shader_resources.
>> Yeah, D3D11 UAVs are also supposed to be bound separately in the pipeline.
>>
>> Jose
>>
>>> Marek
>>>
>>> On Wed, Feb 27, 2013 at 3:18 AM,  <sroland at vmware.com> wrote:
>>>> From: Roland Scheidegger <sroland at vmware.com>
>>>>
>>>> Unfortunately not usable from OpenGL, and no cap bit.
>>>> Pretty similar to a 1d texture, though allows specifying a start element.
>>>> The util code for handling clears also needs adjustments (and fix
>>>> a bug causing crashes for handling pure integer formats there too).
>>>> ---
>>>>  src/gallium/auxiliary/util/u_surface.c      |   55
>>>>  +++++++++++++++++++++++----
>>>>  src/gallium/drivers/llvmpipe/lp_rast.c      |   25 ++----------
>>>>  src/gallium/drivers/llvmpipe/lp_rast_priv.h |    4 +-
>>>>  src/gallium/drivers/llvmpipe/lp_scene.c     |   35 +++++++++++------
>>>>  src/gallium/drivers/llvmpipe/lp_texture.c   |   44 +++++++++++++++------
>>>>  5 files changed, 108 insertions(+), 55 deletions(-)
>>>>
>>>> diff --git a/src/gallium/auxiliary/util/u_surface.c
>>>> b/src/gallium/auxiliary/util/u_surface.c
>>>> index b948b46..fba0798 100644
>>>> --- a/src/gallium/auxiliary/util/u_surface.c
>>>> +++ b/src/gallium/auxiliary/util/u_surface.c
>>>> @@ -323,20 +323,59 @@ util_clear_render_target(struct pipe_context *pipe,
>>>>     if (!dst->texture)
>>>>        return;
>>>>     /* XXX: should handle multiple layers */
>>>> -   dst_map = pipe_transfer_map(pipe,
>>>> -                               dst->texture,
>>>> -                               dst->u.tex.level,
>>>> -                               dst->u.tex.first_layer,
>>>> -                               PIPE_TRANSFER_WRITE,
>>>> -                               dstx, dsty, width, height, &dst_trans);
>>>> +
>>>> +   if (dst->texture->target == PIPE_BUFFER) {
>>>> +      /*
>>>> +       * The fill naturally works on the surface format, however
>>>> +       * the transfer uses resource format which is just bytes for
>>>> buffers.
>>>> +       */
>>>> +      unsigned dx, w;
>>>> +      unsigned pixstride = util_format_get_blocksize(dst->format);
>>>> +      dx = dstx * pixstride;
>>>> +      w = width * pixstride;
>>>> +      dst_map = pipe_transfer_map(pipe,
>>>> +                                  dst->texture,
>>>> +                                  0, 0,
>>>> +                                  PIPE_TRANSFER_WRITE,
>>>> +                                  dx, 0, w, 1,
>>>> +                                  &dst_trans);
>>>> +      dst_map = (uint8_t *)dst_map + dst->u.buf.first_element * pixstride;
>>>> +   }
>>>> +   else {
>>>> +      /* XXX: should handle multiple layers */
>>>> +      dst_map = pipe_transfer_map(pipe,
>>>> +                                  dst->texture,
>>>> +                                  dst->u.tex.level,
>>>> +                                  dst->u.tex.first_layer,
>>>> +                                  PIPE_TRANSFER_WRITE,
>>>> +                                  dstx, dsty, width, height, &dst_trans);
>>>> +
>>>> +   }
>>>>
>>>>     assert(dst_map);
>>>>
>>>>     if (dst_map) {
>>>> +      enum pipe_format format = dst->format;
>>>>        assert(dst_trans->stride > 0);
>>>>
>>>> -      util_pack_color(color->f, dst->texture->format, &uc);
>>>> -      util_fill_rect(dst_map, dst->texture->format,
>>>> +      if (util_format_is_pure_integer(format)) {
>>>> +         /*
>>>> +          * We expect int/uint clear values here, though some APIs
>>>> +          * might disagree (but in any case util_pack_color()
>>>> +          * couldn't handle it)...
>>>> +          */
>>>> +         if (util_format_is_pure_sint(format)) {
>>>> +            util_format_write_4i(format, color->i, 0, &uc, 0, 0, 0, 1, 1);
>>>> +         }
>>>> +         else {
>>>> +            assert(util_format_is_pure_uint(format));
>>>> +            util_format_write_4ui(format, color->ui, 0, &uc, 0, 0, 0, 1,
>>>> 1);
>>>> +         }
>>>> +      }
>>>> +      else {
>>>> +         util_pack_color(color->f, dst->format, &uc);
>>>> +      }
>>>> +      util_fill_rect(dst_map, dst->format,
>>>>                       dst_trans->stride,
>>>>                       0, 0, width, height, &uc);
>>>>
>>>> diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c
>>>> b/src/gallium/drivers/llvmpipe/lp_rast.c
>>>> index b5e5da6..6183f41 100644
>>>> --- a/src/gallium/drivers/llvmpipe/lp_rast.c
>>>> +++ b/src/gallium/drivers/llvmpipe/lp_rast.c
>>>> @@ -165,32 +165,13 @@ lp_rast_clear_color(struct lp_rasterizer_task *task,
>>>>
>>>>           for (i = 0; i < scene->fb.nr_cbufs; i++) {
>>>>              enum pipe_format format = scene->fb.cbufs[i]->format;
>>>> -            /*
>>>> -             * XXX the format_write_4i/ui functions do clamping to max
>>>> value
>>>> -             * and I'm not sure that's actually right - spec doesn't seem
>>>> to
>>>> -             * say much about that topic. If it is should probably adjust
>>>> the
>>>> -             * border color handling to do the same. If not and chopping
>>>> off
>>>> -             * bits is the way to go, the write_4i and write_4ui functions
>>>> -             * would be identical.
>>>> -             */
>>>> -            if (util_format_is_pure_sint(format)) {
>>>> -               int rgba[4];
>>>> -               rgba[0] = arg.clear_color.i[0];
>>>> -               rgba[1] = arg.clear_color.i[1];
>>>> -               rgba[2] = arg.clear_color.i[2];
>>>> -               rgba[3] = arg.clear_color.i[3];
>>>>
>>>> -               util_format_write_4i(format, rgba, 0, &uc, 0, 0, 0, 1, 1);
>>>> +            if (util_format_is_pure_sint(format)) {
>>>> +               util_format_write_4i(format, arg.clear_color.i, 0, &uc, 0,
>>>> 0, 0, 1, 1);
>>>>              }
>>>>              else {
>>>> -               unsigned rgba[4];
>>>> -               rgba[0] = arg.clear_color.ui[0];
>>>> -               rgba[1] = arg.clear_color.ui[1];
>>>> -               rgba[2] = arg.clear_color.ui[2];
>>>> -               rgba[3] = arg.clear_color.ui[3];
>>>> -
>>>>                 assert(util_format_is_pure_uint(format));
>>>> -               util_format_write_4ui(format, rgba, 0, &uc, 0, 0, 0, 1, 1);
>>>> +               util_format_write_4ui(format, arg.clear_color.ui, 0, &uc,
>>>> 0, 0, 0, 1, 1);
>>>>              }
>>>>
>>>>              util_fill_rect(scene->cbufs[i].map,
>>>> diff --git a/src/gallium/drivers/llvmpipe/lp_rast_priv.h
>>>> b/src/gallium/drivers/llvmpipe/lp_rast_priv.h
>>>> index 5db8fcd..c0f41f6 100644
>>>> --- a/src/gallium/drivers/llvmpipe/lp_rast_priv.h
>>>> +++ b/src/gallium/drivers/llvmpipe/lp_rast_priv.h
>>>> @@ -196,7 +196,7 @@ lp_rast_get_unswizzled_color_tile_pointer(struct
>>>> lp_rasterizer_task *task,
>>>>        struct pipe_surface *cbuf = scene->fb.cbufs[buf];
>>>>        assert(cbuf);
>>>>
>>>> -      format_bytes = util_format_description(cbuf->format)->block.bits /
>>>> 8;
>>>> +      format_bytes = util_format_get_blocksize(cbuf->format);
>>>>        task->color_tiles[buf] = scene->cbufs[buf].map +
>>>>        scene->cbufs[buf].stride * task->y + format_bytes * task->x;
>>>>     }
>>>>
>>>> @@ -221,7 +221,7 @@ lp_rast_get_unswizzled_color_block_pointer(struct
>>>> lp_rasterizer_task *task,
>>>>     assert((y % TILE_VECTOR_HEIGHT) == 0);
>>>>     assert(buf < task->scene->fb.nr_cbufs);
>>>>
>>>> -   format_bytes =
>>>> util_format_description(task->scene->fb.cbufs[buf]->format)->block.bits /
>>>> 8;
>>>> +   format_bytes =
>>>> util_format_get_blocksize(task->scene->fb.cbufs[buf]->format);
>>>>
>>>>     color = lp_rast_get_unswizzled_color_tile_pointer(task, buf,
>>>>     LP_TEX_USAGE_READ_WRITE);
>>>>     assert(color);
>>>> diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c
>>>> b/src/gallium/drivers/llvmpipe/lp_scene.c
>>>> index 328c0f7..fec2f74 100644
>>>> --- a/src/gallium/drivers/llvmpipe/lp_scene.c
>>>> +++ b/src/gallium/drivers/llvmpipe/lp_scene.c
>>>> @@ -141,15 +141,24 @@ lp_scene_begin_rasterization(struct lp_scene *scene)
>>>>
>>>>     for (i = 0; i < scene->fb.nr_cbufs; i++) {
>>>>        struct pipe_surface *cbuf = scene->fb.cbufs[i];
>>>> -      assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer);
>>>> -      scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
>>>> -
>>>> cbuf->u.tex.level);
>>>> -
>>>> -      scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
>>>> -                                                  cbuf->u.tex.level,
>>>> -                                                  cbuf->u.tex.first_layer,
>>>> -                                                  LP_TEX_USAGE_READ_WRITE,
>>>> -                                                  LP_TEX_LAYOUT_LINEAR);
>>>> +      if (llvmpipe_resource_is_texture(cbuf->texture)) {
>>>> +         assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer);
>>>> +         scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
>>>> +
>>>> cbuf->u.tex.level);
>>>> +
>>>> +         scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
>>>> +                                                     cbuf->u.tex.level,
>>>> +
>>>> cbuf->u.tex.first_layer,
>>>> +
>>>> LP_TEX_USAGE_READ_WRITE,
>>>> +
>>>> LP_TEX_LAYOUT_LINEAR);
>>>> +      }
>>>> +      else {
>>>> +         struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture);
>>>> +         unsigned pixstride = util_format_get_blocksize(cbuf->format);
>>>> +         scene->cbufs[i].stride = cbuf->texture->width0;
>>>> +         scene->cbufs[i].map = lpr->data;
>>>> +         scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride;
>>>> +      }
>>>>     }
>>>>
>>>>     if (fb->zsbuf) {
>>>> @@ -182,9 +191,11 @@ lp_scene_end_rasterization(struct lp_scene *scene )
>>>>     for (i = 0; i < scene->fb.nr_cbufs; i++) {
>>>>        if (scene->cbufs[i].map) {
>>>>           struct pipe_surface *cbuf = scene->fb.cbufs[i];
>>>> -         llvmpipe_resource_unmap(cbuf->texture,
>>>> -                                 cbuf->u.tex.level,
>>>> -                                 cbuf->u.tex.first_layer);
>>>> +         if (llvmpipe_resource_is_texture(cbuf->texture)) {
>>>> +            llvmpipe_resource_unmap(cbuf->texture,
>>>> +                                    cbuf->u.tex.level,
>>>> +                                    cbuf->u.tex.first_layer);
>>>> +         }
>>>>           scene->cbufs[i].map = NULL;
>>>>        }
>>>>     }
>>>> diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c
>>>> b/src/gallium/drivers/llvmpipe/lp_texture.c
>>>> index f923292..7387166 100644
>>>> --- a/src/gallium/drivers/llvmpipe/lp_texture.c
>>>> +++ b/src/gallium/drivers/llvmpipe/lp_texture.c
>>>> @@ -297,6 +297,12 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
>>>>        assert(templat->depth0 == 1);
>>>>        assert(templat->last_level == 0);
>>>>        lpr->data = align_malloc(bytes, 16);
>>>> +      /*
>>>> +       * buffers don't really have stride but it's probably safer
>>>> +       * (for code doing same calculations for buffers and textures)
>>>> +       * to put something sane in there.
>>>> +       */
>>>> +      lpr->row_stride[0] = bytes;
>>>>        if (!lpr->data)
>>>>           goto fail;
>>>>        memset(lpr->data, 0, bytes);
>>>> @@ -578,12 +584,23 @@ llvmpipe_create_surface(struct pipe_context *pipe,
>>>>        pipe_resource_reference(&ps->texture, pt);
>>>>        ps->context = pipe;
>>>>        ps->format = surf_tmpl->format;
>>>> -      ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
>>>> -      ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
>>>> -
>>>> -      ps->u.tex.level = surf_tmpl->u.tex.level;
>>>> -      ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
>>>> -      ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
>>>> +      if (llvmpipe_resource_is_texture(pt)) {
>>>> +         assert(surf_tmpl->u.tex.level <= pt->last_level);
>>>> +         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
>>>> +         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
>>>> +         ps->u.tex.level = surf_tmpl->u.tex.level;
>>>> +         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
>>>> +         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
>>>> +      }
>>>> +      else {
>>>> +         const enum pipe_format format = surf_tmpl->format;
>>>> +         ps->width = pt->width0 / util_format_get_blocksize(format);
>>>> +         ps->height = pt->height0;
>>>> +         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
>>>> +         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
>>>> +         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
>>>> +         assert(ps->u.buf.last_element < ps->width);
>>>> +      }
>>>>     }
>>>>     return ps;
>>>>  }
>>>> @@ -1342,12 +1359,17 @@ llvmpipe_resource_size(const struct pipe_resource
>>>> *resource)
>>>>     const struct llvmpipe_resource *lpr =
>>>>     llvmpipe_resource_const(resource);
>>>>     unsigned lvl, size = 0;
>>>>
>>>> -   for (lvl = 0; lvl <= lpr->base.last_level; lvl++) {
>>>> -      if (lpr->linear_img.data)
>>>> -         size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_LINEAR);
>>>> +   if (llvmpipe_resource_is_texture(resource)) {
>>>> +      for (lvl = 0; lvl <= lpr->base.last_level; lvl++) {
>>>> +         if (lpr->linear_img.data)
>>>> +            size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_LINEAR);
>>>>
>>>> -      if (lpr->tiled_img.data)
>>>> -         size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_TILED);
>>>> +         if (lpr->tiled_img.data)
>>>> +            size += tex_image_size(lpr, lvl, LP_TEX_LAYOUT_TILED);
>>>> +      }
>>>> +   }
>>>> +   else {
>>>> +      size = resource->width0;
>>>>     }
>>>>
>>>>     return size;
>>>> --
>>>> 1.7.9.5
>>>>
>>>> _______________________________________________
>>>> mesa-dev mailing list
>>>> mesa-dev at lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> 
> _______________________________________________
> 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