llvmpipe: implement occlusion query

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>
This commit is contained in:
Qicheng Christopher Li
2010-05-06 11:45:42 -06:00
committed by Brian Paul
parent f587615e13
commit 86afe8250e
14 changed files with 287 additions and 60 deletions
+42 -1
View 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);
}
+2 -1
View 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 */
+1 -5
View 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];
+4 -2
View 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
+68 -37
View 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
@@ -18,15 +19,15 @@
* 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"
@@ -34,12 +35,10 @@
#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,39 +50,25 @@ 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);
}
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;
llvmpipe->active_query_count++;
llvmpipe->dirty |= LP_NEW_QUERY;
}
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);
llvmpipe->active_query_count--;
sq->end = llvmpipe->occlusion_count;
llvmpipe->dirty |= LP_NEW_QUERY;
struct llvmpipe_query *pq = llvmpipe_query(q);
pipe_mutex_destroy(pq->mutex);
FREE(pq);
}
@@ -93,9 +78,55 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
boolean wait,
uint64_t *result )
{
struct llvmpipe_query *sq = llvmpipe_query(q);
*result = sq->end - sq->start;
return TRUE;
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;
}
static void
llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
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;
}
static void
llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
struct llvmpipe_query *pq = llvmpipe_query(q);
lp_setup_end_query(llvmpipe->setup, pq);
assert(llvmpipe->active_query_count);
llvmpipe->active_query_count--;
llvmpipe->dirty |= LP_NEW_QUERY;
}
+22 -2
View 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
@@ -25,14 +26,33 @@
*
**************************************************************************/
/* 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 * );
+62 -2
View 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;
}
+8
View 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
+4 -1
View 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 );
}
+41
View 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"
@@ -43,11 +45,13 @@
#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);
}
+10
View 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
+1
View 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;
@@ -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)
+20 -8
View 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);