swr: Add polygon stipple support
authorGeorge Kyriazis <george.kyriazis@intel.com>
Sat, 1 Apr 2017 01:09:57 +0000 (20:09 -0500)
committerGeorge Kyriazis <george.kyriazis@intel.com>
Fri, 14 Apr 2017 22:08:12 +0000 (17:08 -0500)
Add polygon stipple functionality to the fragment shader.

Explicitly turn off polygon stipple for lines and points, since we
do them using tris.

Reviewed-by: Bruce Cherniak <bruce.cherniak@intel.com>
src/gallium/drivers/swr/swr_context.h
src/gallium/drivers/swr/swr_shader.cpp
src/gallium/drivers/swr/swr_shader.h
src/gallium/drivers/swr/swr_state.cpp
src/gallium/drivers/swr/swr_state.h

index 233d95ab1675dd95049d4167e559d003f868d58e..4de20c1c1b180d3e38c2db2f7dce11d113da41f1 100644 (file)
@@ -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 *
index 6fc0596ed6011f91211c3a190f204b309849b9f2..d8f551291cd1bb63ef0707bfbd0b1ee1e256252a 100644 (file)
@@ -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});
    }
 
index c9df5b009173a2a0afef5cc20f7ea0053d20b3d5..1ab684605696b47488ce18191de3f9a039195207 100644 (file)
@@ -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 {
index aa9fe099f0a7dec7507145eed6de1451ca2f4988..56b13746d023f91b3072d673b08de49d4165600e 100644 (file)
@@ -40,6 +40,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"
@@ -609,7 +610,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;
 }
 
@@ -986,6 +987,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)
@@ -1407,6 +1419,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);
+      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 |
@@ -1661,7 +1684,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)) {
index c89e303ba337828dd6dd8679af2794e1e094479b..9a8c4e1311cef30c86fb055016c52d373a45f424 100644 (file)
@@ -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.