llvmpipe: implement occlusion query
authorQicheng Christopher Li <chrisl@vmware.com>
Thu, 6 May 2010 17:45:42 +0000 (11:45 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 6 May 2010 17:45:45 +0000 (11:45 -0600)
OpenGL occlusion queries work now.  The Mesa demos, glean test and piglit
tests all pass.  A few enhancements are possible in the future. -Brian

Signed-off-by: Brian Paul <brianp@vmware.com>
14 files changed:
src/gallium/drivers/llvmpipe/lp_bld_depth.c
src/gallium/drivers/llvmpipe/lp_bld_depth.h
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_query.c
src/gallium/drivers/llvmpipe/lp_query.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_state.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index 1b59a13c946353393b24595909be7cb4f5e6c544..e05bbe5011a40c79a227685552c78e90d9c5138a 100644 (file)
@@ -72,6 +72,7 @@
 #include "gallivm/lp_bld_const.h"
 #include "gallivm/lp_bld_logic.h"
 #include "gallivm/lp_bld_flow.h"
+#include "gallivm/lp_bld_intr.h"
 #include "gallivm/lp_bld_debug.h"
 #include "gallivm/lp_bld_swizzle.h"
 
@@ -445,6 +446,42 @@ get_s_shift_and_mask(const struct util_format_description *format_desc,
 }
 
 
+/**
+ * Perform the occlusion test and increase the counter.
+ * Test the depth mask. Add the number of channel which has none zero mask
+ * into the occlusion counter. e.g. maskvalue is {-1, -1, -1, -1}.
+ * The counter will add 4.
+ *
+ * \param type holds element type of the mask vector.
+ * \param maskvalue is the depth test mask.
+ * \param counter is a pointer of the uint32 counter.
+ */
+static void
+lp_build_occlusion_count(LLVMBuilderRef builder,
+                         struct lp_type type,
+                         LLVMValueRef maskvalue,
+                         LLVMValueRef counter)
+{
+   LLVMValueRef countmask = lp_build_const_int_vec(type, 1);
+   LLVMValueRef countv = LLVMBuildAnd(builder, maskvalue, countmask, "countv");
+   LLVMTypeRef i8v16 = LLVMVectorType(LLVMInt8Type(), 16);
+   LLVMValueRef counti = LLVMBuildBitCast(builder, countv, i8v16, "counti");
+   LLVMValueRef maskarray[4] = {
+      LLVMConstInt(LLVMInt32Type(), 0, 0),
+      LLVMConstInt(LLVMInt32Type(), 4, 0),
+      LLVMConstInt(LLVMInt32Type(), 8, 0),
+      LLVMConstInt(LLVMInt32Type(), 12, 0),
+   };
+   LLVMValueRef shufflemask = LLVMConstVector(maskarray, 4);
+   LLVMValueRef shufflev =  LLVMBuildShuffleVector(builder, counti, LLVMGetUndef(i8v16), shufflemask, "shufflev");
+   LLVMValueRef shuffle = LLVMBuildBitCast(builder, shufflev, LLVMInt32Type(), "shuffle");
+   LLVMValueRef count = lp_build_intrinsic_unary(builder, "llvm.ctpop.i32", LLVMInt32Type(), shuffle);
+   LLVMValueRef orig = LLVMBuildLoad(builder, counter, "orig");
+   LLVMValueRef incr = LLVMBuildAdd(builder, orig, count, "incr");
+   LLVMBuildStore(builder, incr, counter);
+}
+
+
 
 /**
  * Generate code for performing depth and/or stencil tests.
@@ -470,7 +507,8 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
                             LLVMValueRef stencil_refs[2],
                             LLVMValueRef z_src,
                             LLVMValueRef zs_dst_ptr,
-                            LLVMValueRef face)
+                            LLVMValueRef face,
+                            LLVMValueRef counter)
 {
    struct lp_build_context bld;
    struct lp_build_context sbld;
@@ -682,4 +720,7 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
 
    if (depth->enabled && stencil[0].enabled)
       lp_build_mask_update(mask, z_pass);
+
+   if (counter)
+      lp_build_occlusion_count(builder, type, mask->value, counter);
 }
index 27dd46b625daff4e2f607af521d6d7f1efa3da33..e257a5bd7d09c678361945e9d56a34b86fd3a60d 100644 (file)
@@ -60,7 +60,8 @@ lp_build_depth_stencil_test(LLVMBuilderRef builder,
                             LLVMValueRef stencil_refs[2],
                             LLVMValueRef zs_src,
                             LLVMValueRef zs_dst_ptr,
-                            LLVMValueRef facing);
+                            LLVMValueRef facing,
+                            LLVMValueRef counter);
 
 
 #endif /* !LP_BLD_DEPTH_H */
index 4e597b247960ac8f0692b108b68f69c669395f4e..de7fe7a17968be2de0737a1c02991a895478b563 100644 (file)
@@ -82,11 +82,7 @@ struct llvmpipe_context {
 
    unsigned dirty; /**< Mask of LP_NEW_x flags */
 
-   /* Counter for occlusion queries.  Note this supports overlapping
-    * queries.
-    */
-   uint64_t occlusion_count;
-   unsigned active_query_count;
+   int active_query_count;
 
    /** Mapped vertex buffers */
    ubyte *mapped_vbuffer[PIPE_MAX_ATTRIBS];
index 5d0268c68c4a5cdaf927a6d3746bd9d024e31a0b..fc43d0bf5aadc1c39bc6788bf4107e7f1edcddfb 100644 (file)
@@ -146,7 +146,8 @@ enum {
    lp_build_struct_get(_builder, _ptr, LP_JIT_CTX_BLEND_COLOR, "blend_color")
 
 #define lp_jit_context_textures(_builder, _ptr) \
-   lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CONTEXT_TEXTURES, "textures")
+   lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CTX_TEXTURES, "textures")
+
 
 
 /** Indexes into jit_function[] array */
@@ -169,7 +170,8 @@ typedef void
                     const int32_t c3,
                     const int32_t *step1,
                     const int32_t *step2,
-                    const int32_t *step3);
+                    const int32_t *step3,
+                    uint32_t *counter);
 
 
 void
