llvmpipe: clamp fragment shader depth write to the current viewport depth range.
authorMatthew McClure <mcclurem@vmware.com>
Tue, 26 Nov 2013 18:50:27 +0000 (10:50 -0800)
committerJosé Fonseca <jfonseca@vmware.com>
Mon, 9 Dec 2013 12:57:02 +0000 (12:57 +0000)
With this patch, generate_fs_loop will clamp any fragment shader depth writes
to the viewport's min and max depth values. Viewport selection is determined
by the geometry shader output for the viewport array index. If no index is
specified, then the default viewport index is zero. Semantics for this path
can be found in draw_clamp_viewport_idx and lp_clamp_viewport_idx.

lp_jit_viewport was created to store viewport information visible to JIT code,
and is validated when the LP_NEW_VIEWPORT dirty flag is set.

lp_rast_shader_inputs is responsible for passing the viewport_index through
the rasterizer stage to fragment stage (via lp_jit_thread_data).

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Reviewed-by: José Fonseca <jfonseca@vmware.com>
13 files changed:
src/gallium/drivers/llvmpipe/lp_jit.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_rast.c
src/gallium/drivers/llvmpipe/lp_rast.h
src/gallium/drivers/llvmpipe/lp_rast_priv.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_setup_line.c
src/gallium/drivers/llvmpipe/lp_setup_point.c
src/gallium/drivers/llvmpipe/lp_setup_tri.c
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index fa0f128ee3fd04ee65f7385d69d7192e1f92f6e7..fa36fd3512e220acaaab5f0aeb3e8b6485d45f30 100644 (file)
@@ -45,7 +45,33 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
 {
    struct gallivm_state *gallivm = lp->gallivm;
    LLVMContextRef lc = gallivm->context;
-   LLVMTypeRef texture_type, sampler_type;
+   LLVMTypeRef viewport_type, texture_type, sampler_type;
+
+   /* struct lp_jit_viewport */
+   {
+      LLVMTypeRef elem_types[LP_JIT_VIEWPORT_NUM_FIELDS];
+
+      elem_types[LP_JIT_VIEWPORT_MIN_DEPTH] =
+      elem_types[LP_JIT_VIEWPORT_MAX_DEPTH] = LLVMFloatTypeInContext(lc);
+
+      viewport_type = LLVMStructTypeInContext(lc, elem_types,
+                                              Elements(elem_types), 0);
+
+#if HAVE_LLVM < 0x0300
+      LLVMAddTypeName(gallivm->module, "viewport", viewport_type);
+
+      LLVMInvalidateStructLayout(gallivm->target, viewport_type);
+#endif
+
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_viewport, min_depth,
+                             gallivm->target, viewport_type,
+                             LP_JIT_VIEWPORT_MIN_DEPTH);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_viewport, max_depth,
+                             gallivm->target, viewport_type,
+                             LP_JIT_VIEWPORT_MAX_DEPTH);
+      LP_CHECK_STRUCT_SIZE(struct lp_jit_viewport,
+                           gallivm->target, viewport_type);
+   }
 
    /* struct lp_jit_texture */
    {
@@ -101,8 +127,8 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
                            gallivm->target, texture_type);
    }
 
-   {
    /* struct lp_jit_sampler */
+   {
       LLVMTypeRef elem_types[LP_JIT_SAMPLER_NUM_FIELDS];
       elem_types[LP_JIT_SAMPLER_MIN_LOD] =
       elem_types[LP_JIT_SAMPLER_MAX_LOD] =
@@ -113,22 +139,22 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       sampler_type = LLVMStructTypeInContext(lc, elem_types,
                                              Elements(elem_types), 0);
 #if HAVE_LLVM < 0x0300
-      LLVMAddTypeName(gallivm->module, "texture", texture_type);
+      LLVMAddTypeName(gallivm->module, "sampler", sampler_type);
 
-      LLVMInvalidateStructLayout(gallivm->target, texture_type);
+      LLVMInvalidateStructLayout(gallivm->target, sampler_type);
 #endif
 
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, min_lod,
-                             gallivm->target, texture_type,
+                             gallivm->target, sampler_type,
                              LP_JIT_SAMPLER_MIN_LOD);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, max_lod,
-                             gallivm->target, texture_type,
+                             gallivm->target, sampler_type,
                              LP_JIT_SAMPLER_MAX_LOD);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, lod_bias,
