Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / mesa / state_tracker / st_cb_queryobj.c
index b10fd9335eda1ae0ed33ed948595be553a4bbb31..aafae16b2df95eaf2c2aabfc07e49e3781bc8b25 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
@@ -35,7 +35,6 @@
 
 #include "main/imports.h"
 #include "main/context.h"
-#include "main/mfeatures.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
@@ -72,6 +71,11 @@ st_DeleteQuery(struct gl_context *ctx, struct gl_query_object *q)
       stq->pq = NULL;
    }
 
+   if (stq->pq_begin) {
+      pipe->destroy_query(pipe, stq->pq_begin);
+      stq->pq_begin = NULL;
+   }
+
    free(stq);
 }
 
@@ -79,7 +83,8 @@ st_DeleteQuery(struct gl_context *ctx, struct gl_query_object *q)
 static void
 st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q)
 {
-   struct pipe_context *pipe = st_context(ctx)->pipe;
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
    struct st_query_object *stq = st_query_object(q);
    unsigned type;
 
@@ -88,6 +93,7 @@ st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q)
    /* convert GL query type to Gallium query type */
    switch (q->Target) {
    case GL_ANY_SAMPLES_PASSED:
+   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
       /* fall-through */
    case GL_SAMPLES_PASSED_ARB:
       type = PIPE_QUERY_OCCLUSION_COUNTER;
@@ -98,29 +104,65 @@ st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q)
    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
       type = PIPE_QUERY_PRIMITIVES_EMITTED;
       break;
-   case GL_TIME_ELAPSED_EXT:
-      type = PIPE_QUERY_TIME_ELAPSED;
+   case GL_TIME_ELAPSED:
+      if (st->has_time_elapsed)
+         type = PIPE_QUERY_TIME_ELAPSED;
+      else
+         type = PIPE_QUERY_TIMESTAMP;
+      break;
+   case GL_VERTICES_SUBMITTED_ARB:
+   case GL_PRIMITIVES_SUBMITTED_ARB:
+   case GL_VERTEX_SHADER_INVOCATIONS_ARB:
+   case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
+   case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
+   case GL_GEOMETRY_SHADER_INVOCATIONS:
+   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
+   case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
+   case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
+   case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
+   case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
+      type = PIPE_QUERY_PIPELINE_STATISTICS;
       break;
    default:
       assert(0 && "unexpected query target in st_BeginQuery()");
       return;
    }
 
-   if (stq->pq && stq->type != type) {
+   if (stq->type != type) {
       /* free old query of different type */
-      pipe->destroy_query(pipe, stq->pq);
-      stq->pq = NULL;
+      if (stq->pq) {
+         pipe->destroy_query(pipe, stq->pq);
+         stq->pq = NULL;
+      }
+      if (stq->pq_begin) {
+         pipe->destroy_query(pipe, stq->pq_begin);
+         stq->pq_begin = NULL;
+      }
       stq->type = PIPE_QUERY_TYPES; /* an invalid value */
    }
 
-   if (!stq->pq) {
-      stq->pq = pipe->create_query(pipe, type);
-      stq->type = type;
+   if (q->Target == GL_TIME_ELAPSED &&
+       type == PIPE_QUERY_TIMESTAMP) {
+      /* Determine time elapsed by emitting two timestamp queries. */
+      if (!stq->pq_begin) {
+         stq->pq_begin = pipe->create_query(pipe, type, 0);
+         stq->type = type;
+      }
+      pipe->end_query(pipe, stq->pq_begin);
+   } else {
+      if (!stq->pq) {
+         stq->pq = pipe->create_query(pipe, type, q->Stream);
+         stq->type = type;
+      }
+      if (stq->pq) {
+         pipe->begin_query(pipe, stq->pq);
+      }
+      else {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery");
+         return;
+      }
    }
-
    assert(stq->type == type);
-
-   pipe->begin_query(pipe, stq->pq);
 }
 
 
@@ -132,12 +174,86 @@ st_EndQuery(struct gl_context *ctx, struct gl_query_object *q)
 
    st_flush_bitmap_cache(st_context(ctx));
 
-   if (q->Target == GL_TIMESTAMP && !stq->pq) {
-      stq->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP);
+   if ((q->Target == GL_TIMESTAMP ||
+        q->Target == GL_TIME_ELAPSED) &&
+       !stq->pq) {
+      stq->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0);
       stq->type = PIPE_QUERY_TIMESTAMP;
    }
 
