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 "util/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
50 if (pq) {
51 memset(pq, 0, sizeof(*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 bool
swr_get_query_result(struct pipe_context * pipe,struct pipe_query * q,bool wait,union pipe_query_result * result)76 swr_get_query_result(struct pipe_context *pipe,
77 struct pipe_query *q,
78 bool 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 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
98 result->b = pq->result.core.DepthPassCount != 0;
99 break;
100 case PIPE_QUERY_GPU_FINISHED:
101 result->b = true;
102 break;
103 /* Counters */
104 case PIPE_QUERY_OCCLUSION_COUNTER:
105 result->u64 = pq->result.core.DepthPassCount;
106 break;
107 case PIPE_QUERY_TIMESTAMP:
108 case PIPE_QUERY_TIME_ELAPSED:
109 result->u64 = pq->result.timestamp_end - pq->result.timestamp_start;
110 break;
111 case PIPE_QUERY_PRIMITIVES_GENERATED:
112 result->u64 = pq->result.coreFE.IaPrimitives;
113 break;
114 case PIPE_QUERY_PRIMITIVES_EMITTED:
115 result->u64 = pq->result.coreFE.SoNumPrimsWritten[index];
116 break;
117 /* Structures */
118 case PIPE_QUERY_SO_STATISTICS: {
119 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
120 so_stats->num_primitives_written =
121 pq->result.coreFE.SoNumPrimsWritten[index];
122 so_stats->primitives_storage_needed =
123 pq->result.coreFE.SoPrimStorageNeeded[index];
124 } break;
125 case PIPE_QUERY_TIMESTAMP_DISJOINT:
126 /* os_get_time_nano returns nanoseconds */
127 result->timestamp_disjoint.frequency = UINT64_C(1000000000);
128 result->timestamp_disjoint.disjoint = FALSE;
129 break;
130 case PIPE_QUERY_PIPELINE_STATISTICS: {
131 struct pipe_query_data_pipeline_statistics *p_stats =
132 &result->pipeline_statistics;
133 p_stats->ia_vertices = pq->result.coreFE.IaVertices;
134 p_stats->ia_primitives = pq->result.coreFE.IaPrimitives;
135 p_stats->vs_invocations = pq->result.coreFE.VsInvocations;
136 p_stats->gs_invocations = pq->result.coreFE.GsInvocations;
137 p_stats->gs_primitives = pq->result.coreFE.GsPrimitives;
138 p_stats->c_invocations = pq->result.coreFE.CPrimitives;
139 p_stats->c_primitives = pq->result.coreFE.CPrimitives;
140 p_stats->ps_invocations = pq->result.core.PsInvocations;
141 p_stats->hs_invocations = pq->result.coreFE.HsInvocations;
142 p_stats->ds_invocations = pq->result.coreFE.DsInvocations;
143 p_stats->cs_invocations = pq->result.core.CsInvocations;
144 } break;
145 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
146 uint64_t num_primitives_written =
147 pq->result.coreFE.SoNumPrimsWritten[index];
148 uint64_t primitives_storage_needed =
149 pq->result.coreFE.SoPrimStorageNeeded[index];
150 result->b = num_primitives_written > primitives_storage_needed;
151 }
152 break;
153 default:
154 assert(0 && "Unsupported query");
155 break;
156 }
157
158 return true;
159 }
160
161 static bool
swr_begin_query(struct pipe_context * pipe,struct pipe_query * q)162 swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
163 {
164 struct swr_context *ctx = swr_context(pipe);
165 struct swr_query *pq = swr_query(q);
166
167 /* Initialize Results */
168 memset(&pq->result, 0, sizeof(pq->result));
169 switch (pq->type) {
170 case PIPE_QUERY_GPU_FINISHED:
171 case PIPE_QUERY_TIMESTAMP:
172 /* nothing to do, but don't want the default */
173 break;
174 case PIPE_QUERY_TIME_ELAPSED:
175 pq->result.timestamp_start = swr_get_timestamp(pipe->screen);
176 break;
177 default:
178 /* Core counters required. Update draw context with location to
179 * store results. */
180 swr_update_draw_context(ctx, &pq->result);
181
182 /* Only change stat collection if there are no active queries */
183 if (ctx->active_queries == 0) {
184 ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, TRUE);
185 ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, TRUE);
186 }
187 ctx->active_queries++;
188 break;
189 }
190
191
192 return true;
193 }
194
195 static bool
swr_end_query(struct pipe_context * pipe,struct pipe_query * q)196 swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
197 {
198 struct swr_context *ctx = swr_context(pipe);
199 struct swr_query *pq = swr_query(q);
200
201 switch (pq->type) {
202 case PIPE_QUERY_GPU_FINISHED:
203 /* nothing to do, but don't want the default */
204 break;
205 case PIPE_QUERY_TIMESTAMP:
206 case PIPE_QUERY_TIME_ELAPSED:
207 pq->result.timestamp_end = swr_get_timestamp(pipe->screen);
208 break;
209 default:
210 /* Stats are updated asynchronously, a fence is used to signal
211 * completion. */
212 if (!pq->fence) {
213 struct swr_screen *screen = swr_screen(pipe->screen);
214 swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence);
215 }
216 swr_fence_submit(ctx, pq->fence);
217
218 /* Only change stat collection if there are no active queries */
219 ctx->active_queries--;
220 if (ctx->active_queries == 0) {
221 ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, FALSE);
222 ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, FALSE);
223 }
224
225 break;
226 }
227
228 return true;
229 }
230
231
232 bool
swr_check_render_cond(struct pipe_context * pipe)233 swr_check_render_cond(struct pipe_context *pipe)
234 {
235 struct swr_context *ctx = swr_context(pipe);
236 bool b, wait;
237 uint64_t result;
238
239 if (!ctx->render_cond_query)
240 return true; /* no query predicate, draw normally */
241
242 wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
243 || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
244
245 b = pipe->get_query_result(
246 pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
247 if (b)
248 return ((!result) == ctx->render_cond_cond);
249 else
250 return true;
251 }
252
253
254 static void
swr_set_active_query_state(struct pipe_context * pipe,bool enable)255 swr_set_active_query_state(struct pipe_context *pipe, bool enable)
256 {
257 }
258
259 void
swr_query_init(struct pipe_context * pipe)260 swr_query_init(struct pipe_context *pipe)
261 {
262 struct swr_context *ctx = swr_context(pipe);
263
264 pipe->create_query = swr_create_query;
265 pipe->destroy_query = swr_destroy_query;
266 pipe->begin_query = swr_begin_query;
267 pipe->end_query = swr_end_query;
268 pipe->get_query_result = swr_get_query_result;
269 pipe->set_active_query_state = swr_set_active_query_state;
270
271 ctx->active_queries = 0;
272 }
273