index 5554285425deb52ab50150a095929a181b989a73..a1836bbde910d2a106cfac6bfc51d47893b2ee1f 100644 (file)
@@ -1,6 +1,7 @@
 /**************************************************************************
  * 
  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2010 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  * 
  **************************************************************************/
 
-/* Author:
- *    Keith Whitwell <keith@tungstengraphics.com>
+/* Authors:
+ *    Keith Whitwell, Qicheng Christopher Li, Brian Paul
  */
 
 #include "draw/draw_context.h"
 #include "util/u_memory.h"
 #include "lp_context.h"
 #include "lp_query.h"
+#include "lp_rast.h"
+#include "lp_rast_priv.h"
 #include "lp_state.h"
-
-struct llvmpipe_query {
-   uint64_t start;
-   uint64_t end;
-};
+#include "lp_setup_context.h"
 
 
 static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )
@@ -51,15 +50,46 @@ static struct pipe_query *
 llvmpipe_create_query(struct pipe_context *pipe, 
                      unsigned type)
 {
+   struct llvmpipe_query *pq;
+
    assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
-   return (struct pipe_query *)CALLOC_STRUCT( llvmpipe_query );
+
+   pq = CALLOC_STRUCT( llvmpipe_query );
+   if (pq) {
+      pipe_mutex_init(pq->mutex);
+   }
+
+   return (struct pipe_query *) pq;
 }
 
 
 static void
 llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
 {
-   FREE(q);
+   struct llvmpipe_query *pq = llvmpipe_query(q);
+   pipe_mutex_destroy(pq->mutex);
+   FREE(pq);
+}
+
+
+static boolean
+llvmpipe_get_query_result(struct pipe_context *pipe, 
+                         struct pipe_query *q,
+                         boolean wait,
+                         uint64_t *result )
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
+   struct llvmpipe_query *pq = llvmpipe_query(q);
+
+   if (!pq->done) {
+      lp_setup_flush(llvmpipe->setup, TRUE);
+   }
+
+   if (pq->done) {
+      *result = pq->result;
+   }
+
+   return pq->done;
 }
 
 
