llvmpipe: Implement PIPE_QUERY_TIMESTAMP and PIPE_QUERY_TIME_ELAPSED.
authorJames Benton <jbenton@vmware.com>
Mon, 3 Dec 2012 07:00:37 +0000 (07:00 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Mon, 3 Dec 2012 17:21:57 +0000 (17:21 +0000)
This required an update for the query storage in llvmpipe, there
can now be an active query per query type, so an occlusion query
can run at the same time as a time elapsed query.

Based on PIPE_QUERY_TIME_ELAPSED patch from Dave Airlie.

v2: fix up piglits for timers (also from Dave Airlie)

a) if we don't render anything the result is 0, so just
return the current time

b) add missing screen get_timestamp callback.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: José Fonseca <jfonseca@vmware.com>
13 files changed:
src/gallium/auxiliary/os/os_time.c
src/gallium/auxiliary/os/os_time.h
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_query.c
src/gallium/drivers/llvmpipe/lp_query.h
src/gallium/drivers/llvmpipe/lp_rast.c
src/gallium/drivers/llvmpipe/lp_rast_priv.h
src/gallium/drivers/llvmpipe/lp_screen.c
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index 3e9d50a598ae7f555e45bd685b76043e8e1634dd..40551252b25be38950ab428f36495a20a201fc5a 100644 (file)
@@ -36,6 +36,7 @@
 #include "pipe/p_config.h"
 
 #if defined(PIPE_OS_UNIX)
+#  include <time.h> /* timeval */
 #  include <sys/time.h> /* timeval */
 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
 #  include <windows.h>
@@ -68,6 +69,20 @@ os_time_get(void)
 }
 
 
+uint64_t
+os_time_get_nano(void)
+{
+#if defined(PIPE_OS_UNIX)
+   struct timespec tv;
+   clock_gettime(CLOCK_REALTIME, &tv);
+   return tv.tv_nsec + tv.tv_sec * 1000000000LL;
+
+#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
+   return os_time_get() * 1000;
+#endif
+}
+
+
 #if defined(PIPE_SUBSYSTEM_WINDOWS_USER)
 
 void
index 7e0f67a76b0d9aa63963191d216ee7b413503f07..54101a1f546619ec41fa8db3d04b785b613196c9 100644 (file)
@@ -57,6 +57,13 @@ int64_t
 os_time_get(void);
 
 
+/*
+ * Get the current time in nanoseconds from an unknown base.
+ */
+uint64_t
+os_time_get_nano(void);
+
+
 /*
  * Sleep.
  */
