Implement query object interface.
authorBrian <brian.paul@tungstengraphics.com>
Tue, 11 Sep 2007 22:01:17 +0000 (16:01 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Tue, 11 Sep 2007 22:01:17 +0000 (16:01 -0600)
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.

14 files changed:
src/mesa/drivers/common/driverfuncs.c
src/mesa/main/dd.h
src/mesa/main/mtypes.h
src/mesa/main/queryobj.c
src/mesa/main/queryobj.h
src/mesa/pipe/failover/fo_context.c
src/mesa/pipe/i915simple/i915_context.c
src/mesa/pipe/p_context.h
src/mesa/pipe/p_defines.h
src/mesa/pipe/p_state.h
src/mesa/pipe/softpipe/sp_context.c
src/mesa/pipe/softpipe/sp_context.h
src/mesa/pipe/softpipe/sp_quad_occlusion.c
src/mesa/state_tracker/st_cb_queryobj.c

index 500dbb25456adcea0260112b8833917075b01f94..96e5037fa57a7324359e12d6ddc6c82aafe5d1be 100644 (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;
index 582e0c334df4517a9ceee4d709242a41e5038c6c..f089fcb48f0e251cd70de865a6b50db1ac697e7c 100644 (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);
    /*@}*/
 
 
index 0a64e0c58c0f8035378178d4388e157ebbb46980..514170dbcf0c7a84fa7c37d7c0e0eb3891b28746 100644 (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? */
 };
 
 
index 0e59ba615a783bd597f1ffe49d78efa616d5b9c4..688d0fc7bcd25b79e3da0d9db10928f1b6cfb65e 100644 (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:
index ada8cf835607585c4459a6c547ae213277e6989f..d466aae65200fc3f35cb3e3eec3586c6a8b91bf2 100644 (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);
 
index b88f1b466cbf4c9044bc262899f7bd685449f5de..c58fc9cedcd421dd5c8b16469f372081997f399b 100644 (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 );
 
index f4121419f79481305ef9ce09684515613ee81b23..6e48b3bd03b6090aed3ad9bef3a1ecb7e9ebc787 100644 (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;
index 27a1128365e59c758a93f1aa9fc9a248b3166483..dafbef410eb5fae09ca1c91102eea116e768a7b9 100644 (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
index c1164c5c08b05cf863bb6393885b61cce8a54b74..b3ee8905769c9f94d930b03e3f1ed7f41cf4a92e 100644 (file)
 #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
index ccd40d39e6651c0b4f382d42c35a3d0faca29322..b994d17ea9e54a0aa5c2bd28c5e627519a3054f1 100644 (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
index 26453d97852952cdb5713d4d727b064cd5c7a32b..92357808e295f25e9c26e2a7e445e471d1f801da 100644 (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;
 
index 2a6b932523a163205daba374f6bfecd27ff83a21..13d1143c89031babc0401ecbaaad6efc12d03064 100644 (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 */
index 6b094a5befbc6b06a41e1b1e408223ff190ad0c2..4f178f0557ebeaa6f6c0a46565cd78fb371fe6bf 100644 (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);
index 3a8fbde8abd3969918ca1df6db8133a0aa52d1d3..5b95dd7fd3c40e54d76dfc076b3b1c4859befee3 100644 (file)
 #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;
 }