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

Ilia Mirkin imirkin at alum.mit.edu
Fri Apr 14 16:35:54 UTC 2017


On Fri, Apr 14, 2017 at 11:18 AM, Ilia Mirkin <imirkin at alum.mit.edu> wrote:
> 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.

Actually the GS thing won't happen since polygon stippling is a
compat-only feature and we don't support GS in compat profiles. You do
need to check that the polymode == FILL here though.

> 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...

I still think this would be a better place. Note that line stippling
is also a thing.

>
> Cheers,
>
>   -ilia


More information about the mesa-dev mailing list