-   pipe->end_query(pipe, stq->pq);
+   if (stq->pq)
+      pipe->end_query(pipe, stq->pq);
+}
+
+
+static boolean
+get_query_result(struct pipe_context *pipe,
+                 struct st_query_object *stq,
+                 boolean wait)
+{
+   union pipe_query_result data;
+
+   if (!stq->pq) {
+      /* Only needed in case we failed to allocate the gallium query earlier.
+       * Return TRUE so we don't spin on this forever.
+       */
+      return TRUE;
+   }
+
+   if (!pipe->get_query_result(pipe, stq->pq, wait, &data))
+      return FALSE;
+
+   switch (stq->base.Target) {
+   case GL_VERTICES_SUBMITTED_ARB:
+      stq->base.Result = data.pipeline_statistics.ia_vertices;
+      break;
+   case GL_PRIMITIVES_SUBMITTED_ARB:
+      stq->base.Result = data.pipeline_statistics.ia_primitives;
+      break;
+   case GL_VERTEX_SHADER_INVOCATIONS_ARB:
+      stq->base.Result = data.pipeline_statistics.vs_invocations;
+      break;
+   case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
+      stq->base.Result = data.pipeline_statistics.hs_invocations;
+      break;
+   case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
+      stq->base.Result = data.pipeline_statistics.ds_invocations;
+      break;
+   case GL_GEOMETRY_SHADER_INVOCATIONS:
+      stq->base.Result = data.pipeline_statistics.gs_invocations;
+      break;
+   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
+      stq->base.Result = data.pipeline_statistics.gs_primitives;
+      break;
+   case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
+      stq->base.Result = data.pipeline_statistics.ps_invocations;
+      break;
+   case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
+      stq->base.Result = data.pipeline_statistics.cs_invocations;
+      break;
+   case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
+      stq->base.Result = data.pipeline_statistics.c_invocations;
+      break;
+   case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
+      stq->base.Result = data.pipeline_statistics.c_primitives;
+      break;
+   default:
+      stq->base.Result = data.u64;
+      break;
+   }
+
+   if (stq->base.Target == GL_TIME_ELAPSED &&
+       stq->type == PIPE_QUERY_TIMESTAMP) {
+      /* Calculate the elapsed time from the two timestamp queries */
+      GLuint64EXT Result0 = 0;
+      assert(stq->pq_begin);
+      pipe->get_query_result(pipe, stq->pq_begin, TRUE, (void *)&Result0);
+      stq->base.Result -= Result0;
+   } else {
+      assert(!stq->pq_begin);
+   }
+
+   return TRUE;
 }
 
 
@@ -151,10 +267,7 @@ st_WaitQuery(struct gl_context *ctx, struct gl_query_object *q)
    assert(!stq->base.Ready);
 
    while (!stq->base.Ready &&
-         !pipe->get_query_result(pipe, 
-                                 stq->pq,
-                                 TRUE,
-                                 (void*)&q->Result))
+         !get_query_result(pipe, stq, TRUE))
    {
       /* nothing */
    }
@@ -169,16 +282,25 @@ st_CheckQuery(struct gl_context *ctx, struct gl_query_object *q)
    struct pipe_context *pipe = st_context(ctx)->pipe;
    struct st_query_object *stq = st_query_object(q);
    assert(!q->Ready);   /* we should not get called if Ready is TRUE */
-   q->Ready = pipe->get_query_result(pipe, stq->pq, FALSE, (void*)&q->Result);
+   q->Ready = get_query_result(pipe, stq, FALSE);
 }
 
 
 static uint64_t
 st_GetTimestamp(struct gl_context *ctx)
 {
-   struct pipe_screen *screen = st_context(ctx)->pipe->screen;
+   struct pipe_context *pipe = st_context(ctx)->pipe;
+   struct pipe_screen *screen = pipe->screen;
 
-   return screen->get_timestamp(screen);
+   /* Prefer the per-screen function */
+   if (screen->get_timestamp) {
+      return screen->get_timestamp(screen);
+   }
+   else {
+      /* Fall back to the per-context function */
+      assert(pipe->get_timestamp);
+      return pipe->get_timestamp(pipe);
+   }
 }