index fcdc0f82b12e2e69e8941d2749d1917aa07d2291..fe6fa3f9390c7bb521f794584dc6f7c720399b63 100644 (file)
@@ -96,7 +96,7 @@ struct llvmpipe_context {
 
    unsigned dirty; /**< Mask of LP_NEW_x flags */
 
-   int active_query_count;
+   unsigned active_occlusion_query;
 
    /** Mapped vertex buffers */
    ubyte *mapped_vbuffer[PIPE_MAX_ATTRIBS];
index 20c0a1e0bcb8f95f0bbd7be3eee8640ce99673ab..e302197256669d6d404eefc3c9dac4ce479bbb8a 100644 (file)
@@ -33,6 +33,7 @@
 #include "draw/draw_context.h"
 #include "pipe/p_defines.h"
 #include "util/u_memory.h"
+#include "os/os_time.h"
 #include "lp_context.h"
 #include "lp_flush.h"
 #include "lp_fence.h"
@@ -51,10 +52,14 @@ llvmpipe_create_query(struct pipe_context *pipe,
 {
    struct llvmpipe_query *pq;
 
-   assert(type == PIPE_QUERY_OCCLUSION_COUNTER);
+   assert(type < PIPE_QUERY_TYPES);
 
    pq = CALLOC_STRUCT( llvmpipe_query );
 
+   if (pq) {
+      pq->type = type;
+   }
+
    return (struct pipe_query *) pq;
 }
 
@@ -100,7 +105,7 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
    if (!lp_fence_signalled(pq->fence)) {
       if (!lp_fence_issued(pq->fence))
          llvmpipe_flush(pipe, NULL, __FUNCTION__);
-         
+
       if (!wait)
          return FALSE;
 
@@ -110,8 +115,32 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
    /* Sum the results from each of the threads:
     */
    *result = 0;
-   for (i = 0; i < LP_MAX_THREADS; i++) {
-      *result += pq->count[i];
+
+   switch (pq->type) {
+   case PIPE_QUERY_OCCLUSION_COUNTER:
+      for (i = 0; i < LP_MAX_THREADS; i++) {
+         *result += pq->count[i];
+      }
+      break;
+   case PIPE_QUERY_TIME_ELAPSED:
+      for (i = 0; i < LP_MAX_THREADS; i++) {
+         if (pq->count[i] > *result) {
+            *result = pq->count[i];
+         }
+      }
+      break;
+   case PIPE_QUERY_TIMESTAMP:
+      for (i = 0; i < LP_MAX_THREADS; i++) {
+         if (pq->count[i] > *result) {
+            *result = pq->count[i];
+         }
+         if (*result == 0)
+            *result = os_time_get_nano();
+      }
+      break;
+   default:
+      assert(0);
+      break;
    }
 
    return TRUE;
@@ -136,8 +165,10 @@ llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
    memset(pq->count, 0, sizeof(pq->count));
    lp_setup_begin_query(llvmpipe->setup, pq);
 
-   llvmpipe->active_query_count++;
-   llvmpipe->dirty |= LP_NEW_QUERY;
+   if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
+      llvmpipe->active_occlusion_query = TRUE;
+      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
+   }
 }
 
 
@@ -149,9 +180,11 @@ llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
 
    lp_setup_end_query(llvmpipe->setup, pq);
 
-   assert(llvmpipe->active_query_count);
-   llvmpipe->active_query_count--;
-   llvmpipe->dirty |= LP_NEW_QUERY;
+   if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
+      assert(llvmpipe->active_occlusion_query);
+      llvmpipe->active_occlusion_query = FALSE;
+      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
+   }
 }
 
 boolean
index ef1bc3070372c62486c8f8ccb3c2be061dbe5c93..cacbd9d0b8c75a834ed42328768ca4511d56cc86 100644 (file)
@@ -42,8 +42,9 @@ struct llvmpipe_context;
 
 
 struct llvmpipe_query {
-   uint64_t count[LP_MAX_THREADS];  /**< a counter for each thread */
-   struct lp_fence *fence;      /* fence from last scene this was binned in */
+   uint64_t count[LP_MAX_THREADS];  /* a counter for each thread */
+   struct lp_fence *fence;          /* fence from last scene this was binned in */
+   unsigned type;                   /* PIPE_QUERY_* */
 };
 
 
index 5c233c06a15123124b4ec22a5c7219046a3d7fab..40a8591cabe14c8b4738409a070b9d84188fd460 100644 (file)
@@ -32,6 +32,8 @@
 #include "util/u_surface.h"
 #include "util/u_pack_color.h"
 
+#include "os/os_time.h"
+
 #include "lp_scene_queue.h"
 #include "lp_debug.h"
 #include "lp_fence.h"
