llvmpipe: implement scissor testing
authorBrian Paul <brianp@vmware.com>
Fri, 15 Jan 2010 02:15:00 +0000 (19:15 -0700)
committerBrian Paul <brianp@vmware.com>
Fri, 15 Jan 2010 02:15:00 +0000 (19:15 -0700)
The scissor test is implemented as another per-quad operation in
the JIT code.  The four scissor box params are passed via the
lp_jit_context.  In the JIT code we compare the quad's x/y coords
against the clip bounds and create a new in/out mask that's AND'd
with the main quad mask.

Note: we should also do scissor testing in the triangle setup code
to improve efficiency.  That's not done yet.

src/gallium/drivers/llvmpipe/lp_jit.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index 4ef0783f3e2962078d51a2477ba968e72f8a779b..429cb973c263575d839138721ce7fd871d1e7261 100644 (file)
@@ -79,13 +79,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
 
    /* struct lp_jit_context */
    {
-      LLVMTypeRef elem_types[4];
+      LLVMTypeRef elem_types[8];
       LLVMTypeRef context_type;
 
       elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* constants */
-      elem_types[1] = LLVMFloatType();                     /* alpha_ref_value */
-      elem_types[2] = LLVMPointerType(LLVMInt8Type(), 0);  /* blend_color */
-      elem_types[3] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
+      elem_types[1] = LLVMFloatType();                     /* alpha_ref_value */      elem_types[2] = LLVMFloatType();                     /* scissor_xmin */
+      elem_types[3] = LLVMFloatType();                     /* scissor_ymin */
+      elem_types[4] = LLVMFloatType();                     /* scissor_xmax */
+      elem_types[5] = LLVMFloatType();                     /* scissor_ymax */
+      elem_types[6] = LLVMPointerType(LLVMInt8Type(), 0);  /* blend_color */
+      elem_types[7] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
 
       context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
 
@@ -93,8 +96,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
                              screen->target, context_type, 0);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, alpha_ref_value,
                              screen->target, context_type, 1);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmin,
                              screen->target, context_type, 2);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymin,
+                             screen->target, context_type, 3);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmax,
+                             screen->target, context_type, 4);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymax,
+                             screen->target, context_type, 5);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
+                             screen->target, context_type, 6);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
                              screen->target, context_type,
                              LP_JIT_CONTEXT_TEXTURES_INDEX);
index 3b316914b02a6d9d70574d223d45a809bb8d6ee6..9cbe1bd3b1b7f6c466311d74fa0cf27169ea676c 100644 (file)
@@ -79,6 +79,9 @@ struct lp_jit_context
 
    float alpha_ref_value;
 
+   /** floats, not ints */
+   float scissor_xmin, scissor_ymin, scissor_xmax, scissor_ymax;
+
    /* FIXME: store (also?) in floats */
    uint8_t *blend_color;
 
@@ -92,10 +95,22 @@ struct lp_jit_context
 #define lp_jit_context_alpha_ref_value(_builder, _ptr) \
    lp_build_struct_get(_builder, _ptr, 1, "alpha_ref_value")
 
+#define lp_jit_context_scissor_xmin_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 2, "scissor_xmin")
+
+#define lp_jit_context_scissor_ymin_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 3, "scissor_ymin")
+
+#define lp_jit_context_scissor_xmax_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 4, "scissor_xmax")
+
+#define lp_jit_context_scissor_ymax_value(_builder, _ptr) \
+   lp_build_struct_get(_builder, _ptr, 5, "scissor_ymax")
+
 #define lp_jit_context_blend_color(_builder, _ptr) \
-   lp_build_struct_get(_builder, _ptr, 2, "blend_color")
+   lp_build_struct_get(_builder, _ptr, 6, "blend_color")
 
-#define LP_JIT_CONTEXT_TEXTURES_INDEX 3
+#define LP_JIT_CONTEXT_TEXTURES_INDEX 7
 
 #define lp_jit_context_textures(_builder, _ptr) \
    lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CONTEXT_TEXTURES_INDEX, "textures")