@@ -67,9 +97,20 @@ static void
 llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
-   struct llvmpipe_query *sq = llvmpipe_query(q);
-   
-   sq->start = llvmpipe->occlusion_count;
+   struct llvmpipe_query *pq = llvmpipe_query(q);
+
+   /* Check if the query is already in the scene.  If so, we need to
+    * flush the scene now.  Real apps shouldn't re-use a query in a
+    * frame of rendering.
+    */
+   if (pq->binned) {
+      struct pipe_fence_handle *fence;
+      pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, &fence);
+      pipe->screen->fence_finish(pipe->screen, fence, 0);
+   }
+
+   lp_setup_begin_query(llvmpipe->setup, pq);
+
    llvmpipe->active_query_count++;
    llvmpipe->dirty |= LP_NEW_QUERY;
 }
@@ -79,26 +120,16 @@ static void
 llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
-   struct llvmpipe_query *sq = llvmpipe_query(q);
+   struct llvmpipe_query *pq = llvmpipe_query(q);
+
+   lp_setup_end_query(llvmpipe->setup, pq);
 
+   assert(llvmpipe->active_query_count);
    llvmpipe->active_query_count--;
-   sq->end = llvmpipe->occlusion_count;
    llvmpipe->dirty |= LP_NEW_QUERY;
 }
 
 
-static boolean
-llvmpipe_get_query_result(struct pipe_context *pipe, 
-                         struct pipe_query *q,
-                         boolean wait,
-                         uint64_t *result )
-{
-   struct llvmpipe_query *sq = llvmpipe_query(q);
-   *result = sq->end - sq->start;
-   return TRUE;
-}
-
-
 void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
 {
    llvmpipe->pipe.create_query = llvmpipe_create_query;
index fa9fcd87139b74d77096073310d71470351ddf55..721c41cb5c956531497705b0a7af2ab45b84c723 100644 (file)
@@ -1,6 +1,7 @@
 /**************************************************************************
  * 
  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2010 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
  * 
  **************************************************************************/
 
-/* Author:
- *    Keith Whitwell
+/* Authors:
+ *    Keith Whitwell, Qicheng Christopher Li, Brian Paul
  */
 
 #ifndef LP_QUERY_H
 #define LP_QUERY_H
 
+#include <limits.h>
+#include "os/os_thread.h"
+#include "lp_limits.h"
+
+
 struct llvmpipe_context;
+
+
+struct llvmpipe_query {
+   uint64_t count[LP_MAX_THREADS];  /**< a counter for each thread */
+   uint64_t result;                 /**< total of all counters */
+
+   pipe_mutex mutex;
+   unsigned num_tiles, tile_count;
+
+   boolean done;
+   boolean binned;  /**< has this query been binned in the scene? */
+};
+
+
 extern void llvmpipe_init_query_funcs(struct llvmpipe_context * );
 
 
index a00a592f2fe120d6fe4b7f272a1244f7eb02daef..6bb868bf1a93fa94214078ad42c24abd3ad1484a 100644 (file)
@@ -34,6 +34,7 @@
 #include "lp_debug.h"
 #include "lp_fence.h"
 #include "lp_perf.h"
+#include "lp_query.h"
 #include "lp_rast.h"
 #include "lp_rast_priv.h"
 #include "lp_tile_soa.h"
@@ -442,7 +443,7 @@ lp_rast_shade_tile(struct lp_rasterizer_task *task,
                                           color,
                                           depth,
                                           INT_MIN, INT_MIN, INT_MIN,
-                                          NULL, NULL, NULL );
+                                          NULL, NULL, NULL, &task->vis_counter);
       }
    }
 }
@@ -502,7 +503,8 @@ void lp_rast_shade_quads( struct lp_rasterizer_task *task,
                                         c1, c2, c3,
                                         inputs->step[0],
                                         inputs->step[1],
-                                        inputs->step[2]);
+                                        inputs->step[2],
+                                       &task->vis_counter);
 }
 
 
