• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * Copyright (C) 2015 Intel Corporation.   All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  ***************************************************************************/
23 
24 #include "pipe/p_defines.h"
25 #include "util/u_memory.h"
26 #include "os/os_time.h"
27 #include "swr_context.h"
28 #include "swr_fence.h"
29 #include "swr_query.h"
30 #include "swr_screen.h"
31 #include "swr_state.h"
32 #include "common/os.h"
33 
34 static struct swr_query *
swr_query(struct pipe_query * p)35 swr_query(struct pipe_query *p)
36 {
37    return (struct swr_query *)p;
38 }
39 
40 static struct pipe_query *
swr_create_query(struct pipe_context * pipe,unsigned type,unsigned index)41 swr_create_query(struct pipe_context *pipe, unsigned type, unsigned index)
42 {
43    struct swr_query *pq;
44 
45    assert(type < PIPE_QUERY_TYPES);
46    assert(index < MAX_SO_STREAMS);
47 
48    pq = (struct swr_query *) AlignedMalloc(sizeof(struct swr_query), 64);
49    memset(pq, 0, sizeof(*pq));
50 
51    if (pq) {
52       pq->type = type;
53       pq->index = index;
54    }
55 
56    return (struct pipe_query *)pq;
57 }
58 
59 
60 static void
swr_destroy_query(struct pipe_context * pipe,struct pipe_query * q)61 swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
62 {
63    struct swr_query *pq = swr_query(q);
64 
65    if (pq->fence) {
66       if (swr_is_fence_pending(pq->fence))
67          swr_fence_finish(pipe->screen, NULL, pq->fence, 0);
68       swr_fence_reference(pipe->screen, &pq->fence, NULL);
69    }
70 
71    AlignedFree(pq);
72 }
73 
74 
75 static boolean
swr_get_query_result(struct pipe_context * pipe,struct pipe_query * q,boolean wait,union pipe_query_result * result)76 swr_get_query_result(struct pipe_context *pipe,
77                      struct pipe_query *q,
78                      boolean wait,
79                      union pipe_query_result *result)
80 {
81    struct swr_query *pq = swr_query(q);
82    unsigned index = pq->index;
83 
84    if (pq->fence) {
85       if (!wait && !swr_is_fence_done(pq->fence))
86          return FALSE;
87 
88       swr_fence_finish(pipe->screen, NULL, pq->fence, 0);
89       swr_fence_reference(pipe->screen, &pq->fence, NULL);
90    }
91 
92    /* All values are reset to 0 at swr_begin_query, except starting timestamp.
93     * Counters become simply end values.  */
94    switch (pq->type) {
95    /* Booleans */
96    case PIPE_QUERY_OCCLUSION_PREDICATE:
97       result->b = pq->result.core.DepthPassCount != 0;
98       break;
99    case PIPE_QUERY_GPU_FINISHED:
100       result->b = TRUE;
101       break;
102    /* Counters */
103    case PIPE_QUERY_OCCLUSION_COUNTER:
104       result->u64 = pq->result.core.DepthPassCount;
105       break;
106    case PIPE_QUERY_TIMESTAMP:
107    case PIPE_QUERY_TIME_ELAPSED:
108       result->u64 = pq->result.timestamp_end - pq->result.timestamp_start;
109       break;
110    case PIPE_QUERY_PRIMITIVES_GENERATED:
111       result->u64 = pq->result.coreFE.IaPrimitives;
112       break;
113    case PIPE_QUERY_PRIMITIVES_EMITTED:
114       result->u64 = pq->result.coreFE.SoNumPrimsWritten[index];
115       break;
116    /* Structures */
117    case PIPE_QUERY_SO_STATISTICS: {
118       struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
119       so_stats->num_primitives_written =
120          pq->result.coreFE.SoNumPrimsWritten[index];
121       so_stats->primitives_storage_needed =
122          pq->result.coreFE.SoPrimStorageNeeded[index];
123    } break;
124    case PIPE_QUERY_TIMESTAMP_DISJOINT:
125       /* os_get_time_nano returns nanoseconds */
126       result->timestamp_disjoint.frequency = UINT64_C(1000000000);
127       result->timestamp_disjoint.disjoint = FALSE;
128       break;
129    case PIPE_QUERY_PIPELINE_STATISTICS: {
130       struct pipe_query_data_pipeline_statistics *p_stats =
131          &result->pipeline_statistics;
132       p_stats->ia_vertices = pq->result.coreFE.IaVertices;
133       p_stats->ia_primitives = pq->result.coreFE.IaPrimitives;
134       p_stats->vs_invocations = pq->result.coreFE.VsInvocations;
135       p_stats->gs_invocations = pq->result.coreFE.GsInvocations;
136       p_stats->gs_primitives = pq->result.coreFE.GsPrimitives;
137       p_stats->c_invocations = pq->result.coreFE.CPrimitives;
138       p_stats->c_primitives = pq->result.coreFE.CPrimitives;
139       p_stats->ps_invocations = pq->result.core.PsInvocations;
140       p_stats->hs_invocations = pq->result.coreFE.HsInvocations;
141       p_stats->ds_invocations = pq->result.coreFE.DsInvocations;
142       p_stats->cs_invocations = pq->result.core.CsInvocations;
143     } break;
144    case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
145       uint64_t num_primitives_written =
146          pq->result.coreFE.SoNumPrimsWritten[index];
147       uint64_t primitives_storage_needed =
148          pq->result.coreFE.SoPrimStorageNeeded[index];
149       result->b = num_primitives_written > primitives_storage_needed;
150    }
151       break;
152    default:
153       assert(0 && "Unsupported query");
154       break;
155    }
156 
157    return TRUE;
158 }
159 
160 static boolean
swr_begin_query(struct pipe_context * pipe,struct pipe_query * q)161 swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
162 {
163    struct swr_context *ctx = swr_context(pipe);
164    struct swr_query *pq = swr_query(q);
165 
166    /* Initialize Results */
167    memset(&pq->result, 0, sizeof(pq->result));
168    switch (pq->type) {
169    case PIPE_QUERY_GPU_FINISHED:
170    case PIPE_QUERY_TIMESTAMP:
171       /* nothing to do, but don't want the default */
172       break;
173    case PIPE_QUERY_TIME_ELAPSED:
174       pq->result.timestamp_start = swr_get_timestamp(pipe->screen);
175       break;
176    default:
177       /* Core counters required.  Update draw context with location to
178        * store results. */
179       swr_update_draw_context(ctx, &pq->result);
180 
181       /* Only change stat collection if there are no active queries */
182       if (ctx->active_queries == 0) {
183          SwrEnableStatsFE(ctx->swrContext, TRUE);
184          SwrEnableStatsBE(ctx->swrContext, TRUE);
185       }
186       ctx->active_queries++;
187       break;
188    }
189 
190 
191    return true;
192 }
193 
194 static bool
swr_end_query(struct pipe_context * pipe,struct pipe_query * q)195 swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
196 {
197    struct swr_context *ctx = swr_context(pipe);
198    struct swr_query *pq = swr_query(q);
199 
200    switch (pq->type) {
201    case PIPE_QUERY_GPU_FINISHED:
202       /* nothing to do, but don't want the default */
203       break;
204    case PIPE_QUERY_TIMESTAMP:
205    case PIPE_QUERY_TIME_ELAPSED:
206       pq->result.timestamp_end = swr_get_timestamp(pipe->screen);
207       break;
208    default:
209       /* Stats are updated asynchronously, a fence is used to signal
210        * completion. */
211       if (!pq->fence) {
212          struct swr_screen *screen = swr_screen(pipe->screen);
213          swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence);
214       }
215       swr_fence_submit(ctx, pq->fence);
216 
217       /* Only change stat collection if there are no active queries */
218       ctx->active_queries--;
219       if (ctx->active_queries == 0) {
220          SwrEnableStatsFE(ctx->swrContext, FALSE);
221          SwrEnableStatsBE(ctx->swrContext, FALSE);
222       }
223 
224       break;
225    }
226 
227    return true;
228 }
229 
230 
231 boolean
swr_check_render_cond(struct pipe_context * pipe)232 swr_check_render_cond(struct pipe_context *pipe)
233 {
234    struct swr_context *ctx = swr_context(pipe);
235    boolean b, wait;
236    uint64_t result;
237 
238    if (!ctx->render_cond_query)
239       return TRUE; /* no query predicate, draw normally */
240 
241    wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
242            || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
243 
244    b = pipe->get_query_result(
245       pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
246    if (b)
247       return ((!result) == ctx->render_cond_cond);
248    else
249       return TRUE;
250 }
251 
252 
253 static void
swr_set_active_query_state(struct pipe_context * pipe,boolean enable)254 swr_set_active_query_state(struct pipe_context *pipe, boolean enable)
255 {
256 }
257 
258 void
swr_query_init(struct pipe_context * pipe)259 swr_query_init(struct pipe_context *pipe)
260 {
261    struct swr_context *ctx = swr_context(pipe);
262 
263    pipe->create_query = swr_create_query;
264    pipe->destroy_query = swr_destroy_query;
265    pipe->begin_query = swr_begin_query;
266    pipe->end_query = swr_end_query;
267    pipe->get_query_result = swr_get_query_result;
268    pipe->set_active_query_state = swr_set_active_query_state;
269 
270    ctx->active_queries = 0;
271 }
272