index 649e97992bad8ce915cf9e1a6cd8b84fdf7ce1a8..284337e8252eeb47199cdb611937f672685b89ab 100644 (file)
@@ -413,6 +413,21 @@ lp_setup_set_blend_color( struct setup_context *setup,
 }
 
 
+void
+lp_setup_set_scissor( struct setup_context *setup,
+                      const struct pipe_scissor_state *scissor )
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   assert(scissor);
+
+   if (memcmp(&setup->scissor.current, scissor, sizeof(*scissor)) != 0) {
+      setup->scissor.current = *scissor; /* struct copy */
+      setup->dirty |= LP_SETUP_NEW_SCISSOR;
+   }
+}
+
+
 void 
 lp_setup_set_flatshade_first( struct setup_context *setup,
                               boolean flatshade_first )
@@ -534,6 +549,25 @@ lp_setup_update_state( struct setup_context *setup )
       setup->dirty |= LP_SETUP_NEW_FS;
    }
 
+   if (setup->dirty & LP_SETUP_NEW_SCISSOR) {
+      float *stored;
+
+      stored = lp_scene_alloc_aligned(scene, 4 * sizeof(int32_t), 16);
+
+      stored[0] = (float) setup->scissor.current.minx;
+      stored[1] = (float) setup->scissor.current.miny;
+      stored[2] = (float) setup->scissor.current.maxx;
+      stored[3] = (float) setup->scissor.current.maxy;
+
+      setup->scissor.stored = stored;
+
+      setup->fs.current.jit_context.scissor_xmin = stored[0];
+      setup->fs.current.jit_context.scissor_ymin = stored[1];
+      setup->fs.current.jit_context.scissor_xmax = stored[2];
+      setup->fs.current.jit_context.scissor_ymax = stored[3];
+
+      setup->dirty |= LP_SETUP_NEW_FS;
+   }
 
    if(setup->dirty & LP_SETUP_NEW_CONSTANTS) {
       struct pipe_buffer *buffer = setup->constants.current;
index 429abeba43b98c919319daff60a3bf94bde4893b..c7ef3d394a44c433ec0e76c51e08de71702266be 100644 (file)
@@ -113,6 +113,10 @@ void
 lp_setup_set_blend_color( struct setup_context *setup,
                           const struct pipe_blend_color *blend_color );
 
+void
+lp_setup_set_scissor( struct setup_context *setup,
+                      const struct pipe_scissor_state *scissor );
+
 void
 lp_setup_set_sampler_textures( struct setup_context *setup,
                                unsigned num, struct pipe_texture **texture);
index e6f6f0e0bbb327f8d14e79878f3bc52edf0fc6b2..fc0aef1376cc41813a5355f5f6346ed8cf3b502b 100644 (file)
@@ -45,6 +45,7 @@
 #define LP_SETUP_NEW_FS          0x01
 #define LP_SETUP_NEW_CONSTANTS   0x02
 #define LP_SETUP_NEW_BLEND_COLOR 0x04
+#define LP_SETUP_NEW_SCISSOR     0x08
 
 
 struct lp_scene_queue;
@@ -122,6 +123,11 @@ struct setup_context
       uint8_t *stored;
    } blend_color;
 
