From 09fbb3837b6aa5dfc6c94f41ab5443820177c569 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 11 Sep 2007 16:01:17 -0600 Subject: Implement query object interface. This replaces the temporary occlusion counter functions we had before. Added new ctx->Driver.WaitQuery() function which should block until the result is ready. Sketch out some code for vertex transformation feedback counters. --- src/mesa/drivers/common/driverfuncs.c | 5 +- src/mesa/main/dd.h | 6 +- src/mesa/main/mtypes.h | 9 +-- src/mesa/main/queryobj.c | 95 ++++++++++++++++-------------- src/mesa/main/queryobj.h | 14 ++++- src/mesa/pipe/failover/fo_context.c | 4 +- src/mesa/pipe/i915simple/i915_context.c | 21 ++++++- src/mesa/pipe/p_context.h | 9 +-- src/mesa/pipe/p_defines.h | 8 +++ src/mesa/pipe/p_state.h | 10 ++++ src/mesa/pipe/softpipe/sp_context.c | 35 ++++++++--- src/mesa/pipe/softpipe/sp_context.h | 7 ++- src/mesa/pipe/softpipe/sp_quad_occlusion.c | 10 ++-- src/mesa/state_tracker/st_cb_queryobj.c | 83 +++++++++++++++++++++++--- 14 files changed, 232 insertions(+), 84 deletions(-) (limited to 'src/mesa') diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c index 500dbb2545..96e5037fa5 100644 --- a/src/mesa/drivers/common/driverfuncs.c +++ b/src/mesa/drivers/common/driverfuncs.c @@ -224,8 +224,9 @@ _mesa_init_driver_functions(struct dd_function_table *driver) /* query objects */ driver->NewQueryObject = _mesa_new_query_object; - driver->BeginQuery = NULL; - driver->EndQuery = NULL; + driver->BeginQuery = _mesa_begin_query; + driver->EndQuery = _mesa_end_query; + driver->WaitQuery = _mesa_wait_query; /* APPLE_vertex_array_object */ driver->NewArrayObject = _mesa_new_array_object; diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 582e0c334d..f089fcb48f 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -811,9 +811,9 @@ struct dd_function_table { */ /*@{*/ struct gl_query_object * (*NewQueryObject)(GLcontext *ctx, GLuint id); - void (*BeginQuery)(GLcontext *ctx, GLenum target, - struct gl_query_object *q); - void (*EndQuery)(GLcontext *ctx, GLenum target, struct gl_query_object *q); + void (*BeginQuery)(GLcontext *ctx, struct gl_query_object *q); + void (*EndQuery)(GLcontext *ctx, struct gl_query_object *q); + void (*WaitQuery)(GLcontext *ctx, struct gl_query_object *q); /*@}*/ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 0a64e0c58c..514170dbcf 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2085,10 +2085,11 @@ struct gl_ati_fragment_shader_state */ struct gl_query_object { - GLuint Id; - GLuint64EXT Result; /* the counter */ - GLboolean Active; /* inside Begin/EndQuery */ - GLboolean Ready; /* result is ready */ + GLenum Target; /**< The query target, when active */ + GLuint Id; /**< hash table ID/name */ + GLuint64EXT Result; /**< the counter */ + GLboolean Active; /**< inside Begin/EndQuery */ + GLboolean Ready; /**< result is ready? */ }; diff --git a/src/mesa/main/queryobj.c b/src/mesa/main/queryobj.c index 0e59ba615a..688d0fc7bc 100644 --- a/src/mesa/main/queryobj.c +++ b/src/mesa/main/queryobj.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 6.5.1 + * Version: 7.1 * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -53,6 +53,42 @@ _mesa_new_query_object(GLcontext *ctx, GLuint id) } +/** + * Begin a query. Software driver fallback. + * Called via ctx->Driver.BeginQuery(). + */ +void +_mesa_begin_query(GLcontext *ctx, struct gl_query_object *q) +{ + /* no-op */ +} + + +/** + * End a query. Software driver fallback. + * Called via ctx->Driver.EndQuery(). + */ +void +_mesa_end_query(GLcontext *ctx, struct gl_query_object *q) +{ + q->Ready = GL_TRUE; +} + + +/** + * Wait for query to complete. Software driver fallback. + * Called via ctx->Driver.WaitQuery(). + */ +void +_mesa_wait_query(GLcontext *ctx, struct gl_query_object *q) +{ + /* For software drivers, _mesa_end_query() should have completed the query. + * For real hardware, implement a proper WaitQuery() driver function. + */ + assert(q->Ready); +} + + /** * Delete an occlusion query object. * Not removed from hash table here. @@ -61,7 +97,7 @@ _mesa_new_query_object(GLcontext *ctx, GLuint id) static void delete_query_object(struct gl_query_object *q) { - FREE(q); + _mesa_free(q); } @@ -216,6 +252,7 @@ _mesa_BeginQueryARB(GLenum target, GLuint id) } } + q->Target = target; q->Active = GL_TRUE; q->Result = 0; q->Ready = GL_FALSE; @@ -229,9 +266,7 @@ _mesa_BeginQueryARB(GLenum target, GLuint id) } #endif - if (ctx->Driver.BeginQuery) { - ctx->Driver.BeginQuery(ctx, target, q); - } + ctx->Driver.BeginQuery(ctx, q); } @@ -275,13 +310,7 @@ _mesa_EndQueryARB(GLenum target) } q->Active = GL_FALSE; - if (ctx->Driver.EndQuery) { - ctx->Driver.EndQuery(ctx, target, q); - } - else { - /* if we're using software rendering/querying */ - q->Ready = GL_TRUE; - } + ctx->Driver.EndQuery(ctx, q); } @@ -346,13 +375,8 @@ _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) switch (pname) { case GL_QUERY_RESULT_ARB: - while (!q->Ready) { - /* Wait for the query to finish! */ - /* If using software rendering, the result will always be ready - * by time we get here. Otherwise, we must be using hardware! - */ - ASSERT(ctx->Driver.EndQuery); - } + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); /* if result is too large for returned type, clamp to max value */ if (q->Result > 0x7fffffff) { *params = 0x7fffffff; @@ -362,7 +386,6 @@ _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) } break; case GL_QUERY_RESULT_AVAILABLE_ARB: - /* XXX revisit when we have a hardware implementation! */ *params = q->Ready; break; default: @@ -390,13 +413,8 @@ _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) switch (pname) { case GL_QUERY_RESULT_ARB: - while (!q->Ready) { - /* Wait for the query to finish! */ - /* If using software rendering, the result will always be ready - * by time we get here. Otherwise, we must be using hardware! - */ - ASSERT(ctx->Driver.EndQuery); - } + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); /* if result is too large for returned type, clamp to max value */ if (q->Result > 0xffffffff) { *params = 0xffffffff; @@ -406,7 +424,6 @@ _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) } break; case GL_QUERY_RESULT_AVAILABLE_ARB: - /* XXX revisit when we have a hardware implementation! */ *params = q->Ready; break; default: @@ -439,17 +456,11 @@ _mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) switch (pname) { case GL_QUERY_RESULT_ARB: - while (!q->Ready) { - /* Wait for the query to finish! */ - /* If using software rendering, the result will always be ready - * by time we get here. Otherwise, we must be using hardware! - */ - ASSERT(ctx->Driver.EndQuery); - } + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); *params = q->Result; break; case GL_QUERY_RESULT_AVAILABLE_ARB: - /* XXX revisit when we have a hardware implementation! */ *params = q->Ready; break; default: @@ -480,17 +491,11 @@ _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) switch (pname) { case GL_QUERY_RESULT_ARB: - while (!q->Ready) { - /* Wait for the query to finish! */ - /* If using software rendering, the result will always be ready - * by time we get here. Otherwise, we must be using hardware! - */ - ASSERT(ctx->Driver.EndQuery); - } + if (!q->Ready) + ctx->Driver.WaitQuery(ctx, q); *params = q->Result; break; case GL_QUERY_RESULT_AVAILABLE_ARB: - /* XXX revisit when we have a hardware implementation! */ *params = q->Ready; break; default: diff --git a/src/mesa/main/queryobj.h b/src/mesa/main/queryobj.h index ada8cf8356..d466aae652 100644 --- a/src/mesa/main/queryobj.h +++ b/src/mesa/main/queryobj.h @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 6.5 + * Version: 7.1 * - * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,6 +36,16 @@ _mesa_init_query(GLcontext *ctx); extern void _mesa_free_query_data(GLcontext *ctx); +extern void +_mesa_begin_query(GLcontext *ctx, struct gl_query_object *q); + +extern void +_mesa_end_query(GLcontext *ctx, struct gl_query_object *q); + +extern void +_mesa_wait_query(GLcontext *ctx, struct gl_query_object *q); + + extern void GLAPIENTRY _mesa_GenQueriesARB(GLsizei n, GLuint *ids); diff --git a/src/mesa/pipe/failover/fo_context.c b/src/mesa/pipe/failover/fo_context.c index b88f1b466c..c58fc9cedc 100644 --- a/src/mesa/pipe/failover/fo_context.c +++ b/src/mesa/pipe/failover/fo_context.c @@ -129,8 +129,8 @@ struct pipe_context *failover_create( struct pipe_context *hw, * at this point - if the hardware doesn't support it, don't * advertise it to the application. */ - failover->pipe.reset_occlusion_counter = hw->reset_occlusion_counter; - failover->pipe.get_occlusion_counter = hw->get_occlusion_counter; + failover->pipe.begin_query = hw->begin_query; + failover->pipe.end_query = hw->end_query; failover_init_state_functions( failover ); diff --git a/src/mesa/pipe/i915simple/i915_context.c b/src/mesa/pipe/i915simple/i915_context.c index f4121419f7..6e48b3bd03 100644 --- a/src/mesa/pipe/i915simple/i915_context.c +++ b/src/mesa/pipe/i915simple/i915_context.c @@ -149,6 +149,22 @@ static void i915_destroy( struct pipe_context *pipe ) +static void +i915_begin_query(struct pipe_context *pipe, struct pipe_query_object *q) +{ + /* should never be called */ + assert(0); +} + + +static void +i915_end_query(struct pipe_context *pipe, struct pipe_query_object *q) +{ + /* should never be called */ + assert(0); +} + + static boolean i915_draw_elements( struct pipe_context *pipe, struct pipe_buffer_handle *indexBuffer, unsigned indexSize, @@ -257,8 +273,9 @@ struct pipe_context *i915_create( struct pipe_winsys *pipe_winsys, i915->pipe.supported_formats = i915_supported_formats; i915->pipe.max_texture_size = i915_max_texture_size; i915->pipe.clear = i915_clear; - i915->pipe.reset_occlusion_counter = NULL; /* no support */ - i915->pipe.get_occlusion_counter = NULL; + + i915->pipe.begin_query = i915_begin_query; + i915->pipe.end_query = i915_end_query; i915->pipe.draw_arrays = i915_draw_arrays; i915->pipe.draw_elements = i915_draw_elements; diff --git a/src/mesa/pipe/p_context.h b/src/mesa/pipe/p_context.h index 27a1128365..dafbef410e 100644 --- a/src/mesa/pipe/p_context.h +++ b/src/mesa/pipe/p_context.h @@ -75,11 +75,12 @@ struct pipe_context { void (*clear)(struct pipe_context *pipe, struct pipe_surface *ps, unsigned clearValue); - /** occlusion counting (XXX this may be temporary - we should probably - * have generic query objects with begin/end methods) + /** + * Query objects */ - void (*reset_occlusion_counter)(struct pipe_context *pipe); - unsigned (*get_occlusion_counter)(struct pipe_context *pipe); + void (*begin_query)(struct pipe_context *pipe, struct pipe_query_object *q); + void (*end_query)(struct pipe_context *pipe, struct pipe_query_object *q); + void (*wait_query)(struct pipe_context *pipe, struct pipe_query_object *q); /* * State functions diff --git a/src/mesa/pipe/p_defines.h b/src/mesa/pipe/p_defines.h index c1164c5c08..b3ee890576 100644 --- a/src/mesa/pipe/p_defines.h +++ b/src/mesa/pipe/p_defines.h @@ -299,4 +299,12 @@ #define PIPE_PRIM_POLYGON 9 +/** + * Query object types + */ +#define PIPE_QUERY_OCCLUSION_COUNTER 0 +#define PIPE_QUERY_PRIMITIVES_GENERATED 1 +#define PIPE_QUERY_PRIMITIVES_EMITTED 2 +#define PIPE_QUERY_TYPES 3 + #endif diff --git a/src/mesa/pipe/p_state.h b/src/mesa/pipe/p_state.h index ccd40d39e6..b994d17ea9 100644 --- a/src/mesa/pipe/p_state.h +++ b/src/mesa/pipe/p_state.h @@ -381,4 +381,14 @@ struct pipe_feedback_buffer { }; +/** + * Hardware queries (occlusion, transform feedback, timing, etc) + */ +struct pipe_query_object { + uint type:3; /**< PIPE_QUERY_x */ + uint ready:1; /**< is result ready? */ + uint64 count; +}; + + #endif diff --git a/src/mesa/pipe/softpipe/sp_context.c b/src/mesa/pipe/softpipe/sp_context.c index 26453d9785..92357808e2 100644 --- a/src/mesa/pipe/softpipe/sp_context.c +++ b/src/mesa/pipe/softpipe/sp_context.c @@ -195,19 +195,37 @@ static void softpipe_destroy( struct pipe_context *pipe ) } -static void softpipe_reset_occlusion_counter(struct pipe_context *pipe) +static void +softpipe_begin_query(struct pipe_context *pipe, struct pipe_query_object *q) { struct softpipe_context *softpipe = softpipe_context( pipe ); - softpipe->occlusion_counter = 0; + assert(q->type < PIPE_QUERY_TYPES); + assert(!softpipe->queries[q->type]); + softpipe->queries[q->type] = q; } -/* XXX pipe param should be const */ -static unsigned softpipe_get_occlusion_counter(struct pipe_context *pipe) + +static void +softpipe_end_query(struct pipe_context *pipe, struct pipe_query_object *q) { struct softpipe_context *softpipe = softpipe_context( pipe ); - return softpipe->occlusion_counter; + assert(q->type < PIPE_QUERY_TYPES); + assert(softpipe->queries[q->type]); + q->ready = 1; /* software rendering is synchronous */ + softpipe->queries[q->type] = NULL; +} + + +static void +softpipe_wait_query(struct pipe_context *pipe, struct pipe_query_object *q) +{ + /* Should never get here since we indicated that the result was + * ready in softpipe_end_query(). + */ + assert(0); } + static const char *softpipe_get_name( struct pipe_context *pipe ) { return "softpipe"; @@ -260,8 +278,11 @@ struct pipe_context *softpipe_create( struct pipe_winsys *pipe_winsys, softpipe->pipe.clear = softpipe_clear; softpipe->pipe.flush = softpipe_flush; - softpipe->pipe.reset_occlusion_counter = softpipe_reset_occlusion_counter; - softpipe->pipe.get_occlusion_counter = softpipe_get_occlusion_counter; + + softpipe->pipe.begin_query = softpipe_begin_query; + softpipe->pipe.end_query = softpipe_end_query; + softpipe->pipe.wait_query = softpipe_wait_query; + softpipe->pipe.get_name = softpipe_get_name; softpipe->pipe.get_vendor = softpipe_get_vendor; diff --git a/src/mesa/pipe/softpipe/sp_context.h b/src/mesa/pipe/softpipe/sp_context.h index 2a6b932523..13d1143c89 100644 --- a/src/mesa/pipe/softpipe/sp_context.h +++ b/src/mesa/pipe/softpipe/sp_context.h @@ -93,6 +93,11 @@ struct softpipe_context { struct pipe_vertex_element vertex_element[PIPE_ATTRIB_MAX]; unsigned dirty; + /* + * Active queries + */ + struct pipe_query_object *queries[PIPE_QUERY_TYPES]; + /* * Mapped vertex buffers */ @@ -120,8 +125,6 @@ struct softpipe_context { /** Derived from scissor and surface bounds: */ struct pipe_scissor_state cliprect; - unsigned occlusion_counter; - unsigned line_stipple_counter; /** Software quad rendering pipeline */ diff --git a/src/mesa/pipe/softpipe/sp_quad_occlusion.c b/src/mesa/pipe/softpipe/sp_quad_occlusion.c index 6b094a5bef..4f178f0557 100644 --- a/src/mesa/pipe/softpipe/sp_quad_occlusion.c +++ b/src/mesa/pipe/softpipe/sp_quad_occlusion.c @@ -44,11 +44,13 @@ static void occlusion_count_quad(struct quad_stage *qs, struct quad_header *quad) { struct softpipe_context *softpipe = qs->softpipe; + struct pipe_query_object *occ + = softpipe->queries[PIPE_QUERY_OCCLUSION_COUNTER]; - softpipe->occlusion_counter += (quad->mask ) & 1; - softpipe->occlusion_counter += (quad->mask >> 1) & 1; - softpipe->occlusion_counter += (quad->mask >> 2) & 1; - softpipe->occlusion_counter += (quad->mask >> 3) & 1; + occ->count += (quad->mask ) & 1; + occ->count += (quad->mask >> 1) & 1; + occ->count += (quad->mask >> 2) & 1; + occ->count += (quad->mask >> 3) & 1; if (quad->mask) qs->next->run(qs->next, quad); diff --git a/src/mesa/state_tracker/st_cb_queryobj.c b/src/mesa/state_tracker/st_cb_queryobj.c index 3a8fbde8ab..5b95dd7fd3 100644 --- a/src/mesa/state_tracker/st_cb_queryobj.c +++ b/src/mesa/state_tracker/st_cb_queryobj.c @@ -44,33 +44,102 @@ #include "st_public.h" +struct st_query_object +{ + struct gl_query_object base; + struct pipe_query_object pq; +}; + + +/** + * Cast wrapper + */ +static struct st_query_object * +st_query_object(struct gl_query_object *q) +{ + return (struct st_query_object *) q; +} + + +static struct gl_query_object * +st_NewQueryObject(GLcontext *ctx, GLuint id) +{ + struct st_query_object *stq = CALLOC_STRUCT(st_query_object); + if (stq) { + stq->base.Id = id; + stq->base.Ready = GL_TRUE; + return &stq->base; + } + return NULL; +} + + /** * Do glReadPixels by getting rows from the framebuffer surface with * get_tile(). Convert to requested format/type with Mesa image routines. * Image transfer ops are done in software too. */ static void -st_BeginQuery(GLcontext *ctx, GLenum target, struct gl_query_object *q) +st_BeginQuery(GLcontext *ctx, struct gl_query_object *q) { struct pipe_context *pipe = ctx->st->pipe; - if (target == GL_SAMPLES_PASSED_ARB) { - pipe->reset_occlusion_counter(pipe); + struct st_query_object *stq = st_query_object(q); + + stq->pq.count = 0; + + switch (q->Target) { + case GL_SAMPLES_PASSED_ARB: + stq->pq.type = PIPE_QUERY_OCCLUSION_COUNTER; + break; + case GL_PRIMITIVES_GENERATED_NV: + /* someday */ + stq->pq.type = PIPE_QUERY_PRIMITIVES_GENERATED; + break; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV: + /* someday */ + stq->pq.type = PIPE_QUERY_PRIMITIVES_EMITTED; + break; + default: + assert(0); } + + pipe->begin_query(pipe, &stq->pq); } static void -st_EndQuery(GLcontext *ctx, GLenum target, struct gl_query_object *q) +st_EndQuery(GLcontext *ctx, struct gl_query_object *q) { struct pipe_context *pipe = ctx->st->pipe; - if (target == GL_SAMPLES_PASSED_ARB) { - q->Result = pipe->get_occlusion_counter(pipe); - } + struct st_query_object *stq = st_query_object(q); + + pipe->end_query(pipe, &stq->pq); + stq->base.Ready = stq->pq.ready; + if (stq->base.Ready) + stq->base.Result = stq->pq.count; +} + + +static void +st_WaitQuery(GLcontext *ctx, struct gl_query_object *q) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_query_object *stq = st_query_object(q); + + /* this function should only be called if we don't have a ready result */ + assert(!stq->base.Ready); + + pipe->wait_query(pipe, &stq->pq); + q->Ready = GL_TRUE; + q->Result = stq->pq.count; } + void st_init_query_functions(struct dd_function_table *functions) { + functions->NewQueryObject = st_NewQueryObject; functions->BeginQuery = st_BeginQuery; functions->EndQuery = st_EndQuery; + functions->WaitQuery = st_WaitQuery; } -- cgit v1.2.3