#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"
}
+/**
+ * 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.
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;
if (depth->enabled && stencil[0].enabled)
lp_build_mask_update(mask, z_pass);
+
+ if (counter)
+ lp_build_occlusion_count(builder, type, mask->value, counter);
}
LLVMValueRef stencil_refs[2],
LLVMValueRef zs_src,
LLVMValueRef zs_dst_ptr,
- LLVMValueRef facing);
+ LLVMValueRef facing,
+ LLVMValueRef counter);
#endif /* !LP_BLD_DEPTH_H */
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];
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 */
const int32_t c3,
const int32_t *step1,
const int32_t *step2,
- const int32_t *step3);
+ const int32_t *step3,
+ uint32_t *counter);
void
/**************************************************************************
*
* 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 )
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;
}
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;
}
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;
/**************************************************************************
*
* 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 * );
#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"
color,
depth,
INT_MIN, INT_MIN, INT_MIN,
- NULL, NULL, NULL );
+ NULL, NULL, NULL, &task->vis_counter);
}
}
}
c1, c2, c3,
inputs->step[0],
inputs->step[1],
- inputs->step[2]);
+ inputs->step[2],
+ &task->vis_counter);
}
}
+/**
+ * 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);
+}
+
/**
RAST(set_state),
RAST(store_color),
RAST(fence),
+ RAST(begin_query),
+ RAST(end_query),
};
static void
{
return rast->num_threads;
}
+
+
uint8_t clear_color[4];
unsigned clear_zstencil;
struct lp_fence *fence;
+ struct llvmpipe_query *query_obj;
};
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
/** "my" index */
unsigned thread_index;
+ /* occlude counter for visiable pixels */
+ uint32_t vis_counter;
+
pipe_semaphore work_ready;
pipe_semaphore work_done;
};
color,
depth,
INT_MIN, INT_MIN, INT_MIN,
- NULL, NULL, NULL );
+ NULL, NULL, NULL, &task->vis_counter );
}
* 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"
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);
+}
};
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,
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
unsigned nr_cbufs:8;
unsigned flatshade:1;
unsigned scissor:1;
+ unsigned occlusion_count:1;
struct {
ubyte colormask;
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)
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;
stencil_refs,
src,
dst_ptr,
- facing);
+ facing,
+ counter);
}
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;
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,
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);
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;
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;
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);
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
*/
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)
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);