+   struct {
+      struct pipe_scissor_state current;
+      const void *stored;
+   } scissor;
+
    unsigned dirty;   /**< bitmask of LP_SETUP_NEW_x bits */
 
    void (*point)( struct setup_context *,
index 4c6747bb2b67186bfab3bc8c3161d85a0e43fa70..ddb152c074057c8a63b661e316680abee783b9ce 100644 (file)
@@ -72,6 +72,7 @@ struct lp_fragment_shader_variant_key
    enum pipe_format zsbuf_format;
    unsigned nr_cbufs:8;
    unsigned flatshade:1;
+   unsigned scissor:1;
 
    struct {
       ubyte colormask;
index 2c349fdb1d11a77fd618e9f55faf0554de303e00..28af477914c28860d70d3e35a45cfa6d62466ead 100644 (file)
@@ -160,6 +160,7 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
 
    if (llvmpipe->dirty & (LP_NEW_FS |
                           LP_NEW_BLEND |
+                          LP_NEW_SCISSOR |
                           LP_NEW_DEPTH_STENCIL_ALPHA |
                           LP_NEW_RASTERIZER |
                           LP_NEW_SAMPLER |
@@ -170,6 +171,9 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
       lp_setup_set_blend_color(llvmpipe->setup,
                                &llvmpipe->blend_color);
 
+   if (llvmpipe->dirty & LP_NEW_SCISSOR)
+      lp_setup_set_scissor(llvmpipe->setup, &llvmpipe->scissor);
+
    if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA)
       lp_setup_set_alpha_ref_value(llvmpipe->setup, 
                                    llvmpipe->depth_stencil->alpha.ref_value);
index 26a2d6cc2399e22da9335466a4a8fdb87f5d0f38..d12d3f6091aeb10ab56d6744daba541128766bc1 100644 (file)
@@ -304,6 +304,51 @@ generate_tri_edge_mask(LLVMBuilderRef builder,
 }
 
 
+static LLVMValueRef
+generate_scissor_test(LLVMBuilderRef builder,
+                      LLVMValueRef context_ptr,
+                      const struct lp_build_interp_soa_context *interp,
+                      struct lp_type type)
+{
+   LLVMTypeRef vec_type = lp_build_vec_type(type);
+   LLVMValueRef xpos = interp->pos[0], ypos = interp->pos[1];
+   LLVMValueRef xmin, ymin, xmax, ymax;
+   LLVMValueRef m0, m1, m2, m3, m;
+
+   /* xpos, ypos contain the window coords for the four pixels in the quad */
+   assert(xpos);
+   assert(ypos);
+
+   /* get the current scissor bounds, convert to vectors */
+   xmin = lp_jit_context_scissor_xmin_value(builder, context_ptr);
+   xmin = lp_build_broadcast(builder, vec_type, xmin);
+
+   ymin = lp_jit_context_scissor_ymin_value(builder, context_ptr);
+   ymin = lp_build_broadcast(builder, vec_type, ymin);
+
+   xmax = lp_jit_context_scissor_xmax_value(builder, context_ptr);
+   xmax = lp_build_broadcast(builder, vec_type, xmax);
+
+   ymax = lp_jit_context_scissor_ymax_value(builder, context_ptr);
+   ymax = lp_build_broadcast(builder, vec_type, ymax);
+
+   /* compare the fragment's position coordinates against the scissor bounds */
+   m0 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, xpos, xmin);
+   m1 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, ypos, ymin);
+   m2 = lp_build_compare(builder, type, PIPE_FUNC_LESS, xpos, xmax);
+   m3 = lp_build_compare(builder, type, PIPE_FUNC_LESS, ypos, ymax);
+
+   /* AND all the masks together */
+   m = LLVMBuildAnd(builder, m0, m1, "");
+   m = LLVMBuildAnd(builder, m, m2, "");
+   m = LLVMBuildAnd(builder, m, m3, "");
+
+   lp_build_name(m, "scissormask");
+
+   return m;
+}
+
+
 /**
  * Generate the fragment shader, depth/stencil test, and alpha tests.
  * \param i  which quad in the tile, in range [0,3]
@@ -372,6 +417,11 @@ generate_fs(struct llvmpipe_context *lp,
    /* 'mask' will control execution based on quad's pixel alive/killed state */
    lp_build_mask_begin(&mask, flow, type, *pmask);
 
+   if (key->scissor) {
+      LLVMValueRef smask =
+         generate_scissor_test(builder, context_ptr, interp, type);
+      lp_build_mask_update(&mask, smask);
+   }
 
    early_depth_test =
       key->depth.enabled &&
@@ -968,6 +1018,7 @@ make_variant_key(struct llvmpipe_context *lp,
    /* alpha.ref_value is passed in jit_context */
 
    key->flatshade = lp->rasterizer->flatshade;
+   key->scissor = lp->rasterizer->scissor;
 
    if (lp->framebuffer.nr_cbufs) {
       memcpy(&key->blend, lp->blend, sizeof key->blend);
@@ -1033,6 +1084,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
             key.blend.colormask == 0xf &&
             !key.alpha.enabled &&
             !key.depth.enabled &&
+            !key.scissor &&
             !shader->info.uses_kill
             ? TRUE : FALSE;