@@ -602,6 +604,60 @@ lp_rast_fence(struct lp_rasterizer_task *task,
 }
 
 
+/**
+ * Begin a new occlusion query.
+ * This is a bin command put in all bins.
+ * Called per thread.
+ */
+void
+lp_rast_begin_query(struct lp_rasterizer_task *task,
+                    const union lp_rast_cmd_arg arg)
+{
+   /* Reset the the per-task counter */
+   task->vis_counter = 0;
+}
+
+/**
+ * End the current occlusion query.
+ * This is a bin command put in all bins.
+ * Called per thread.
+ */
+void
+lp_rast_end_query(struct lp_rasterizer_task *task,
+                  const union lp_rast_cmd_arg arg)
+{
+   struct llvmpipe_query *pq = arg.query_obj;
+
+   pipe_mutex_lock(pq->mutex);
+   {
+      /* Accumulate the visible fragment counter from this tile in
+       * the query object.
+       */
+      pq->count[task->thread_index] += task->vis_counter;
+
+      /* check if this is the last tile in the scene */
+      pq->tile_count++;
+      if (pq->tile_count == pq->num_tiles) {
+         uint i;
+
+         /* sum the per-thread counters for the query */
+         pq->result = 0;
+         for (i = 0; i < LP_MAX_THREADS; i++) {
+            pq->result += pq->count[i];
+         }
+
+         /* reset counters (in case this query is re-used in the scene) */
+         memset(pq->count, 0, sizeof(pq->count));
+
+         pq->tile_count = 0;
+         pq->binned = FALSE;
+         pq->done = TRUE;
+      }
+   }
+   pipe_mutex_unlock(pq->mutex);
+}
+
 
 
 /**
@@ -650,6 +706,8 @@ static struct {
    RAST(set_state),
    RAST(store_color),
    RAST(fence),
+   RAST(begin_query),
+   RAST(end_query),
 };
 
 static void
@@ -956,3 +1014,5 @@ lp_rast_get_num_threads( struct lp_rasterizer *rast )
 {
    return rast->num_threads;
 }
+
+
index e2f6f926779e9a3a54b94941384414c77eab1540..881f475189ea30c10026ccc965e68235b481a088 100644 (file)
@@ -157,6 +157,7 @@ union lp_rast_cmd_arg {
    uint8_t clear_color[4];
    unsigned clear_zstencil;
    struct lp_fence *fence;
+   struct llvmpipe_query *query_obj;
 };
 
 
@@ -233,4 +234,11 @@ void lp_rast_store_color( struct lp_rasterizer_task *,
                           const union lp_rast_cmd_arg );
 
 
+void lp_rast_begin_query(struct lp_rasterizer_task *,
+                         const union lp_rast_cmd_arg );
+
+void lp_rast_end_query(struct lp_rasterizer_task *,
+                       const union lp_rast_cmd_arg );
+
+
 #endif
index 5884d12721e248385841676ff192168abf9e7c28..0ceba209e062045a73b14d8a0cc8f3d9bf8234eb 100644 (file)
@@ -59,6 +59,9 @@ struct lp_rasterizer_task
    /** "my" index */
    unsigned thread_index;
 
+   /* occlude counter for visiable pixels */
+   uint32_t vis_counter;
+
    pipe_semaphore work_ready;
    pipe_semaphore work_done;
 };
@@ -221,7 +224,7 @@ lp_rast_shade_quads_all( struct lp_rasterizer_task *task,
                                     color,
                                     depth,
                                     INT_MIN, INT_MIN, INT_MIN,
-                                    NULL, NULL, NULL );
+                                    NULL, NULL, NULL, &task->vis_counter );
 }
 
 
index 0bf75de901a7b7e2f31583caaf8812694b77d04c..de9d4366a8c0a5279e339fb971e460103c63e99e 100644 (file)
@@ -32,6 +32,8 @@
  * lp_setup_flush().
  */
 
+#include <limits.h>
+
 #include "pipe/p_defines.h"
 #include "util/u_framebuffer.h"
 #include "util/u_inlines.h"
 #include "lp_texture.h"
 #include "lp_debug.h"
 #include "lp_fence.h"