-                             gallivm->target, texture_type,
+                             gallivm->target, sampler_type,
                              LP_JIT_SAMPLER_LOD_BIAS);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, border_color,
-                             gallivm->target, texture_type,
+                             gallivm->target, sampler_type,
                              LP_JIT_SAMPLER_BORDER_COLOR);
       LP_CHECK_STRUCT_SIZE(struct lp_jit_sampler,
                            gallivm->target, sampler_type);
@@ -146,6 +172,7 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       elem_types[LP_JIT_CTX_STENCIL_REF_BACK] = LLVMInt32TypeInContext(lc);
       elem_types[LP_JIT_CTX_U8_BLEND_COLOR] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
       elem_types[LP_JIT_CTX_F_BLEND_COLOR] = LLVMPointerType(LLVMFloatTypeInContext(lc), 0);
+      elem_types[LP_JIT_CTX_VIEWPORTS] = LLVMPointerType(viewport_type, 0);
       elem_types[LP_JIT_CTX_TEXTURES] = LLVMArrayType(texture_type,
                                                       PIPE_MAX_SHADER_SAMPLER_VIEWS);
       elem_types[LP_JIT_CTX_SAMPLERS] = LLVMArrayType(sampler_type,
@@ -178,6 +205,9 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, f_blend_color,
                              gallivm->target, context_type,
                              LP_JIT_CTX_F_BLEND_COLOR);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, viewports,
+                             gallivm->target, context_type,
+                             LP_JIT_CTX_VIEWPORTS);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
                              gallivm->target, context_type,
                              LP_JIT_CTX_TEXTURES);
@@ -196,6 +226,8 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LLVMTypeRef thread_data_type;
 
       elem_types[LP_JIT_THREAD_DATA_COUNTER] = LLVMInt64TypeInContext(lc);
+      elem_types[LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX] =
+            LLVMInt32TypeInContext(lc);
 
       thread_data_type = LLVMStructTypeInContext(lc, elem_types,
                                                  Elements(elem_types), 0);
index 30cfaaef5d6afb827b356ca352aa973112147b5a..8eefa7c8479a3eb2562cfc6a222e27f64d094ed1 100644 (file)
@@ -70,6 +70,13 @@ struct lp_jit_sampler
 };
 
 
+struct lp_jit_viewport
+{
+   float min_depth;
+   float max_depth;
+};
+
+
 enum {
    LP_JIT_TEXTURE_WIDTH = 0,
    LP_JIT_TEXTURE_HEIGHT,
@@ -93,6 +100,13 @@ enum {
 };
 
 
+enum {
+   LP_JIT_VIEWPORT_MIN_DEPTH,
+   LP_JIT_VIEWPORT_MAX_DEPTH,
+   LP_JIT_VIEWPORT_NUM_FIELDS /* number of fields above */
+};
+
+
 /**
  * This structure is passed directly to the generated fragment shader.
  *
@@ -115,6 +129,8 @@ struct lp_jit_context
    uint8_t *u8_blend_color;
    float *f_blend_color;
 
+   struct lp_jit_viewport *viewports;
+
    struct lp_jit_texture textures[PIPE_MAX_SHADER_SAMPLER_VIEWS];
    struct lp_jit_sampler samplers[PIPE_MAX_SAMPLERS];
 };
@@ -131,6 +147,7 @@ enum {
    LP_JIT_CTX_STENCIL_REF_BACK,
    LP_JIT_CTX_U8_BLEND_COLOR,
    LP_JIT_CTX_F_BLEND_COLOR,
+   LP_JIT_CTX_VIEWPORTS,
    LP_JIT_CTX_TEXTURES,
    LP_JIT_CTX_SAMPLERS,
    LP_JIT_CTX_COUNT
@@ -155,6 +172,9 @@ enum {
 #define lp_jit_context_f_blend_color(_gallivm, _ptr) \
    lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_F_BLEND_COLOR, "f_blend_color")
 
+#define lp_jit_context_viewports(_gallivm, _ptr) \
+   lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_VIEWPORTS, "viewports")
+
 #define lp_jit_context_textures(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_TEXTURES, "textures")
 
@@ -165,11 +185,19 @@ enum {
 struct lp_jit_thread_data
 {
    uint64_t vis_counter;
+
+   /*
+    * Non-interpolated rasterizer state passed through to the fragment shader.
+    */
+   struct {
+      uint32_t viewport_index;
+   } raster_state;
 };
 
 
 enum {
    LP_JIT_THREAD_DATA_COUNTER = 0,
+   LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX,
    LP_JIT_THREAD_DATA_COUNT
 };
 
