[Mesa-dev] [PATCH 6/7] i965/gen7: Add support for transform feedback.

Paul Berry stereotype441 at gmail.com
Thu Dec 22 19:22:16 PST 2011


On 22 December 2011 16:54, Eric Anholt <eric at anholt.net> wrote:

> Fixes almost all of the transform feedback piglit tests.  Remaining
> are a few tests related to tesselation for
> quads/trifans/tristrips/polygons with flat shading.
> ---
>  src/mesa/drivers/dri/i965/gen7_sol_state.c |  199
> ++++++++++++++++++++++++++-
>  1 files changed, 191 insertions(+), 8 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/i965/gen7_sol_state.c
> b/src/mesa/drivers/dri/i965/gen7_sol_state.c
> index 650f625..a5e28b6 100644
> --- a/src/mesa/drivers/dri/i965/gen7_sol_state.c
> +++ b/src/mesa/drivers/dri/i965/gen7_sol_state.c
> @@ -32,31 +32,214 @@
>  #include "brw_state.h"
>  #include "brw_defines.h"
>  #include "intel_batchbuffer.h"
> +#include "intel_buffer_objects.h"
>
>  static void
> -upload_sol_state(struct brw_context *brw)
> +upload_3dstate_so_buffers(struct brw_context *brw)
> +{
> +   struct intel_context *intel = &brw->intel;
> +   struct gl_context *ctx = &intel->ctx;
> +   /* BRW_NEW_VERTEX_PROGRAM */
> +   const struct gl_shader_program *vs_prog =
> +      ctx->Shader.CurrentVertexProgram;
> +   const struct gl_transform_feedback_info *linked_xfb_info =
> +      &vs_prog->LinkedTransformFeedback;
> +   struct gl_transform_feedback_object *xfb_obj =
> +      ctx->TransformFeedback.CurrentObject;
>

Can we have a "/* NEW_TRANSFORM_FEEDBACK */" comment here?


> +   int i;
> +
> +   /* Set up the up to 4 output buffers.  These are the ranges defined in
> the
> +    * gl_transform_feedback_object.
> +    */
> +   for (i = 0; i < 4; i++) {
> +      struct gl_buffer_object *bufferobj = xfb_obj->Buffers[i];
> +      drm_intel_bo *bo;
> +      uint32_t start, end;
> +
> +      if (!xfb_obj->Buffers[i]) {
> +        /* The pitch of 0 in this command indicates that the buffer is
> +         * unbound and won't be written to.
> +         */
> +        BEGIN_BATCH(4);
> +        OUT_BATCH(_3DSTATE_SO_BUFFER << 16 | (4 - 2));
> +        OUT_BATCH((i << SO_BUFFER_INDEX_SHIFT));
> +        OUT_BATCH(0);
> +        OUT_BATCH(0);
> +        ADVANCE_BATCH();
> +
> +        continue;
> +      }
> +
> +      bo = intel_buffer_object(bufferobj)->buffer;
> +
> +      start = xfb_obj->Offset[i];
> +      assert(start % 4 == 0);
> +      end = ALIGN(start + xfb_obj->Size[i], 4);
> +      assert(end <= bo->size);
> +
> +      BEGIN_BATCH(4);
> +      OUT_BATCH(_3DSTATE_SO_BUFFER << 16 | (4 - 2));
> +      OUT_BATCH((i << SO_BUFFER_INDEX_SHIFT) |
> +               ((linked_xfb_info->BufferStride[i] * 4) <<
> +                SO_BUFFER_PITCH_SHIFT));
>

It looks like we're not setting "SO Buffer Object Control State".  Is that
ok?  I'm not too familiar with memory object control states so I'm not
sure, but it seemed to me that it might be sensible to mark the stream
output as L3 cacheable.


> +      OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
> start);
> +      OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, end);
> +      ADVANCE_BATCH();
> +   }
> +}
> +
> +/**
> + * Outputs the 3DSTATE_SO_DECL_LIST command.
> + *
> + * The data output is a series of 64-bit entries containing a SO_DECL per
> + * stream.  We only have one stream of rendering coming out of the GS
> unit, so
> + * we only emit stream 0 (low 16 bits) SO_DECLs.
> + */
> +static void
> +upload_3dstate_so_decl_list(struct brw_context *brw,
> +                           struct brw_vue_map *vue_map)
> +{
> +   struct intel_context *intel = &brw->intel;
> +   struct gl_context *ctx = &intel->ctx;
> +   /* BRW_NEW_VERTEX_PROGRAM */
> +   const struct gl_shader_program *vs_prog =
> +      ctx->Shader.CurrentVertexProgram;
> +   /* NEW_TRANSFORM_FEEDBACK */
> +   const struct gl_transform_feedback_info *linked_xfb_info =
> +      &vs_prog->LinkedTransformFeedback;
> +   int i;
> +   uint16_t so_decl[128];
>

Can we add an assertion to verify that there is no danger of overflowing
this array?  I think STATIC_ASSERT(ARRAY_SIZE(so_decl) >=
MAX_PROGRAM_OUTPUTS) ought to do the trick.


> +   int buffer_mask = 0;
> +   int next_offset[4] = {0, 0, 0, 0};
>
+
> +   /* Construct the list of SO_DECLs to be emitted.  The formatting of the
> +    * command is feels strange -- each dword pair contains a SO_DECL per
> stream.
> +    */
> +   for (i = 0; i < linked_xfb_info->NumOutputs; i++) {
> +      int buffer = linked_xfb_info->Outputs[i].OutputBuffer;
> +      uint16_t decl = 0;
> +      int vert_result = linked_xfb_info->Outputs[i].OutputRegister;
> +
> +      buffer_mask |= 1 << buffer;
> +
> +      decl |= buffer << SO_DECL_OUTPUT_BUFFER_SLOT_SHIFT;
> +      decl |= vue_map->vert_result_to_slot[vert_result] <<
> +        SO_DECL_REGISTER_INDEX_SHIFT;
> +      decl |= ((1 << linked_xfb_info->Outputs[i].NumComponents) - 1) <<
> +        SO_DECL_COMPONENT_MASK_SHIFT;
> +
> +      /* FINISHME */
> +      assert(linked_xfb_info->Outputs[i].DstOffset ==
> next_offset[buffer]);
>

FYI, this assertion should hold true until we implement
ARB_transfrom_feedback3 (which allows holes in the transform feedback
structure).  I think Marek has some plans to implement that for Gallium
(not sure of his timeframe though), so we may want to keep an eye out.


> +
> +      next_offset[buffer] += linked_xfb_info->Outputs[i].NumComponents;
> +
> +      so_decl[i] = decl;
> +   }
> +
> +   BEGIN_BATCH(linked_xfb_info->NumOutputs * 2 + 3);
> +   OUT_BATCH(_3DSTATE_SO_DECL_LIST << 16 |
> +            (linked_xfb_info->NumOutputs * 2 + 1));
> +
> +   OUT_BATCH((buffer_mask << SO_STREAM_TO_BUFFER_SELECTS_0_SHIFT) |
> +            (0 << SO_STREAM_TO_BUFFER_SELECTS_1_SHIFT) |
> +            (0 << SO_STREAM_TO_BUFFER_SELECTS_2_SHIFT) |
> +            (0 << SO_STREAM_TO_BUFFER_SELECTS_3_SHIFT));
> +
> +   OUT_BATCH((linked_xfb_info->NumOutputs << SO_NUM_ENTRIES_0_SHIFT) |
> +            (0 << SO_NUM_ENTRIES_1_SHIFT) |
> +            (0 << SO_NUM_ENTRIES_2_SHIFT) |
> +            (0 << SO_NUM_ENTRIES_3_SHIFT));
> +
> +   for (i = 0; i < linked_xfb_info->NumOutputs; i++) {
> +      OUT_BATCH(so_decl[i]);
> +      OUT_BATCH(0);
> +   }
> +
> +   ADVANCE_BATCH();
> +}
> +
> +static void
> +upload_3dstate_streamout(struct brw_context *brw, bool active,
> +                        struct brw_vue_map *vue_map)
>  {
>    struct intel_context *intel = &brw->intel;
>    struct gl_context *ctx = &intel->ctx;
> -   uint32_t dw1 = 0;
> +   /* _NEW_TRANSFORM_FEEDBACK */
> +   struct gl_transform_feedback_object *xfb_obj =
> +      ctx->TransformFeedback.CurrentObject;
> +   uint32_t dw1 = 0, dw2 = 0;
> +   int i;
>
>    /* _NEW_RASTERIZER_DISCARD */
>    if (ctx->RasterDiscard)
>       dw1 |= SO_RENDERING_DISABLE;
>
> -   /* Disable the SOL stage */
> +   if (active) {
> +      int urb_entry_read_offset = 0;
> +      int urb_entry_read_length = (vue_map->num_slots + 1) / 2 -
> +        urb_entry_read_offset;
> +
> +      dw1 |= SO_FUNCTION_ENABLE;
> +      dw1 |= SO_STATISTICS_ENABLE;
>
+
> +      for (i = 0; i < 4; i++) {
> +        if (xfb_obj->Buffers[i]) {
> +           dw1 |= SO_BUFFER_ENABLE_0 << i;
>
+        }
> +      }
> +
> +      /* We always read the whole vertex.  This could be reduced at some
> +       * point by reading less and offsetting the register index in the
> +       * SO_DECLs.
> +       */
> +      dw2 |= urb_entry_read_offset <<
> SO_STREAM_0_VERTEX_READ_OFFSET_SHIFT;
> +      dw2 |= (urb_entry_read_length - 1) <<
> +        SO_STREAM_0_VERTEX_READ_LENGTH_SHIFT;
> +   }
> +
>    BEGIN_BATCH(3);
>    OUT_BATCH(_3DSTATE_STREAMOUT << 16 | (3 - 2));
> -   OUT_BATCH(0);
> -   OUT_BATCH(0);
> +   OUT_BATCH(dw1);
> +   OUT_BATCH(dw2);
>    ADVANCE_BATCH();
>  }
>
> +static void
> +upload_sol_state(struct brw_context *brw)
> +{
> +   struct intel_context *intel = &brw->intel;
> +   struct gl_context *ctx = &intel->ctx;
> +   /* _NEW_TRANSFORM_FEEDBACK */
> +   struct gl_transform_feedback_object *xfb_obj =
> +      ctx->TransformFeedback.CurrentObject;
> +   bool active = xfb_obj->Active && !xfb_obj->Paused;
> +   struct brw_vue_map vue_map;
> +
> +   /* _NEW_TRANSFORM, CACHE_NEW_VS_PROG */
> +   brw_compute_vue_map(&vue_map, intel, ctx->Transform.ClipPlanesEnabled
> != 0,
> +                       brw->vs.prog_data->outputs_written);
> +
> +   if (active) {
> +      upload_3dstate_so_buffers(brw);
> +      upload_3dstate_so_decl_list(brw, &vue_map);
> +   }
> +
> +   /* Finally, set up the SOL stage.  This command must always follow
> updates to
> +    * the nonpipelined SOL state (3DSTATE_SO_BUFFER,
> 3DSTATE_SO_DECL_LIST) or
> +    * MMIO register updates (current performed by the kernel at each batch
> +    * emit).
> +    */
> +   upload_3dstate_streamout(brw, active, &vue_map);
> +}
> +
>  const struct brw_tracked_state gen7_sol_state = {
>    .dirty = {
> -      .mesa  = _NEW_RASTERIZER_DISCARD,
> -      .brw   = BRW_NEW_BATCH,
> -      .cache = 0,
> +      .mesa  = (_NEW_RASTERIZER_DISCARD |
> +               _NEW_TRANSFORM_FEEDBACK |
> +               _NEW_TRANSFORM),
> +      .brw   = (BRW_NEW_BATCH |
> +               BRW_NEW_VERTEX_PROGRAM),
> +      .cache = CACHE_NEW_VS_PROG,
>    },
>    .emit = upload_sol_state,
>  };
> --
> 1.7.7.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20111222/b3280a29/attachment.htm>


More information about the mesa-dev mailing list