summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/swr/swr_query.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/swr/swr_query.cpp')
-rw-r--r--src/gallium/drivers/swr/swr_query.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/gallium/drivers/swr/swr_query.cpp b/src/gallium/drivers/swr/swr_query.cpp
new file mode 100644
index 00000000000..810c50b2f8f
--- /dev/null
+++ b/src/gallium/drivers/swr/swr_query.cpp
@@ -0,0 +1,334 @@
+/****************************************************************************
+ * Copyright (C) 2015 Intel Corporation. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ ***************************************************************************/
+
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+#include "os/os_time.h"
+#include "swr_context.h"
+#include "swr_fence.h"
+#include "swr_query.h"
+#include "swr_screen.h"
+#include "swr_state.h"
+
+
+static struct swr_query *
+swr_query(struct pipe_query *p)
+{
+ return (struct swr_query *)p;
+}
+
+static struct pipe_query *
+swr_create_query(struct pipe_context *pipe, unsigned type, unsigned index)
+{
+ struct swr_query *pq;
+
+ assert(type < PIPE_QUERY_TYPES);
+ assert(index < MAX_SO_STREAMS);
+
+ pq = CALLOC_STRUCT(swr_query);
+
+ if (pq) {
+ pq->type = type;
+ pq->index = index;
+ }
+
+ return (struct pipe_query *)pq;
+}
+
+
+static void
+swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+ struct swr_query *pq = swr_query(q);
+
+ if (pq->fence) {
+ if (!swr_is_fence_pending(pq->fence)) {
+ swr_fence_submit(swr_context(pipe), pq->fence);
+ swr_fence_finish(pipe->screen, pq->fence, 0);
+ }
+ swr_fence_reference(pipe->screen, &pq->fence, NULL);
+ }
+
+ FREE(pq);
+}
+
+
+// XXX Create a fence callback, rather than stalling SwrWaitForIdle
+static void
+swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq)
+{
+ struct swr_context *ctx = swr_context(pipe);
+
+ assert(pq->result);
+ union pipe_query_result *result = pq->result;
+ boolean enable_stats = pq->enable_stats;
+ SWR_STATS swr_stats = {0};
+
+ if (pq->fence) {
+ if (!swr_is_fence_pending(pq->fence)) {
+ swr_fence_submit(ctx, pq->fence);
+ swr_fence_finish(pipe->screen, pq->fence, 0);
+ }
+ swr_fence_reference(pipe->screen, &pq->fence, NULL);
+ }
+
+ /*
+ * These queries don't need SWR Stats enabled in the core
+ * Set and return.
+ */
+ switch (pq->type) {
+ case PIPE_QUERY_TIMESTAMP:
+ case PIPE_QUERY_TIME_ELAPSED:
+ result->u64 = swr_get_timestamp(pipe->screen);
+ return;
+ break;
+ case PIPE_QUERY_TIMESTAMP_DISJOINT:
+ /* nothing to do here */
+ return;
+ break;
+ case PIPE_QUERY_GPU_FINISHED:
+ result->b = TRUE; /* XXX TODO Add an api func to SWR to compare drawId
+ vs LastRetiredId? */
+ return;
+ break;
+ default:
+ /* Any query that needs SwrCore stats */
+ break;
+ }
+
+ /*
+ * All other results are collected from SwrCore counters
+ */
+
+ /* XXX, Should turn this into a fence callback and skip the stall */
+ SwrGetStats(ctx->swrContext, &swr_stats);
+ /* SwrGetStats returns immediately, wait for collection */
+ SwrWaitForIdle(ctx->swrContext);
+
+ switch (pq->type) {
+ case PIPE_QUERY_OCCLUSION_PREDICATE:
+ case PIPE_QUERY_OCCLUSION_COUNTER:
+ result->u64 = swr_stats.DepthPassCount;
+ break;
+ case PIPE_QUERY_PRIMITIVES_GENERATED:
+ result->u64 = swr_stats.IaPrimitives;
+ break;
+ case PIPE_QUERY_PRIMITIVES_EMITTED:
+ result->u64 = swr_stats.SoNumPrimsWritten[pq->index];
+ break;
+ case PIPE_QUERY_SO_STATISTICS:
+ case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
+ struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
+ so_stats->num_primitives_written =
+ swr_stats.SoNumPrimsWritten[pq->index];
+ so_stats->primitives_storage_needed =
+ swr_stats.SoPrimStorageNeeded[pq->index];
+ } break;
+ case PIPE_QUERY_PIPELINE_STATISTICS: {
+ struct pipe_query_data_pipeline_statistics *p_stats =
+ &result->pipeline_statistics;
+ p_stats->ia_vertices = swr_stats.IaVertices;
+ p_stats->ia_primitives = swr_stats.IaPrimitives;
+ p_stats->vs_invocations = swr_stats.VsInvocations;
+ p_stats->gs_invocations = swr_stats.GsInvocations;
+ p_stats->gs_primitives = swr_stats.GsPrimitives;
+ p_stats->c_invocations = swr_stats.CPrimitives;
+ p_stats->c_primitives = swr_stats.CPrimitives;
+ p_stats->ps_invocations = swr_stats.PsInvocations;
+ p_stats->hs_invocations = swr_stats.HsInvocations;
+ p_stats->ds_invocations = swr_stats.DsInvocations;
+ p_stats->cs_invocations = swr_stats.CsInvocations;
+ } break;
+ default:
+ assert(0 && "Unsupported query");
+ break;
+ }
+
+ /* Only change stat collection if there are no active queries */
+ if (ctx->active_queries == 0)
+ SwrEnableStats(ctx->swrContext, enable_stats);
+}
+
+
+static boolean
+swr_get_query_result(struct pipe_context *pipe,
+ struct pipe_query *q,
+ boolean wait,
+ union pipe_query_result *result)
+{
+ struct swr_context *ctx = swr_context(pipe);
+ struct swr_query *pq = swr_query(q);
+
+ if (pq->fence) {
+ if (!swr_is_fence_pending(pq->fence)) {
+ swr_fence_submit(ctx, pq->fence);
+ if (!wait)
+ return FALSE;
+ swr_fence_finish(pipe->screen, pq->fence, 0);
+ }
+ swr_fence_reference(pipe->screen, &pq->fence, NULL);
+ }
+
+ /* XXX: Need to handle counter rollover */
+
+ switch (pq->type) {
+ /* Booleans */
+ case PIPE_QUERY_OCCLUSION_PREDICATE:
+ result->b = pq->end.u64 != pq->start.u64 ? TRUE : FALSE;
+ break;
+ case PIPE_QUERY_GPU_FINISHED:
+ result->b = pq->end.b;
+ break;
+ /* Counters */
+ case PIPE_QUERY_OCCLUSION_COUNTER:
+ case PIPE_QUERY_TIMESTAMP:
+ case PIPE_QUERY_TIME_ELAPSED:
+ case PIPE_QUERY_PRIMITIVES_GENERATED:
+ case PIPE_QUERY_PRIMITIVES_EMITTED:
+ result->u64 = pq->end.u64 - pq->start.u64;
+ break;
+ /* Structures */
+ case PIPE_QUERY_SO_STATISTICS: {
+ struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
+ struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
+ struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
+ so_stats->num_primitives_written =
+ end->num_primitives_written - start->num_primitives_written;
+ so_stats->primitives_storage_needed =
+ end->primitives_storage_needed - start->primitives_storage_needed;
+ } break;
+ case PIPE_QUERY_TIMESTAMP_DISJOINT: {
+ /* os_get_time_nano returns nanoseconds */
+ result->timestamp_disjoint.frequency = UINT64_C(1000000000);
+ result->timestamp_disjoint.disjoint = FALSE;
+ } break;
+ case PIPE_QUERY_PIPELINE_STATISTICS: {
+ struct pipe_query_data_pipeline_statistics *p_stats =
+ &result->pipeline_statistics;
+ struct pipe_query_data_pipeline_statistics *start =
+ &pq->start.pipeline_statistics;
+ struct pipe_query_data_pipeline_statistics *end =
+ &pq->end.pipeline_statistics;
+ p_stats->ia_vertices = end->ia_vertices - start->ia_vertices;
+ p_stats->ia_primitives = end->ia_primitives - start->ia_primitives;
+ p_stats->vs_invocations = end->vs_invocations - start->vs_invocations;
+ p_stats->gs_invocations = end->gs_invocations - start->gs_invocations;
+ p_stats->gs_primitives = end->gs_primitives - start->gs_primitives;
+ p_stats->c_invocations = end->c_invocations - start->c_invocations;
+ p_stats->c_primitives = end->c_primitives - start->c_primitives;
+ p_stats->ps_invocations = end->ps_invocations - start->ps_invocations;
+ p_stats->hs_invocations = end->hs_invocations - start->hs_invocations;
+ p_stats->ds_invocations = end->ds_invocations - start->ds_invocations;
+ p_stats->cs_invocations = end->cs_invocations - start->cs_invocations;
+ } break;
+ case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
+ struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
+ struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
+ uint64_t num_primitives_written =
+ end->num_primitives_written - start->num_primitives_written;
+ uint64_t primitives_storage_needed =
+ end->primitives_storage_needed - start->primitives_storage_needed;
+ result->b = num_primitives_written > primitives_storage_needed;
+ } break;
+ default:
+ assert(0 && "Unsupported query");
+ break;
+ }
+
+ return TRUE;
+}
+
+static boolean
+swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+ struct swr_context *ctx = swr_context(pipe);
+ struct swr_query *pq = swr_query(q);
+
+ /* Initialize Results */
+ memset(&pq->start, 0, sizeof(pq->start));
+ memset(&pq->end, 0, sizeof(pq->end));
+
+ /* Gather start stats and enable SwrCore counters */
+ pq->result = &pq->start;
+ pq->enable_stats = TRUE;
+ swr_gather_stats(pipe, pq);
+ ctx->active_queries++;
+
+ /* override start timestamp to 0 for TIMESTAMP query */
+ if (pq->type == PIPE_QUERY_TIMESTAMP)
+ pq->start.u64 = 0;
+
+ return true;
+}
+
+static void
+swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
+{
+ struct swr_context *ctx = swr_context(pipe);
+ struct swr_query *pq = swr_query(q);
+
+ assert(ctx->active_queries
+ && "swr_end_query, there are no active queries!");
+ ctx->active_queries--;
+
+ /* Gather end stats and disable SwrCore counters */
+ pq->result = &pq->end;
+ pq->enable_stats = FALSE;
+ swr_gather_stats(pipe, pq);
+}
+
+
+boolean
+swr_check_render_cond(struct pipe_context *pipe)
+{
+ struct swr_context *ctx = swr_context(pipe);
+ boolean b, wait;
+ uint64_t result;
+
+ if (!ctx->render_cond_query)
+ return TRUE; /* no query predicate, draw normally */
+
+ wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
+ || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
+
+ b = pipe->get_query_result(
+ pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
+ if (b)
+ return (!result == ctx->render_cond_cond);
+ else
+ return TRUE;
+}
+
+void
+swr_query_init(struct pipe_context *pipe)
+{
+ struct swr_context *ctx = swr_context(pipe);
+
+ pipe->create_query = swr_create_query;
+ pipe->destroy_query = swr_destroy_query;
+ pipe->begin_query = swr_begin_query;
+ pipe->end_query = swr_end_query;
+ pipe->get_query_result = swr_get_query_result;
+
+ ctx->active_queries = 0;
+}