| /**************************************************************************** |
| * 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" |
| #include "common/os.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 = (struct swr_query *) AlignedMalloc(sizeof(struct swr_query), 64); |
| memset(pq, 0, sizeof(*pq)); |
| |
| 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_finish(pipe->screen, NULL, pq->fence, 0); |
| swr_fence_reference(pipe->screen, &pq->fence, NULL); |
| } |
| |
| AlignedFree(pq); |
| } |
| |
| |
| static boolean |
| swr_get_query_result(struct pipe_context *pipe, |
| struct pipe_query *q, |
| boolean wait, |
| union pipe_query_result *result) |
| { |
| struct swr_query *pq = swr_query(q); |
| unsigned index = pq->index; |
| |
| if (pq->fence) { |
| if (!wait && !swr_is_fence_done(pq->fence)) |
| return FALSE; |
| |
| swr_fence_finish(pipe->screen, NULL, pq->fence, 0); |
| swr_fence_reference(pipe->screen, &pq->fence, NULL); |
| } |
| |
| /* All values are reset to 0 at swr_begin_query, except starting timestamp. |
| * Counters become simply end values. */ |
| switch (pq->type) { |
| /* Booleans */ |
| case PIPE_QUERY_OCCLUSION_PREDICATE: |
| result->b = pq->result.core.DepthPassCount != 0; |
| break; |
| case PIPE_QUERY_GPU_FINISHED: |
| result->b = TRUE; |
| break; |
| /* Counters */ |
| case PIPE_QUERY_OCCLUSION_COUNTER: |
| result->u64 = pq->result.core.DepthPassCount; |
| break; |
| case PIPE_QUERY_TIMESTAMP: |
| case PIPE_QUERY_TIME_ELAPSED: |
| result->u64 = pq->result.timestamp_end - pq->result.timestamp_start; |
| break; |
| case PIPE_QUERY_PRIMITIVES_GENERATED: |
| result->u64 = pq->result.coreFE.IaPrimitives; |
| break; |
| case PIPE_QUERY_PRIMITIVES_EMITTED: |
| result->u64 = pq->result.coreFE.SoNumPrimsWritten[index]; |
| break; |
| /* Structures */ |
| case PIPE_QUERY_SO_STATISTICS: { |
| struct pipe_query_data_so_statistics *so_stats = &result->so_statistics; |
| so_stats->num_primitives_written = |
| pq->result.coreFE.SoNumPrimsWritten[index]; |
| so_stats->primitives_storage_needed = |
| pq->result.coreFE.SoPrimStorageNeeded[index]; |
| } 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; |
| p_stats->ia_vertices = pq->result.coreFE.IaVertices; |
| p_stats->ia_primitives = pq->result.coreFE.IaPrimitives; |
| p_stats->vs_invocations = pq->result.coreFE.VsInvocations; |
| p_stats->gs_invocations = pq->result.coreFE.GsInvocations; |
| p_stats->gs_primitives = pq->result.coreFE.GsPrimitives; |
| p_stats->c_invocations = pq->result.coreFE.CPrimitives; |
| p_stats->c_primitives = pq->result.coreFE.CPrimitives; |
| p_stats->ps_invocations = pq->result.core.PsInvocations; |
| p_stats->hs_invocations = pq->result.coreFE.HsInvocations; |
| p_stats->ds_invocations = pq->result.coreFE.DsInvocations; |
| p_stats->cs_invocations = pq->result.core.CsInvocations; |
| } break; |
| case PIPE_QUERY_SO_OVERFLOW_PREDICATE: { |
| uint64_t num_primitives_written = |
| pq->result.coreFE.SoNumPrimsWritten[index]; |
| uint64_t primitives_storage_needed = |
| pq->result.coreFE.SoPrimStorageNeeded[index]; |
| 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->result, 0, sizeof(pq->result)); |
| switch (pq->type) { |
| case PIPE_QUERY_GPU_FINISHED: |
| case PIPE_QUERY_TIMESTAMP: |
| /* nothing to do, but don't want the default */ |
| break; |
| case PIPE_QUERY_TIME_ELAPSED: |
| pq->result.timestamp_start = swr_get_timestamp(pipe->screen); |
| break; |
| default: |
| /* Core counters required. Update draw context with location to |
| * store results. */ |
| swr_update_draw_context(ctx, &pq->result); |
| |
| /* Only change stat collection if there are no active queries */ |
| if (ctx->active_queries == 0) { |
| SwrEnableStatsFE(ctx->swrContext, TRUE); |
| SwrEnableStatsBE(ctx->swrContext, TRUE); |
| } |
| ctx->active_queries++; |
| break; |
| } |
| |
| |
| return true; |
| } |
| |
| static bool |
| 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); |
| |
| switch (pq->type) { |
| case PIPE_QUERY_GPU_FINISHED: |
| /* nothing to do, but don't want the default */ |
| break; |
| case PIPE_QUERY_TIMESTAMP: |
| case PIPE_QUERY_TIME_ELAPSED: |
| pq->result.timestamp_end = swr_get_timestamp(pipe->screen); |
| break; |
| default: |
| /* Stats are updated asynchronously, a fence is used to signal |
| * completion. */ |
| if (!pq->fence) { |
| struct swr_screen *screen = swr_screen(pipe->screen); |
| swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence); |
| } |
| swr_fence_submit(ctx, pq->fence); |
| |
| /* Only change stat collection if there are no active queries */ |
| ctx->active_queries--; |
| if (ctx->active_queries == 0) { |
| SwrEnableStatsFE(ctx->swrContext, FALSE); |
| SwrEnableStatsBE(ctx->swrContext, FALSE); |
| } |
| |
| break; |
| } |
| |
| return true; |
| } |
| |
| |
| 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; |
| } |
| |
| |
| static void |
| swr_set_active_query_state(struct pipe_context *pipe, boolean enable) |
| { |
| } |
| |
| 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; |
| pipe->set_active_query_state = swr_set_active_query_state; |
| |
| ctx->active_queries = 0; |
| } |