[Mesa-dev] [PATCH] swr: Add polygon stipple support

Ilia Mirkin imirkin at alum.mit.edu
Fri Apr 14 15:18:12 UTC 2017


On Thu, Apr 13, 2017 at 4:30 PM, George Kyriazis
<george.kyriazis at intel.com> wrote:
> Add polygon stipple functionality to the fragment shader.
>
> Explicitly turn off polygon stipple for lines and points, since we
> do them using tris.
> ---
>  src/gallium/drivers/swr/swr_context.h  |  4 ++-
>  src/gallium/drivers/swr/swr_shader.cpp | 56 ++++++++++++++++++++++++++++++----
>  src/gallium/drivers/swr/swr_shader.h   |  1 +
>  src/gallium/drivers/swr/swr_state.cpp  | 27 ++++++++++++++--
>  src/gallium/drivers/swr/swr_state.h    |  5 +++
>  5 files changed, 84 insertions(+), 9 deletions(-)
>
> diff --git a/src/gallium/drivers/swr/swr_context.h b/src/gallium/drivers/swr/swr_context.h
> index be65a20..9d80c70 100644
> --- a/src/gallium/drivers/swr/swr_context.h
> +++ b/src/gallium/drivers/swr/swr_context.h
> @@ -98,6 +98,8 @@ struct swr_draw_context {
>
>     float userClipPlanes[PIPE_MAX_CLIP_PLANES][4];
>
> +   uint32_t polyStipple[32];
> +
>     SWR_SURFACE_STATE renderTargets[SWR_NUM_ATTACHMENTS];
>     void *pStats;
>  };
> @@ -127,7 +129,7 @@ struct swr_context {
>     struct pipe_constant_buffer
>        constants[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
>     struct pipe_framebuffer_state framebuffer;
> -   struct pipe_poly_stipple poly_stipple;
> +   struct swr_poly_stipple poly_stipple;
>     struct pipe_scissor_state scissor;
>     SWR_RECT swr_scissor;
>     struct pipe_sampler_view *
> diff --git a/src/gallium/drivers/swr/swr_shader.cpp b/src/gallium/drivers/swr/swr_shader.cpp
> index 6fc0596..d8f5512 100644
> --- a/src/gallium/drivers/swr/swr_shader.cpp
> +++ b/src/gallium/drivers/swr/swr_shader.cpp
> @@ -165,6 +165,9 @@ swr_generate_fs_key(struct swr_jit_fs_key &key,
>            sizeof(key.vs_output_semantic_idx));
>
>     swr_generate_sampler_key(swr_fs->info, ctx, PIPE_SHADER_FRAGMENT, key);
> +
> +   key.poly_stipple_enable = ctx->rasterizer->poly_stipple_enable &&
> +      ctx->poly_stipple.prim_is_poly;
>  }
>
>  void
> @@ -1099,17 +1102,58 @@ BuilderSWR::CompileFS(struct swr_context *ctx, swr_jit_fs_key &key)
>     memset(&system_values, 0, sizeof(system_values));
>
>     struct lp_build_mask_context mask;
> +   bool uses_mask = false;
>
> -   if (swr_fs->info.base.uses_kill) {
> -      Value *mask_val = LOAD(pPS, {0, SWR_PS_CONTEXT_activeMask}, "activeMask");
> +   if (swr_fs->info.base.uses_kill ||
> +       key.poly_stipple_enable) {
> +      Value *vActiveMask = NULL;
> +      if (swr_fs->info.base.uses_kill) {
> +         vActiveMask = LOAD(pPS, {0, SWR_PS_CONTEXT_activeMask}, "activeMask");
> +      }
> +      if (key.poly_stipple_enable) {
> +         // first get fragment xy coords and clip to stipple bounds
> +         Value *vXf = LOAD(pPS, {0, SWR_PS_CONTEXT_vX, PixelPositions_UL});
> +         Value *vYf = LOAD(pPS, {0, SWR_PS_CONTEXT_vY, PixelPositions_UL});
> +         Value *vXu = FP_TO_UI(vXf, mSimdInt32Ty);
> +         Value *vYu = FP_TO_UI(vYf, mSimdInt32Ty);
> +
> +         // stipple pattern is 32x32, which means that one line of stipple
> +         // is stored in one word:
> +         // vXstipple is bit offset inside 32-bit stipple word
> +         // vYstipple is word index is stipple array
> +         Value *vXstipple = AND(vXu, VIMMED1(0x1f)); // & (32-1)
> +         Value *vYstipple = AND(vYu, VIMMED1(0x1f)); // & (32-1)
> +
> +         // grab stipple pattern base address
> +         Value *stipplePtr = GEP(hPrivateData, {0, swr_draw_context_polyStipple, 0});
> +         stipplePtr = BITCAST(stipplePtr, mInt8PtrTy);
> +
> +         // peform a gather to grab stipple words for each lane
> +         Value *vStipple = GATHERDD(VUNDEF_I(), stipplePtr, vYstipple,
> +                                    VIMMED1(0xffffffff), C((char)4));
> +
> +         // create a mask with one bit corresponding to the x stipple
> +         // and AND it with the pattern, to see if we have a bit
> +         Value *vBitMask = LSHR(VIMMED1(0x80000000), vXstipple);
> +         Value *vStippleMask = AND(vStipple, vBitMask);
> +         vStippleMask = ICMP_NE(vStippleMask, VIMMED1(0));
> +         vStippleMask = VMASK(vStippleMask);
> +
> +         if (swr_fs->info.base.uses_kill) {
> +            vActiveMask = AND(vActiveMask, vStippleMask);
> +         } else {
> +            vActiveMask = vStippleMask;
> +         }
> +      }
>        lp_build_mask_begin(
> -         &mask, gallivm, lp_type_float_vec(32, 32 * 8), wrap(mask_val));
> +         &mask, gallivm, lp_type_float_vec(32, 32 * 8), wrap(vActiveMask));
> +      uses_mask = true;
>     }
>
>     lp_build_tgsi_soa(gallivm,
>                       swr_fs->pipe.tokens,
>                       lp_type_float_vec(32, 32 * 8),
> -                     swr_fs->info.base.uses_kill ? &mask : NULL, // mask
> +                     uses_mask ? &mask : NULL, // mask
>                       wrap(consts_ptr),
>                       wrap(const_sizes_ptr),
>                       &system_values,
> @@ -1172,13 +1216,13 @@ BuilderSWR::CompileFS(struct swr_context *ctx, swr_jit_fs_key &key)
>     }
>
>     LLVMValueRef mask_result = 0;
> -   if (swr_fs->info.base.uses_kill) {
> +   if (uses_mask) {
>        mask_result = lp_build_mask_end(&mask);
>     }
>
>     IRB()->SetInsertPoint(unwrap(LLVMGetInsertBlock(gallivm->builder)));
>
> -   if (swr_fs->info.base.uses_kill) {
> +   if (uses_mask) {
>        STORE(unwrap(mask_result), pPS, {0, SWR_PS_CONTEXT_activeMask});
>     }
>
> diff --git a/src/gallium/drivers/swr/swr_shader.h b/src/gallium/drivers/swr/swr_shader.h
> index c9df5b0..1ab6846 100644
> --- a/src/gallium/drivers/swr/swr_shader.h
> +++ b/src/gallium/drivers/swr/swr_shader.h
> @@ -66,6 +66,7 @@ struct swr_jit_fs_key : swr_jit_sampler_key {
>     unsigned sprite_coord_enable;
>     ubyte vs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
>     ubyte vs_output_semantic_idx[PIPE_MAX_SHADER_OUTPUTS];
> +   bool poly_stipple_enable;
>  };
>
>  struct swr_jit_vs_key : swr_jit_sampler_key {
> diff --git a/src/gallium/drivers/swr/swr_state.cpp b/src/gallium/drivers/swr/swr_state.cpp
> index 5cc01dd..4f7ef66 100644
> --- a/src/gallium/drivers/swr/swr_state.cpp
> +++ b/src/gallium/drivers/swr/swr_state.cpp
> @@ -39,6 +39,7 @@
>  #include "util/u_helpers.h"
>  #include "util/u_framebuffer.h"
>  #include "util/u_viewport.h"
> +#include "util/u_prim.h"
>
>  #include "swr_state.h"
>  #include "swr_context.h"
> @@ -608,7 +609,7 @@ swr_set_polygon_stipple(struct pipe_context *pipe,
>  {
>     struct swr_context *ctx = swr_context(pipe);
>
> -   ctx->poly_stipple = *stipple; /* struct copy */
> +   ctx->poly_stipple.pipe = *stipple; /* struct copy */
>     ctx->dirty |= SWR_NEW_STIPPLE;
>  }
>
> @@ -952,6 +953,17 @@ swr_user_vbuf_range(const struct pipe_draw_info *info,
>     }
>  }
>
> +static void
> +swr_update_poly_stipple(struct swr_context *ctx)
> +{
> +   struct swr_draw_context *pDC = &ctx->swrDC;
> +
> +   assert(sizeof(ctx->poly_stipple.pipe.stipple) == sizeof(pDC->polyStipple));
> +   memcpy(pDC->polyStipple,
> +          ctx->poly_stipple.pipe.stipple,
> +          sizeof(ctx->poly_stipple.pipe.stipple));
> +}
> +
>  void
>  swr_update_derived(struct pipe_context *pipe,
>                     const struct pipe_draw_info *p_draw_info)
> @@ -1352,6 +1364,17 @@ swr_update_derived(struct pipe_context *pipe,
>        }
>     }
>
> +   /* work around the fact that poly stipple also affects lines */
> +   /* and points, since we rasterize them as triangles, too */
> +   /* Has to be before fragment shader, since it sets SWR_NEW_FS */
> +   if (p_draw_info) {
> +      bool new_prim_is_poly = (u_reduced_prim(p_draw_info->mode) == PIPE_PRIM_TRIANGLES);

What about glPolygonMode and what about geometry shaders that take in
e.g. points and put out triangles? Perhaps you need to pass in a "is
this *really* a triangle" parameter to the shader generated by the
rasterizer.

Also it might be easy to just do all this masking directly in core
instead of as a frag shader variant implemented in swr_shader...

Cheers,

  -ilia

> +      if (new_prim_is_poly != ctx->poly_stipple.prim_is_poly) {
> +         ctx->dirty |= SWR_NEW_FS;
> +         ctx->poly_stipple.prim_is_poly = new_prim_is_poly;
> +      }
> +   }
> +
>     /* FragmentShader */
>     if (ctx->dirty & (SWR_NEW_FS |
>                       SWR_NEW_VS |
> @@ -1606,7 +1629,7 @@ swr_update_derived(struct pipe_context *pipe,
>     }
>
>     if (ctx->dirty & SWR_NEW_STIPPLE) {
> -      /* XXX What to do with this one??? SWR doesn't stipple */
> +      swr_update_poly_stipple(ctx);
>     }
>
>     if (ctx->dirty & (SWR_NEW_VS | SWR_NEW_SO | SWR_NEW_RASTERIZER)) {
> diff --git a/src/gallium/drivers/swr/swr_state.h b/src/gallium/drivers/swr/swr_state.h
> index c89e303..9a8c4e1 100644
> --- a/src/gallium/drivers/swr/swr_state.h
> +++ b/src/gallium/drivers/swr/swr_state.h
> @@ -92,6 +92,11 @@ struct swr_blend_state {
>     RENDER_TARGET_BLEND_COMPILE_STATE compileState[PIPE_MAX_COLOR_BUFS];
>  };
>
> +struct swr_poly_stipple {
> +   struct pipe_poly_stipple pipe;
> +   bool prim_is_poly;
> +};
> +
>  /*
>   * Derived SWR API DrawState
>   * For convenience of making simple changes without re-deriving state.
> --
> 2.7.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list