+#include "lp_query.h"
 #include "lp_rast.h"
 #include "lp_setup_context.h"
 #include "lp_screen.h"
 #include "lp_state.h"
 #include "state_tracker/sw_winsys.h"
+#include "lp_rast_priv.h"
 
 #include "draw/draw_context.h"
 #include "draw/draw_vbuf.h"
@@ -856,3 +860,40 @@ fail:
    return NULL;
 }
 
+
+/**
+ * Put a BeginQuery command into all bins.
+ */
+void
+lp_setup_begin_query(struct lp_setup_context *setup,
+                     struct llvmpipe_query *pq)
+{
+   struct lp_scene * scene = lp_setup_get_current_scene(setup);
+   union lp_rast_cmd_arg cmd_arg;
+
+   /* init the query to its beginning state */
+   pq->done = FALSE;
+   pq->tile_count = 0;
+   pq->num_tiles = scene->tiles_x * scene->tiles_y;
+   assert(pq->num_tiles > 0);
+
+   memset(pq->count, 0, sizeof(pq->count));  /* reset all counters */
+
+   cmd_arg.query_obj = pq;
+   lp_scene_bin_everywhere(scene, lp_rast_begin_query, cmd_arg);
+   pq->binned = TRUE;
+}
+
+
+/**
+ * Put an EndQuery command into all bins.
+ */
+void
+lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
+{
+   struct lp_scene * scene = lp_setup_get_current_scene(setup);
+   union lp_rast_cmd_arg cmd_arg;
+
+   cmd_arg.query_obj = pq;
+   lp_scene_bin_everywhere(scene, lp_rast_end_query, cmd_arg);
+}
index e10d37d8d0430089cddc051c6c675aee100e1dc3..10db03b9c69798d738a7f8ea7684a7fa5347d3d5 100644 (file)
@@ -53,12 +53,15 @@ struct lp_shader_input {
 };
 
 struct pipe_resource;
+struct pipe_query;
 struct pipe_surface;
 struct pipe_blend_color;
 struct pipe_screen;
 struct pipe_framebuffer_state;
 struct lp_fragment_shader;
 struct lp_jit_context;
+struct llvmpipe_query;
+
 
 struct lp_setup_context *
 lp_setup_create( struct pipe_context *pipe,
@@ -140,5 +143,12 @@ void
 lp_setup_set_vertex_info( struct lp_setup_context *setup, 
                           struct vertex_info *info );
 
+void
+lp_setup_begin_query(struct lp_setup_context *setup,
+                     struct llvmpipe_query *pq);
+
+void
+lp_setup_end_query(struct lp_setup_context *setup,
+                   struct llvmpipe_query *pq);
 
 #endif
index 18143807c915136af46c8b588a5428d0b7d1808f..848cb49f91923dbac976051ba8a47283fd21306a 100644 (file)
@@ -73,6 +73,7 @@ struct lp_fragment_shader_variant_key
    unsigned nr_cbufs:8;
    unsigned flatshade:1;
    unsigned scissor:1;
+   unsigned occlusion_count:1;
 
    struct {
       ubyte colormask;
index 113d77ab7880003f73c9e856b5a8959f96b65dbb..2edfcb28ce6dafb0baa70426ba5d43256357f369 100644 (file)
@@ -163,7 +163,8 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                           LP_NEW_DEPTH_STENCIL_ALPHA |
                           LP_NEW_RASTERIZER |
                           LP_NEW_SAMPLER |
-                          LP_NEW_SAMPLER_VIEW))
+                          LP_NEW_SAMPLER_VIEW |
+                          LP_NEW_QUERY))
       llvmpipe_update_fs( llvmpipe );
 
    if (llvmpipe->dirty & LP_NEW_BLEND_COLOR)