@@ -429,9 +431,21 @@ lp_rast_begin_query(struct lp_rasterizer_task *task,
 {
    struct llvmpipe_query *pq = arg.query_obj;
 
-   assert(task->query == NULL);
-   task->vis_counter = 0;
-   task->query = pq;
+   assert(task->query[pq->type] == NULL);
+
+   switch (pq->type) {
+   case PIPE_QUERY_OCCLUSION_COUNTER:
+      task->vis_counter = 0;
+      break;
+   case PIPE_QUERY_TIME_ELAPSED:
+      task->query_start = os_time_get_nano();
+      break;
+   default:
+      assert(0);
+      break;
+   }
+
+   task->query[pq->type] = pq;
 }
 
 
@@ -444,10 +458,26 @@ static void
 lp_rast_end_query(struct lp_rasterizer_task *task,
                   const union lp_rast_cmd_arg arg)
 {
-   assert(task->query);
-   if (task->query) {
-      task->query->count[task->thread_index] += task->vis_counter;
-      task->query = NULL;
+   struct llvmpipe_query *pq = arg.query_obj;
+   assert(task->query[pq->type] == pq || pq->type == PIPE_QUERY_TIMESTAMP);
+
+   switch (pq->type) {
+   case PIPE_QUERY_OCCLUSION_COUNTER:
+      pq->count[task->thread_index] += task->vis_counter;
+      break;
+   case PIPE_QUERY_TIME_ELAPSED:
+      pq->count[task->thread_index] = os_time_get_nano() - task->query_start;
+      break;
+   case PIPE_QUERY_TIMESTAMP:
+      pq->count[task->thread_index] = os_time_get_nano();
+      break;
+   default:
+      assert(0);
+      break;
+   }
+
+   if (task->query[pq->type] == pq) {
+      task->query[pq->type] = NULL;
    }
 }
 
@@ -467,9 +497,12 @@ lp_rast_set_state(struct lp_rasterizer_task *task,
 static void
 lp_rast_tile_end(struct lp_rasterizer_task *task)
 {
-   if (task->query) {
-      union lp_rast_cmd_arg dummy = {0};
-      lp_rast_end_query(task, dummy);
+   unsigned i;
+
+   for (i = 0; i < PIPE_QUERY_TYPES; ++i) {
+      if (task->query[i]) {
+         lp_rast_end_query(task, lp_rast_arg_query(task->query[i]));
+      }
    }
 
    /* debug */
index dc9739e9ad049fe72888f99a03ec50bad8dccdee..afcf33382f4e3eb429b774e97fc1e986afd1e2ea 100644 (file)
@@ -96,7 +96,8 @@ struct lp_rasterizer_task
 
    /* occlude counter for visiable pixels */
    uint32_t vis_counter;
-   struct llvmpipe_query *query;
+   uint64_t query_start;
+   struct llvmpipe_query *query[PIPE_QUERY_TYPES];
 
    pipe_semaphore work_ready;
    pipe_semaphore work_done;
index 3f207d713af6590d73e462195cbe5cb20d7394b2..acbde9da983fc1f881bb12813209a1821f9a416e 100644 (file)
@@ -37,6 +37,7 @@
 #include "draw/draw_context.h"
 #include "gallivm/lp_bld_type.h"
 
+#include "os/os_time.h"
 #include "lp_texture.h"
 #include "lp_fence.h"
 #include "lp_jit.h"
@@ -126,7 +127,8 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_OCCLUSION_QUERY:
       return 1;
    case PIPE_CAP_TIMER_QUERY:
-      return 0;
+   case PIPE_CAP_QUERY_TIMESTAMP:
+      return 1;
    case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
       return 1;
    case PIPE_CAP_TEXTURE_SHADOW_MAP:
@@ -210,7 +212,6 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
       return 16;
    case PIPE_CAP_START_INSTANCE:
-   case PIPE_CAP_QUERY_TIMESTAMP:
    case PIPE_CAP_TEXTURE_MULTISAMPLE:
    case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT:
    case PIPE_CAP_CUBE_MAP_ARRAY:
@@ -446,7 +447,11 @@ llvmpipe_fence_finish(struct pipe_screen *screen,
    return TRUE;
 }
 
-
+static uint64_t
+llvmpipe_get_timestamp(struct pipe_screen *_screen)
+{
+   return os_time_get_nano();
+}
 
 /**
  * Create a new pipe_screen object
@@ -491,6 +496,8 @@ llvmpipe_create_screen(struct sw_winsys *winsys)
    screen->base.fence_signalled = llvmpipe_fence_signalled;
    screen->base.fence_finish = llvmpipe_fence_finish;
 
+   screen->base.get_timestamp = llvmpipe_get_timestamp;
+
    llvmpipe_init_screen_resource_funcs(&screen->base);
 
    lp_jit_screen_init(screen);
index 84defc65054006c1ecadd63d595b2e85bcbaaea9..1d71a87319eefc27d3d5c55aa1a01a45764f03d6 100644 (file)
@@ -232,12 +232,14 @@ begin_binning( struct lp_setup_context *setup )
       }
    }
 
-   if (setup->active_query) {
-      ok = lp_scene_bin_everywhere( scene,
-                                    LP_RAST_OP_BEGIN_QUERY,
-                                    lp_rast_arg_query(setup->active_query) );
-      if (!ok)
-         return FALSE;
+   for (i = 0; i < PIPE_QUERY_TYPES; ++i) {
+      if (setup->active_query[i]) {
+         ok = lp_scene_bin_everywhere( scene,
+                                       LP_RAST_OP_BEGIN_QUERY,
+                                       lp_rast_arg_query(setup->active_query[i]) );
+         if (!ok)
+            return FALSE;
+      }
    }
 
    setup->clear.flags = 0;
@@ -1116,11 +1118,16 @@ lp_setup_begin_query(struct lp_setup_context *setup,
                      struct llvmpipe_query *pq)
 {
    /* init the query to its beginning state */
-   assert(setup->active_query == NULL);
+   assert(setup->active_query[pq->type] == NULL);
 
    set_scene_state(setup, SETUP_ACTIVE, "begin_query");
    
-   setup->active_query = pq;
+   setup->active_query[pq->type] = pq;
+
+   /* XXX: It is possible that a query is created before the scene
+    * has been created. This means that setup->scene == NULL resulting
+    * in the query not being binned and thus is ignored.
+    */
 
    if (setup->scene) {
       if (!lp_scene_bin_everywhere(setup->scene,
@@ -1146,12 +1153,12 @@ lp_setup_begin_query(struct lp_setup_context *setup,
 void
 lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
 {
-   union lp_rast_cmd_arg dummy = { 0 };
-
    set_scene_state(setup, SETUP_ACTIVE, "end_query");
 
-   assert(setup->active_query == pq);
-   setup->active_query = NULL;
+   if (pq->type != PIPE_QUERY_TIMESTAMP) {
+      assert(setup->active_query[pq->type] == pq);
+      setup->active_query[pq->type] = NULL;
+   }
 
    /* Setup will automatically re-issue any query which carried over a
     * scene boundary, and the rasterizer automatically "ends" queries
@@ -1166,7 +1173,7 @@ lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq)
 
       if (!lp_scene_bin_everywhere(setup->scene,
                                    LP_RAST_OP_END_QUERY,
-                                   dummy)) {
+                                   lp_rast_arg_query(pq))) {
          lp_setup_flush(setup, NULL, __FUNCTION__);
       }
    }
index 7fdd1e735c4475873ff582cf45bffdd520217ecf..6c86b4b779ac82ea6473fb2c5d0cf8a26bd22051 100644 (file)
@@ -89,7 +89,7 @@ struct lp_setup_context
    struct lp_scene *scene;               /**< current scene being built */
 
    struct lp_fence *last_fence;
-   struct llvmpipe_query *active_query;
+   struct llvmpipe_query *active_query[PIPE_QUERY_TYPES];
 
    boolean flatshade_first;
    boolean ccw_is_frontface;
index 97ca1727c9babdca03ce0ac89da377355fbd2293..94a21a0158bdde9ac64ace262419478598c25def 100644 (file)
@@ -51,7 +51,7 @@
 #define LP_NEW_SAMPLER_VIEW  0x800
 #define LP_NEW_VERTEX        0x1000
 #define LP_NEW_VS            0x2000
-#define LP_NEW_QUERY         0x4000
+#define LP_NEW_OCCLUSION_QUERY 0x4000
 #define LP_NEW_BLEND_COLOR   0x8000
 #define LP_NEW_GS            0x10000
 #define LP_NEW_SO            0x20000
index 5bb5a7a0b7eeee84dc0c31b903db53e97de31da7..3b826de80c97d080eeef92f96ecfea7254d7f0e5 100644 (file)
@@ -152,7 +152,7 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                           LP_NEW_RASTERIZER |
                           LP_NEW_SAMPLER |
                           LP_NEW_SAMPLER_VIEW |
-                          LP_NEW_QUERY))
+                          LP_NEW_OCCLUSION_QUERY))
       llvmpipe_update_fs( llvmpipe );
 
    if (llvmpipe->dirty & (LP_NEW_FS |
index dcd11b65c8ff00a8f33ed248385eedac7cf1ee50..c56ce9ee71cc81fbe0b2185750960a4f506f9698 100644 (file)
@@ -2493,7 +2493,7 @@ make_variant_key(struct llvmpipe_context *lp,
    /* alpha.ref_value is passed in jit_context */
 
    key->flatshade = lp->rasterizer->flatshade;
-   if (lp->active_query_count) {
+   if (lp->active_occlusion_query) {
       key->occlusion_count = TRUE;
    }