@@ -177,7 +205,11 @@ enum {
 #define lp_jit_thread_data_counter(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_THREAD_DATA_COUNTER, "counter")
 
-
+#define lp_jit_thread_data_raster_state_viewport_index(_gallivm, _ptr) \
+   lp_build_struct_get(_gallivm, _ptr, \
+                       LP_JIT_THREAD_DATA_RASTER_STATE_VIEWPORT_INDEX, \
+                       "raster_state.viewport_index")
 /**
  * typedef for fragment shader function
  *
index 0cd62c2d99ff9c7d3a1b2274224753f5a2024950..6feec9471378377fc483b6c316a5d6eb3800fcac 100644 (file)
@@ -367,6 +367,9 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
             depth_stride = scene->zsbuf.stride;
          }
 
+         /* Propagate non-interpolated raster state. */
+         task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
          /* run shader on 4x4 block */
          BEGIN_JIT_CALL(state, task);
          variant->jit_function[RAST_WHOLE]( &state->jit_context,
@@ -462,6 +465,9 @@ lp_rast_shade_quads_mask(struct lp_rasterizer_task *task,
       /* always count this not worth bothering? */
       task->ps_invocations += 1 * variant->ps_inv_multiplier;
 
+      /* Propagate non-interpolated raster state. */
+      task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
       /* run shader on 4x4 block */
       BEGIN_JIT_CALL(state, task);
       variant->jit_function[RAST_EDGE_TEST](&state->jit_context,
index b81d94f50f0e665c61db93998e6d13d2f7246a8f..e2a9ec2089236ebd6880ad6a554fcb6a3fd055e8 100644 (file)
@@ -102,7 +102,7 @@ struct lp_rast_shader_inputs {
    unsigned pad0:29;            /* wasted space */
    unsigned stride;             /* how much to advance data between a0, dadx, dady */
    unsigned layer;              /* the layer to render to (from gs, already clamped) */
-   unsigned pad2;               /* wasted space */
+   unsigned viewport_index;     /* the active viewport index (from gs, already clamped) */
    /* followed by a0, dadx, dady and planes[] */
 };
 
index 77ec329485dd351ee40f4a081057f11978f1cba4..bc361b6f1b9fd85db94d6074ffa2f750876b9816 100644 (file)
@@ -97,7 +97,7 @@ struct lp_rasterizer_task
    /** "my" index */
    unsigned thread_index;
 
-   /* occlude counter for visible pixels */
+   /** Non-interpolated passthru state and occlude counter for visible pixels */
    struct lp_jit_thread_data thread_data;
    uint64_t ps_invocations;
    uint8_t ps_inv_multiplier;
@@ -311,6 +311,9 @@ lp_rast_shade_quads_all( struct lp_rasterizer_task *task,
       /* always count this not worth bothering? */
       task->ps_invocations += 1 * variant->ps_inv_multiplier;
 
+      /* Propagate non-interpolated raster state. */
+      task->thread_data.raster_state.viewport_index = inputs->viewport_index;
+
       /* run shader on 4x4 block */
       BEGIN_JIT_CALL(state, task);
       variant->jit_function[RAST_WHOLE]( &state->jit_context,
index 9b277d32ddc82832e85d0b08ce90021dcb87b877..31aaf963fe9617ab9b11c70553e600d7cd96dd42 100644 (file)
@@ -648,6 +648,41 @@ lp_setup_set_vertex_info( struct lp_setup_context *setup,
 }
 
 
+/**
+ * Called during state validation when LP_NEW_VIEWPORT is set.
+ */
+void
+lp_setup_set_viewports(struct lp_setup_context *setup,
+                       unsigned num_viewports,
+                       const struct pipe_viewport_state *viewports)
+{
+   unsigned i;
+
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   assert(num_viewports <= PIPE_MAX_VIEWPORTS);
+   assert(viewports);
+
+   /*
+    * For use in lp_state_fs.c, propagate the viewport values for all viewports.
+    */
+   for (i = 0; i < num_viewports; i++) {
+      float min_depth;
+      float max_depth;
+
+      min_depth = viewports[i].translate[2];
+      max_depth = viewports[i].translate[2] + viewports[i].scale[2];
+
+      if (setup->viewports[i].min_depth != min_depth ||
+          setup->viewports[i].max_depth != max_depth) {
+          setup->viewports[i].min_depth = min_depth;
+          setup->viewports[i].max_depth = max_depth;
+          setup->dirty |= LP_SETUP_NEW_VIEWPORTS;
+      }
+   }
+}
+
+
 /**
  * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
  */
@@ -863,6 +898,15 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup,
 
 /**
  * Called by vbuf code when we're about to draw something.
+ *
+ * This function stores all dirty state in the current scene's display list
+ * memory, via lp_scene_alloc().  We can not pass pointers of mutable state to
+ * the JIT functions, as the JIT functions will be called later on, most likely
+ * on a different thread.
+ *
+ * When processing dirty state it is imperative that we don't refer to any
+ * pointers previously allocated with lp_scene_alloc() in this function (or any
+ * function) as they may belong to a scene freed since then.
  */
 static boolean
 try_update_scene_state( struct lp_setup_context *setup )
@@ -873,6 +917,29 @@ try_update_scene_state( struct lp_setup_context *setup )
 
    assert(scene);
 
+   if (setup->dirty & LP_SETUP_NEW_VIEWPORTS) {
+      /*
+       * Record new depth range state for changes due to viewport updates.
+       *
+       * TODO: Collapse the existing viewport and depth range information
+       *       into one structure, for access by JIT.
+       */
+      struct lp_jit_viewport *stored;
+
+      stored = (struct lp_jit_viewport *)
+         lp_scene_alloc(scene, sizeof setup->viewports);
+
+      if (!stored) {
+         assert(!new_scene);
+         return FALSE;
+      }
+
+      memcpy(stored, setup->viewports, sizeof setup->viewports);
+
+      setup->fs.current.jit_context.viewports = stored;
+      setup->dirty |= LP_SETUP_NEW_FS;
+   }
+
    if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) {
       uint8_t *stored;
       float* fstored;
index 712ed145d8e8d268e0eeebc52304e657ffdf240e..f4fbd3dbf65aefa575c107bb23065c53297d82af 100644 (file)
@@ -120,6 +120,11 @@ void
 lp_setup_set_scissors( struct lp_setup_context *setup,
                        const struct pipe_scissor_state *scissors );
 
+void
+lp_setup_set_viewports(struct lp_setup_context *setup,
+                       unsigned num_viewports,
+                       const struct pipe_viewport_state *viewports);
+
 void
 lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                                     unsigned num,
@@ -155,7 +160,7 @@ lp_setup_end_query(struct lp_setup_context *setup,
                    struct llvmpipe_query *pq);
 
 static INLINE unsigned
-lp_clamp_scissor_idx(int idx)
+lp_clamp_viewport_idx(int idx)
 {
    return (PIPE_MAX_VIEWPORTS > idx && idx >= 0) ? idx : 0;
 }
index 44be85fde1a57d4818d2ceccac9c09a013d8a9a1..8bb95c15697c5709b983f8f89b0c88fc66e7c8e5 100644 (file)
@@ -47,6 +47,7 @@
 #define LP_SETUP_NEW_CONSTANTS   0x02
 #define LP_SETUP_NEW_BLEND_COLOR 0x04
 #define LP_SETUP_NEW_SCISSOR     0x08
+#define LP_SETUP_NEW_VIEWPORTS   0x10
 
 
 struct lp_setup_variant;
@@ -112,6 +113,7 @@ struct lp_setup_context
    struct u_rect framebuffer;
    struct u_rect scissors[PIPE_MAX_VIEWPORTS];
    struct u_rect draw_regions[PIPE_MAX_VIEWPORTS];   /* intersection of fb & scissor */
+   struct lp_jit_viewport viewports[PIPE_MAX_VIEWPORTS];
 
    struct {
       unsigned flags;
index 9b3321e3ec1a68a97c8cc9b2493b3465cfcefca4..7e1f6a36745b0ab7632a3962aa04422e9758e1ec 100644 (file)
@@ -294,7 +294,7 @@ try_setup_line( struct lp_setup_context *setup,
    int y[4];
    int i;
    int nr_planes = 4;
-   unsigned scissor_index = 0;
+   unsigned viewport_index = 0;
    unsigned layer = 0;
    
    /* linewidth should be interpreted as integer */
@@ -324,7 +324,7 @@ try_setup_line( struct lp_setup_context *setup,
       nr_planes = 8;
       if (setup->viewport_index_slot > 0) {
          unsigned *udata = (unsigned*)v1[setup->viewport_index_slot];
-         scissor_index = lp_clamp_scissor_idx(*udata);
+         viewport_index = lp_clamp_viewport_idx(*udata);
       }
    }
    else {
@@ -573,7 +573,7 @@ try_setup_line( struct lp_setup_context *setup,
       return TRUE;
    }
 
-   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
@@ -635,6 +635,7 @@ try_setup_line( struct lp_setup_context *setup,
    line->inputs.disable = FALSE;
    line->inputs.opaque = FALSE;
    line->inputs.layer = layer;
+   line->inputs.viewport_index = viewport_index;
 
    for (i = 0; i < 4; i++) {
 
@@ -697,7 +698,7 @@ try_setup_line( struct lp_setup_context *setup,
     */
    if (nr_planes == 8) {
       const struct u_rect *scissor =
-         &setup->scissors[scissor_index];
+         &setup->scissors[viewport_index];
 
       plane[4].dcdx = -1;
       plane[4].dcdy = 0;
@@ -720,7 +721,7 @@ try_setup_line( struct lp_setup_context *setup,
       plane[7].eo = 0;
    }
 
-   return lp_setup_bin_triangle(setup, line, &bbox, nr_planes, scissor_index);
+   return lp_setup_bin_triangle(setup, line, &bbox, nr_planes, viewport_index);
 }
 
 
index 45068ec6df3e09043d567041791126d6bae6d975..4b31495a5c8bbb66101a7b11868d7475ef8a64f9 100644 (file)
@@ -330,12 +330,12 @@ try_setup_point( struct lp_setup_context *setup,
    struct u_rect bbox;
    unsigned nr_planes = 4;
    struct point_info info;
-   unsigned scissor_index = 0;
+   unsigned viewport_index = 0;
    unsigned layer = 0;
 
    if (setup->viewport_index_slot > 0) {
       unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
-      scissor_index = lp_clamp_scissor_idx(*udata);
+      viewport_index = lp_clamp_viewport_idx(*udata);
    }
    if (setup->layer_slot > 0) {
       layer = *(unsigned*)v0[setup->layer_slot];
@@ -362,13 +362,13 @@ try_setup_point( struct lp_setup_context *setup,
       bbox.y1--;
    }
    
-   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
    }
 
-   u_rect_find_intersection(&setup->draw_regions[scissor_index], &bbox);
+   u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox);
 
    point = lp_setup_alloc_triangle(scene,
                                    key->num_inputs,
@@ -413,6 +413,7 @@ try_setup_point( struct lp_setup_context *setup,
    point->inputs.disable = FALSE;
    point->inputs.opaque = FALSE;
    point->inputs.layer = layer;
+   point->inputs.viewport_index = viewport_index;
 
    {
       struct lp_rast_plane *plane = GET_PLANES(point);
@@ -438,7 +439,7 @@ try_setup_point( struct lp_setup_context *setup,
       plane[3].eo = 0;
    }
 
-   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes, scissor_index);
+   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes, viewport_index);
 }
 
 
index 53ab1f1f0c0bfabd09b065e2e9ea19b029a883d7..e22f14c9ca086bb2e85d6d6f95ef34f92102a3d2 100644 (file)
@@ -274,7 +274,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
    struct u_rect bbox;
    unsigned tri_bytes;
    int nr_planes = 3;
-   unsigned scissor_index = 0;
+   unsigned viewport_index = 0;
    unsigned layer = 0;
 
    /* Area should always be positive here */
@@ -287,7 +287,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
       nr_planes = 7;
       if (setup->viewport_index_slot > 0) {
          unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
-         scissor_index = lp_clamp_scissor_idx(*udata);
+         viewport_index = lp_clamp_viewport_idx(*udata);
       }
    }
    else {
@@ -323,7 +323,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
       return TRUE;
    }
 
-   if (!u_rect_test_intersection(&setup->draw_regions[scissor_index], &bbox)) {
+   if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
       if (0) debug_printf("offscreen\n");
       LP_COUNT(nr_culled_tris);
       return TRUE;
@@ -368,6 +368,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
    tri->inputs.disable = FALSE;
    tri->inputs.opaque = setup->fs.current.variant->opaque;
    tri->inputs.layer = layer;
+   tri->inputs.viewport_index = viewport_index;
 
    if (0)
       lp_dump_setup_coef(&setup->setup.variant->key,
@@ -547,7 +548,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
     * these planes elsewhere.
     */
    if (nr_planes == 7) {
-      const struct u_rect *scissor = &setup->scissors[scissor_index];
+      const struct u_rect *scissor = &setup->scissors[viewport_index];
 
       plane[3].dcdx = -1;
       plane[3].dcdy = 0;
@@ -570,7 +571,7 @@ do_triangle_ccw(struct lp_setup_context *setup,
       plane[6].eo = 0;
    }
 
-   return lp_setup_bin_triangle(setup, tri, &bbox, nr_planes, scissor_index);
+   return lp_setup_bin_triangle(setup, tri, &bbox, nr_planes, viewport_index);
 }
 
 /*
@@ -605,7 +606,7 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
                        struct lp_rast_triangle *tri,
                        const struct u_rect *bbox,
                        int nr_planes,
-                       unsigned scissor_index )
+                       unsigned viewport_index )
 {
    struct lp_scene *scene = setup->scene;
    struct u_rect trimmed_box = *bbox;   
@@ -628,7 +629,7 @@ lp_setup_bin_triangle( struct lp_setup_context *setup,
     * the rasterizer to also respect scissor, etc, just for the rare
     * cases where a small triangle extends beyond the scissor.
     */
-   u_rect_find_intersection(&setup->draw_regions[scissor_index],
+   u_rect_find_intersection(&setup->draw_regions[viewport_index],
                             &trimmed_box);
 
    /* Determine which tile(s) intersect the triangle's bounding box
index 47e413b776c17ad2a5cb32059968ea2765b85f2f..5c3a3a8e3a9a9cabe3ffc54e7fdfe2e07c8f3c3c 100644 (file)
@@ -219,6 +219,18 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                                           llvmpipe->num_samplers[PIPE_SHADER_FRAGMENT],
                                           llvmpipe->samplers[PIPE_SHADER_FRAGMENT]);
 
+   if (llvmpipe->dirty & LP_NEW_VIEWPORT) {
+      /*
+       * Update setup and fragment's view of the active viewport state.
+       *
+       * XXX TODO: It is possible to only loop over the active viewports
+       *           instead of all viewports (PIPE_MAX_VIEWPORTS).
+       */
+      lp_setup_set_viewports(llvmpipe->setup,
+                             PIPE_MAX_VIEWPORTS,
+                             llvmpipe->viewports);
+   }
+
    llvmpipe->dirty = 0;
 }
 
index b5816e038f1e0c6a1f575677195757c5e9e39a70..74c7360bfbb380ec5790f3589c428395054d662c 100644 (file)
@@ -214,6 +214,30 @@ find_output_by_semantic( const struct tgsi_shader_info *info,
 }
 
 
+/**
+ * Fetch the specified lp_jit_viewport structure for a given viewport_index.
+ */
+static LLVMValueRef
+lp_llvm_viewport(LLVMValueRef context_ptr,
+                 struct gallivm_state *gallivm,
+                 LLVMValueRef viewport_index)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMValueRef ptr;
+   LLVMValueRef res;
+   struct lp_type viewport_type =
+      lp_type_float_vec(32, 32 * LP_JIT_VIEWPORT_NUM_FIELDS);
+
+   ptr = lp_jit_context_viewports(gallivm, context_ptr);
+   ptr = LLVMBuildPointerCast(builder, ptr,
+            LLVMPointerType(lp_build_vec_type(gallivm, viewport_type), 0), "");
+
+   res = lp_build_pointer_get(builder, ptr, viewport_index);
+
+   return res;
+}
+
+
 /**
  * Generate the fragment shader, depth/stencil test, and alpha tests.
  */
@@ -421,7 +445,47 @@ generate_fs_loop(struct gallivm_state *gallivm,
                                          0);
 
       if (pos0 != -1 && outputs[pos0][2]) {
+         LLVMValueRef viewport, min_depth, max_depth;
+         LLVMValueRef viewport_index;
+         struct lp_build_context f32_bld;
+
+         assert(type.floating);
+         lp_build_context_init(&f32_bld, gallivm, type);
+
+         /*
+          * Assumes clamping of the viewport index will occur in setup/gs. Value
+          * is passed through the rasterization stage via lp_rast_shader_inputs.
+          *
+          * See: draw_clamp_viewport_idx and lp_clamp_viewport_idx for clamping
+          *      semantics.
+          */
+         viewport_index = lp_jit_thread_data_raster_state_viewport_index(gallivm,
+                             thread_data_ptr);
+
+         /*
+          * Load the min and max depth from the lp_jit_context.viewports
+          * array of lp_jit_viewport structures.
+          */
+         viewport = lp_llvm_viewport(context_ptr, gallivm, viewport_index);
+
+         /* viewports[viewport_index].min_depth */
+         min_depth = LLVMBuildExtractElement(builder, viewport,
+                        lp_build_const_int32(gallivm, LP_JIT_VIEWPORT_MIN_DEPTH),
+                        "");
+         min_depth = lp_build_broadcast_scalar(&f32_bld, min_depth);
+
+         /* viewports[viewport_index].max_depth */
+         max_depth = LLVMBuildExtractElement(builder, viewport,
+                        lp_build_const_int32(gallivm, LP_JIT_VIEWPORT_MAX_DEPTH),
+                        "");
+         max_depth = lp_build_broadcast_scalar(&f32_bld, max_depth);
+
          z = LLVMBuildLoad(builder, outputs[pos0][2], "output.z");
+
+         /*
+          * Clamp to the min and max depth values for the given viewport.
+          */
+         z = lp_build_clamp(&f32_bld, z, min_depth, max_depth);
       }
 
       lp_build_depth_stencil_load_swizzled(gallivm, type,