index 5f861d6ca4d1479b9b9063a2ea513f1da91b31c4..6c81114482d8d9148b7616ab63eae6443015f4e0 100644 (file)
@@ -148,7 +148,8 @@ generate_depth_stencil(LLVMBuilderRef builder,
                        LLVMValueRef stencil_refs[2],
                        LLVMValueRef src,
                        LLVMValueRef dst_ptr,
-                       LLVMValueRef facing)
+                       LLVMValueRef facing,
+                       LLVMValueRef counter)
 {
    const struct util_format_description *format_desc;
    struct lp_type dst_type;
@@ -195,7 +196,8 @@ generate_depth_stencil(LLVMBuilderRef builder,
                                stencil_refs,
                                src,
                                dst_ptr,
-                               facing);
+                               facing,
+                               counter);
 }
 
 
@@ -400,7 +402,8 @@ generate_fs(struct llvmpipe_context *lp,
             LLVMValueRef c2,
             LLVMValueRef step0_ptr,
             LLVMValueRef step1_ptr,
-            LLVMValueRef step2_ptr)
+            LLVMValueRef step2_ptr,
+            LLVMValueRef counter)
 {
    const struct tgsi_token *tokens = shader->base.tokens;
    LLVMTypeRef vec_type;
@@ -466,7 +469,7 @@ generate_fs(struct llvmpipe_context *lp,
    if (early_depth_stencil_test)
       generate_depth_stencil(builder, key,
                              type, &mask,
-                             stencil_refs, z, depth_ptr, facing);
+                             stencil_refs, z, depth_ptr, facing, counter);
 
    lp_build_tgsi_soa(builder, tokens, type, &mask,
                      consts_ptr, interp->pos, interp->inputs,
@@ -513,7 +516,7 @@ generate_fs(struct llvmpipe_context *lp,
    if (!early_depth_stencil_test)
       generate_depth_stencil(builder, key,
                              type, &mask,
-                             stencil_refs, z, depth_ptr, facing);
+                             stencil_refs, z, depth_ptr, facing, counter);
 
    lp_build_mask_end(&mask);
 
@@ -620,7 +623,7 @@ generate_fragment(struct llvmpipe_context *lp,
    LLVMTypeRef fs_elem_type;
    LLVMTypeRef fs_int_vec_type;
    LLVMTypeRef blend_vec_type;
-   LLVMTypeRef arg_types[15];
+   LLVMTypeRef arg_types[16];
    LLVMTypeRef func_type;
    LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type();
    LLVMValueRef context_ptr;
@@ -631,7 +634,7 @@ generate_fragment(struct llvmpipe_context *lp,
    LLVMValueRef dady_ptr;
    LLVMValueRef color_ptr_ptr;
    LLVMValueRef depth_ptr;
-   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
+   LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr, counter = NULL;
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
    LLVMValueRef x0;
@@ -696,6 +699,7 @@ generate_fragment(struct llvmpipe_context *lp,
    arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step0 */
    arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step1 */
    arg_types[14] = LLVMPointerType(int32_vec4_type, 0);/* step2 */
+   arg_types[15] = LLVMPointerType(LLVMInt32Type(), 0);/* counter */
 
    func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
 
@@ -743,6 +747,11 @@ generate_fragment(struct llvmpipe_context *lp,
    lp_build_name(step1_ptr, "step1");
    lp_build_name(step2_ptr, "step2");
 
+   if (key->occlusion_count) {
+      counter = LLVMGetParam(function, 15);
+      lp_build_name(counter, "counter");
+   }
+
    /*
     * Function body
     */
@@ -787,7 +796,7 @@ generate_fragment(struct llvmpipe_context *lp,
                   facing,
                   do_tri_test,
                   c0, c1, c2,
-                  step0_ptr, step1_ptr, step2_ptr);
+                  step0_ptr, step1_ptr, step2_ptr, counter);
 
       for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
         for(chan = 0; chan < NUM_CHANNELS; ++chan)
@@ -1123,6 +1132,9 @@ make_variant_key(struct llvmpipe_context *lp,
 
    key->flatshade = lp->rasterizer->flatshade;
    key->scissor = lp->rasterizer->scissor;
+   if (lp->active_query_count) {
+      key->occlusion_count = TRUE;
+   }
 
    if (lp->framebuffer.nr_cbufs) {
       memcpy(&key->blend, lp->blend, sizeof key->blend);