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.
This commit is contained in:
Brian
2007-09-11 16:01:17 -06:00
parent 5620d66e36
commit 09fbb3837b
14 changed files with 232 additions and 84 deletions

View File

@@ -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;

View File

@@ -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);
/*@}*/

View File

@@ -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? */
};

View File

@@ -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:

View File

@@ -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);

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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;
}