From c157cfc6376f7469ab272b18868183e5ff9ac754 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 6 Oct 2008 17:34:51 -0700 Subject: i965: Add ARB_occlusion_query support. --- src/mesa/drivers/dri/i965/Makefile | 1 + src/mesa/drivers/dri/i965/brw_context.c | 4 + src/mesa/drivers/dri/i965/brw_context.h | 30 +++- src/mesa/drivers/dri/i965/brw_draw.c | 2 +- src/mesa/drivers/dri/i965/brw_draw_upload.c | 3 + src/mesa/drivers/dri/i965/brw_queryobj.c | 263 ++++++++++++++++++++++++++++ src/mesa/drivers/dri/i965/brw_vtbl.c | 10 ++ src/mesa/drivers/dri/intel/intel_context.c | 51 +----- src/mesa/drivers/dri/intel/intel_reg.h | 19 ++ 9 files changed, 331 insertions(+), 52 deletions(-) create mode 100644 src/mesa/drivers/dri/i965/brw_queryobj.c (limited to 'src') diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile index c2d555cd0c..7bc16a02c8 100644 --- a/src/mesa/drivers/dri/i965/Makefile +++ b/src/mesa/drivers/dri/i965/Makefile @@ -51,6 +51,7 @@ DRIVER_SOURCES = \ brw_metaops.c \ brw_misc_state.c \ brw_program.c \ + brw_queryobj.c \ brw_sf.c \ brw_sf_emit.c \ brw_sf_state.c \ diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index 5f60477176..474158b484 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -33,6 +33,7 @@ #include "main/imports.h" #include "main/api_noop.h" #include "main/vtxfmt.h" +#include "main/simple_list.h" #include "shader/shader_api.h" #include "brw_context.h" @@ -68,6 +69,7 @@ static void brwInitDriverFunctions( struct dd_function_table *functions ) brwInitFragProgFuncs( functions ); brwInitProgFuncs( functions ); + brw_init_queryobj_functions(functions); } @@ -150,6 +152,8 @@ GLboolean brwCreateContext( const __GLcontextModes *mesaVis, ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + make_empty_list(&brw->query.active_head); + brw_draw_init( brw ); return GL_TRUE; diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index 8bddc9da40..1c6a0dede0 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -410,7 +410,22 @@ struct brw_tnl_cache { GLuint size, n_items; }; +struct brw_query_object { + struct gl_query_object Base; + /** Doubly linked list of active query objects in the context. */ + struct brw_query_object *prev, *next; + + /** Last query BO associated with this query. */ + dri_bo *bo; + /** First index in bo with query data for this object. */ + int first_index; + /** Last index in bo with query data for this object. */ + int last_index; + + /* Total count of pixels from previous BOs */ + unsigned int count; +}; struct brw_context { @@ -626,7 +641,12 @@ struct brw_context dri_bo *vp_bo; } cc; - + struct { + struct brw_query_object active_head; + dri_bo *bo; + int index; + GLboolean active; + } query; /* Used to give every program string a unique id */ GLuint program_id; @@ -651,7 +671,13 @@ GLboolean brwCreateContext( const __GLcontextModes *mesaVis, __DRIcontextPrivate *driContextPriv, void *sharedContextPrivate); - +/*====================================================================== + * brw_queryobj.c + */ +void brw_init_queryobj_functions(struct dd_function_table *functions); +void brw_prepare_query_begin(struct brw_context *brw); +void brw_emit_query_begin(struct brw_context *brw); +void brw_emit_query_end(struct brw_context *brw); /*====================================================================== * brw_state.c diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c index 39ce8eb4b6..6c71b4abcf 100644 --- a/src/mesa/drivers/dri/i965/brw_draw.c +++ b/src/mesa/drivers/dri/i965/brw_draw.c @@ -382,7 +382,6 @@ void brw_draw_prims( GLcontext *ctx, return; } - /* Make a first attempt at drawing: */ retval = brw_try_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); @@ -395,6 +394,7 @@ void brw_draw_prims( GLcontext *ctx, _swsetup_Wakeup(ctx); _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); } + } void brw_draw_init( struct brw_context *brw ) diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c index cc3d9396ac..7b88b5eaa1 100644 --- a/src/mesa/drivers/dri/i965/brw_draw_upload.c +++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c @@ -415,6 +415,8 @@ static void brw_prepare_vertices(struct brw_context *brw) copy_array_to_vbo_array(brw, upload[i], upload[i]->element_size); } } + + brw_prepare_query_begin(brw); } static void brw_emit_vertices(struct brw_context *brw) @@ -435,6 +437,7 @@ static void brw_emit_vertices(struct brw_context *brw) enabled[nr_enabled++] = input; } + brw_emit_query_begin(brw); /* Now emit VB and VEP state packets. * diff --git a/src/mesa/drivers/dri/i965/brw_queryobj.c b/src/mesa/drivers/dri/i965/brw_queryobj.c new file mode 100644 index 0000000000..a1a1353dee --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_queryobj.c @@ -0,0 +1,263 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt + * + */ + +/** @file support for ARB_query_object + * + * ARB_query_object is implemented by using the PIPE_CONTROL command to stall + * execution on the completion of previous depth tests, and write the + * current PS_DEPTH_COUNT to a buffer object. + * + * We use before and after counts when drawing during a query so that + * we don't pick up other clients' query data in ours. To reduce overhead, + * a single BO is used to record the query data for all active queries at + * once. This also gives us a simple bound on how much batchbuffer space is + * required for handling queries, so that we can be sure that we won't + * have to emit a batchbuffer without getting the ending PS_DEPTH_COUNT. + */ +#include "main/simple_list.h" +#include "main/imports.h" + +#include "brw_context.h" +#include "intel_batchbuffer.h" +#include "intel_reg.h" + +/** Waits on the query object's BO and totals the results for this query */ +static void +brw_queryobj_get_results(struct brw_query_object *query) +{ + int i; + uint64_t *results; + + if (query->bo == NULL) + return; + + /* Map and count the pixels from the current query BO */ + dri_bo_map(query->bo, GL_FALSE); + results = query->bo->virtual; + for (i = query->first_index; i <= query->last_index; i++) { + query->Base.Result += results[i * 2 + 1] - results[i * 2]; + } + dri_bo_unmap(query->bo); + + dri_bo_unreference(query->bo); + query->bo = NULL; +} + +static struct gl_query_object * +brw_new_query_object(GLcontext *ctx, GLuint id) +{ + struct brw_query_object *query; + + query = _mesa_calloc(sizeof(struct brw_query_object)); + + query->Base.Id = id; + query->Base.Result = 0; + query->Base.Active = GL_FALSE; + query->Base.Ready = GL_TRUE; + + return &query->Base; +} + +static void +brw_delete_query(GLcontext *ctx, struct gl_query_object *q) +{ + struct brw_query_object *query = (struct brw_query_object *)q; + + dri_bo_unreference(query->bo); + _mesa_free(query); +} + +static void +brw_begin_query(GLcontext *ctx, struct gl_query_object *q) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_context *intel = intel_context(ctx); + struct brw_query_object *query = (struct brw_query_object *)q; + + /* Reset our driver's tracking of query state. */ + dri_bo_unreference(query->bo); + query->bo = NULL; + query->first_index = -1; + query->last_index = -1; + + insert_at_head(&brw->query.active_head, query); + intel->stats_wm++; +} + +/** + * Begin the ARB_occlusion_query query on a query object. + */ +static void +brw_end_query(GLcontext *ctx, struct gl_query_object *q) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_context *intel = intel_context(ctx); + struct brw_query_object *query = (struct brw_query_object *)q; + + /* Flush the batchbuffer in case it has writes to our query BO. + * Have later queries write to a new query BO so that further rendering + * doesn't delay the collection of our results. + */ + if (query->bo) { + brw_emit_query_end(brw); + intel_batchbuffer_flush(intel->batch); + + dri_bo_unreference(brw->query.bo); + brw->query.bo = NULL; + } + + remove_from_list(query); + + intel->stats_wm--; +} + +static void brw_wait_query(GLcontext *ctx, struct gl_query_object *q) +{ + struct brw_query_object *query = (struct brw_query_object *)q; + + brw_queryobj_get_results(query); + query->Base.Ready = GL_TRUE; +} + +static void brw_check_query(GLcontext *ctx, struct gl_query_object *q) +{ + /* XXX: Need to expose dri_bo_is_idle from bufmgr. */ +#if 0 + struct brw_query_object *query = (struct brw_query_object *)q; + + if (dri_bo_is_idle(query->bo)) { + brw_queryobj_get_results(query); + query->Base.Ready = GL_TRUE; + } +#else + brw_wait_query(ctx, q); +#endif +} + +/** Called to set up the query BO and account for its aperture space */ +void +brw_prepare_query_begin(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + dri_bo *aper_array[] = { + intel->batch->buf, + brw->query.bo, + }; + + /* Skip if we're not doing any queries. */ + if (is_empty_list(&brw->query.active_head)) + return; + + /* Get a new query BO if we're going to need it. */ + if (brw->query.bo == NULL || + brw->query.index * 2 + 1 >= 4096 / sizeof(uint64_t)) { + dri_bo_unreference(brw->query.bo); + brw->query.bo = NULL; + + brw->query.bo = dri_bo_alloc(intel->bufmgr, "query", 4096, 1); + brw->query.index = 0; + } + + if (dri_bufmgr_check_aperture_space(aper_array, ARRAY_SIZE(aper_array))) + intel_batchbuffer_flush(intel->batch); +} + +/** Called just before primitive drawing to get a beginning PS_DEPTH_COUNT. */ +void +brw_emit_query_begin(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + struct brw_query_object *query; + + /* Skip if we're not doing any queries, or we've emitted the start. */ + if (brw->query.active || is_empty_list(&brw->query.active_head)) + return; + + BEGIN_BATCH(4, IGNORE_CLIPRECTS); + OUT_BATCH(_3DSTATE_PIPE_CONTROL | + PIPE_CONTROL_DEPTH_STALL | + PIPE_CONTROL_WRITE_DEPTH_COUNT); + /* This object could be mapped cacheable, but we don't have an exposed + * mechanism to support that. Since it's going uncached, tell GEM that + * we're writing to it. The usual clflush should be all that's required + * to pick up the results. + */ + OUT_RELOC(brw->query.bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + PIPE_CONTROL_GLOBAL_GTT_WRITE | + ((brw->query.index * 2) * sizeof(uint64_t))); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + + foreach(query, &brw->query.active_head) { + if (query->bo != brw->query.bo) { + if (query->bo != NULL) + brw_queryobj_get_results(query); + dri_bo_reference(brw->query.bo); + query->bo = brw->query.bo; + query->first_index = brw->query.index; + } + query->last_index = brw->query.index; + } + brw->query.active = GL_TRUE; +} + +/** Called at batchbuffer flush to get an ending PS_DEPTH_COUNT */ +void +brw_emit_query_end(struct brw_context *brw) +{ + struct intel_context *intel = &brw->intel; + + if (!brw->query.active) + return; + + BEGIN_BATCH(4, IGNORE_CLIPRECTS); + OUT_BATCH(_3DSTATE_PIPE_CONTROL | + PIPE_CONTROL_DEPTH_STALL | + PIPE_CONTROL_WRITE_DEPTH_COUNT); + OUT_RELOC(brw->query.bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + PIPE_CONTROL_GLOBAL_GTT_WRITE | + ((brw->query.index * 2 + 1) * sizeof(uint64_t))); + OUT_BATCH(0); + OUT_BATCH(0); + ADVANCE_BATCH(); + + brw->query.active = GL_FALSE; + brw->query.index++; +} + +void brw_init_queryobj_functions(struct dd_function_table *functions) +{ + functions->NewQueryObject = brw_new_query_object; + functions->DeleteQuery = brw_delete_query; + functions->BeginQuery = brw_begin_query; + functions->EndQuery = brw_end_query; + functions->CheckQuery = brw_check_query; + functions->WaitQuery = brw_wait_query; +} diff --git a/src/mesa/drivers/dri/i965/brw_vtbl.c b/src/mesa/drivers/dri/i965/brw_vtbl.c index cd074dfed6..a64e437860 100644 --- a/src/mesa/drivers/dri/i965/brw_vtbl.c +++ b/src/mesa/drivers/dri/i965/brw_vtbl.c @@ -120,6 +120,15 @@ static void brw_set_draw_region( struct intel_context *intel, brw->state.nr_draw_regions = num_regions; } +/* called from intel_batchbuffer_flush and children before sending a + * batchbuffer off. + */ +static void brw_finish_batch(struct intel_context *intel) +{ + struct brw_context *brw = brw_context(&intel->ctx); + + brw_emit_query_end(brw); +} /* called from intelFlushBatchLocked */ @@ -218,6 +227,7 @@ void brwInitVtbl( struct brw_context *brw ) brw->intel.vtbl.note_fence = brw_note_fence; brw->intel.vtbl.note_unlock = brw_note_unlock; brw->intel.vtbl.new_batch = brw_new_batch; + brw->intel.vtbl.finish_batch = brw_finish_batch; brw->intel.vtbl.destroy = brw_destroy_context; brw->intel.vtbl.set_draw_region = brw_set_draw_region; brw->intel.vtbl.flush_cmd = brw_flush_cmd; diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c index 9dc32e487f..e6c0d3175e 100644 --- a/src/mesa/drivers/dri/intel/intel_context.c +++ b/src/mesa/drivers/dri/intel/intel_context.c @@ -394,6 +394,7 @@ static const struct dri_extension brw_extensions[] = { { "GL_ARB_fragment_program", NULL }, { "GL_ARB_fragment_program_shadow", NULL }, { "GL_ARB_fragment_shader", NULL }, + { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions }, { "GL_ARB_point_sprite", NULL }, { "GL_ARB_shader_objects", GL_ARB_shader_objects_functions }, { "GL_ARB_shading_language_100", GL_VERSION_2_0_functions }, @@ -407,12 +408,9 @@ static const struct dri_extension brw_extensions[] = { { NULL, NULL } }; -#ifdef I915_MMIO_READ -static const struct dri_extension arb_oc_extensions[] = { - { "GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions }, +static const struct dri_extension arb_oq_extensions[] = { { NULL, NULL } }; -#endif static const struct dri_extension ttm_extensions[] = { { "GL_ARB_pixel_buffer_object", NULL }, @@ -437,13 +435,6 @@ void intelInitExtensions(GLcontext *ctx, GLboolean enable_imaging) if (intel == NULL || intel->ttm) driInitExtensions(ctx, ttm_extensions, GL_FALSE); -#ifdef I915_MMIO_READ - if (intel == NULL || - (IS_965(intel->intelScreen->deviceID) && - intel->intelScreen->drmMinor >= 8)) - driInitExtensions(ctx, arb_oc_extensions, GL_FALSE); -#endif - if (intel == NULL || IS_965(intel->intelScreen->deviceID)) driInitExtensions(ctx, brw_extensions, GL_FALSE); } @@ -540,39 +531,6 @@ intelFinish(GLcontext * ctx) } } -#ifdef I915_MMIO_READ -static void -intelBeginQuery(GLcontext *ctx, struct gl_query_object *q) -{ - struct intel_context *intel = intel_context( ctx ); - struct drm_i915_mmio io = { - .read_write = I915_MMIO_READ, - .reg = MMIO_REGS_PS_DEPTH_COUNT, - .data = &q->Result - }; - intel->stats_wm++; - intelFinish(&intel->ctx); - drmCommandWrite(intel->driFd, DRM_I915_MMIO, &io, sizeof(io)); -} - -static void -intelEndQuery(GLcontext *ctx, struct gl_query_object *q) -{ - struct intel_context *intel = intel_context( ctx ); - GLuint64EXT tmp; - struct drm_i915_mmio io = { - .read_write = I915_MMIO_READ, - .reg = MMIO_REGS_PS_DEPTH_COUNT, - .data = &tmp - }; - intelFinish(&intel->ctx); - drmCommandWrite(intel->driFd, DRM_I915_MMIO, &io, sizeof(io)); - q->Result = tmp - q->Result; - q->Ready = GL_TRUE; - intel->stats_wm--; -} -#endif - void intelInitDriverFunctions(struct dd_function_table *functions) { @@ -589,11 +547,6 @@ intelInitDriverFunctions(struct dd_function_table *functions) functions->CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; functions->CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; -#ifdef I915_MMIO_READ - functions->BeginQuery = intelBeginQuery; - functions->EndQuery = intelEndQuery; -#endif - intelInitTextureFuncs(functions); intelInitStateFuncs(functions); intelInitBufferFuncs(functions); diff --git a/src/mesa/drivers/dri/intel/intel_reg.h b/src/mesa/drivers/dri/intel/intel_reg.h index 96af7e1a03..c21f408093 100644 --- a/src/mesa/drivers/dri/intel/intel_reg.h +++ b/src/mesa/drivers/dri/intel/intel_reg.h @@ -44,6 +44,25 @@ #define _3DSTATE_LOAD_STATE_IMMEDIATE_1 (CMD_3D | (0x1d<<24) | (0x04<<16)) #define I1_LOAD_S(n) (1<<(4+n)) +/** @{ + * + * PIPE_CONTROL operation, a combination MI_FLUSH and register write with + * additional flushing control. + */ +#define _3DSTATE_PIPE_CONTROL (CMD_3D | (3 << 27) | (2 << 24) | 2) +#define PIPE_CONTROL_NO_WRITE (0 << 14) +#define PIPE_CONTROL_WRITE_IMMEDIATE (1 << 14) +#define PIPE_CONTROL_WRITE_DEPTH_COUNT (2 << 14) +#define PIPE_CONTROL_WRITE_TIMESTAMP (3 << 14) +#define PIPE_CONTROL_DEPTH_STALL (1 << 13) +#define PIPE_CONTROL_WRITE_FLUSH (1 << 12) +#define PIPE_CONTROL_INSTRUCTION_FLUSH (1 << 11) +#define PIPE_CONTROL_INTERRUPT_ENABLE (1 << 8) +#define PIPE_CONTROL_PPGTT_WRITE (0 << 2) +#define PIPE_CONTROL_GLOBAL_GTT_WRITE (1 << 2) + +/** @} */ + /** @{ * 915 definitions */ -- cgit v1.2.3