gallium/swr: add OpenSWR driver
[mesa.git] / src / gallium / drivers / swr / swr_query.cpp
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
33
34 static struct swr_query *
35 swr_query(struct pipe_query *p)
36 {
37 return (struct swr_query *)p;
38 }
39
40 static struct pipe_query *
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 = CALLOC_STRUCT(swr_query);
49
50 if (pq) {
51 pq->type = type;
52 pq->index = index;
53 }
54
55 return (struct pipe_query *)pq;
56 }
57
58
59 static void
60 swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
61 {
62 struct swr_query *pq = swr_query(q);
63
64 if (pq->fence) {
65 if (!swr_is_fence_done(swr_fence(pq->fence))) {
66 swr_fence_submit(swr_context(pipe), pq->fence);
67 swr_fence_finish(pipe->screen, pq->fence, 0);
68 }
69 swr_fence_reference(pipe->screen, &pq->fence, NULL);
70 }
71
72 FREE(pq);
73 }
74
75
76 // XXX Create a fence callback, rather than stalling SwrWaitForIdle
77 static void
78 swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq)
79 {
80 struct swr_context *ctx = swr_context(pipe);
81
82 assert(pq->result);
83 union pipe_query_result *result = pq->result;
84 boolean enable_stats = pq->enable_stats;
85 SWR_STATS swr_stats = {0};
86
87 if (pq->fence) {
88 if (!swr_is_fence_done(swr_fence(pq->fence))) {
89 swr_fence_submit(ctx, pq->fence);
90 swr_fence_finish(pipe->screen, pq->fence, 0);
91 }
92 swr_fence_reference(pipe->screen, &pq->fence, NULL);
93 }
94
95 /*
96 * These queries don't need SWR Stats enabled in the core
97 * Set and return.
98 */
99 switch (pq->type) {
100 case PIPE_QUERY_TIMESTAMP:
101 case PIPE_QUERY_TIME_ELAPSED:
102 result->u64 = swr_get_timestamp(pipe->screen);
103 return;
104 break;
105 case PIPE_QUERY_TIMESTAMP_DISJOINT:
106 /* nothing to do here */
107 return;
108 break;
109 case PIPE_QUERY_GPU_FINISHED:
110 result->b = TRUE; /* XXX TODO Add an api func to SWR to compare drawId
111 vs LastRetiredId? */
112 return;
113 break;
114 default:
115 /* Any query that needs SwrCore stats */
116 break;
117 }
118
119 /*
120 * All other results are collected from SwrCore counters
121 */
122
123 /* XXX, Should turn this into a fence callback and skip the stall */
124 SwrGetStats(ctx->swrContext, &swr_stats);
125 /* SwrGetStats returns immediately, wait for collection */
126 SwrWaitForIdle(ctx->swrContext);
127
128 switch (pq->type) {
129 case PIPE_QUERY_OCCLUSION_PREDICATE:
130 case PIPE_QUERY_OCCLUSION_COUNTER:
131 result->u64 = swr_stats.DepthPassCount;
132 break;
133 case PIPE_QUERY_PRIMITIVES_GENERATED:
134 result->u64 = swr_stats.IaPrimitives;
135 break;
136 case PIPE_QUERY_PRIMITIVES_EMITTED:
137 result->u64 = swr_stats.SoNumPrimsWritten[pq->index];
138 break;
139 case PIPE_QUERY_SO_STATISTICS:
140 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
141 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
142 so_stats->num_primitives_written =
143 swr_stats.SoNumPrimsWritten[pq->index];
144 so_stats->primitives_storage_needed =
145 swr_stats.SoPrimStorageNeeded[pq->index];
146 } break;
147 case PIPE_QUERY_PIPELINE_STATISTICS: {
148 struct pipe_query_data_pipeline_statistics *p_stats =
149 &result->pipeline_statistics;
150 p_stats->ia_vertices = swr_stats.IaVertices;
151 p_stats->ia_primitives = swr_stats.IaPrimitives;
152 p_stats->vs_invocations = swr_stats.VsInvocations;
153 p_stats->gs_invocations = swr_stats.GsInvocations;
154 p_stats->gs_primitives = swr_stats.GsPrimitives;
155 p_stats->c_invocations = swr_stats.CPrimitives;
156 p_stats->c_primitives = swr_stats.CPrimitives;
157 p_stats->ps_invocations = swr_stats.PsInvocations;
158 p_stats->hs_invocations = swr_stats.HsInvocations;
159 p_stats->ds_invocations = swr_stats.DsInvocations;
160 p_stats->cs_invocations = swr_stats.CsInvocations;
161 } break;
162 default:
163 assert(0 && "Unsupported query");
164 break;
165 }
166
167 /* Only change stat collection if there are no active queries */
168 if (ctx->active_queries == 0)
169 SwrEnableStats(ctx->swrContext, enable_stats);
170 }
171
172
173 static boolean
174 swr_get_query_result(struct pipe_context *pipe,
175 struct pipe_query *q,
176 boolean wait,
177 union pipe_query_result *result)
178 {
179 struct swr_context *ctx = swr_context(pipe);
180 struct swr_query *pq = swr_query(q);
181
182 if (pq->fence) {
183 if (!swr_is_fence_done(swr_fence(pq->fence))) {
184 swr_fence_submit(ctx, pq->fence);
185 if (!wait)
186 return FALSE;
187 swr_fence_finish(pipe->screen, pq->fence, 0);
188 }
189 swr_fence_reference(pipe->screen, &pq->fence, NULL);
190 }
191
192 /* XXX: Need to handle counter rollover */
193
194 switch (pq->type) {
195 /* Booleans */
196 case PIPE_QUERY_OCCLUSION_PREDICATE:
197 result->b = pq->end.u64 != pq->start.u64 ? TRUE : FALSE;
198 break;
199 case PIPE_QUERY_GPU_FINISHED:
200 result->b = pq->end.b;
201 break;
202 /* Counters */
203 case PIPE_QUERY_OCCLUSION_COUNTER:
204 case PIPE_QUERY_TIMESTAMP:
205 case PIPE_QUERY_TIME_ELAPSED:
206 case PIPE_QUERY_PRIMITIVES_GENERATED:
207 case PIPE_QUERY_PRIMITIVES_EMITTED:
208 result->u64 = pq->end.u64 - pq->start.u64;
209 break;
210 /* Structures */
211 case PIPE_QUERY_SO_STATISTICS: {
212 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
213 struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
214 struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
215 so_stats->num_primitives_written =
216 end->num_primitives_written - start->num_primitives_written;
217 so_stats->primitives_storage_needed =
218 end->primitives_storage_needed - start->primitives_storage_needed;
219 } break;
220 case PIPE_QUERY_TIMESTAMP_DISJOINT: {
221 /* os_get_time_nano returns nanoseconds */
222 result->timestamp_disjoint.frequency = UINT64_C(1000000000);
223 result->timestamp_disjoint.disjoint = FALSE;
224 } break;
225 case PIPE_QUERY_PIPELINE_STATISTICS: {
226 struct pipe_query_data_pipeline_statistics *p_stats =
227 &result->pipeline_statistics;
228 struct pipe_query_data_pipeline_statistics *start =
229 &pq->start.pipeline_statistics;
230 struct pipe_query_data_pipeline_statistics *end =
231 &pq->end.pipeline_statistics;
232 p_stats->ia_vertices = end->ia_vertices - start->ia_vertices;
233 p_stats->ia_primitives = end->ia_primitives - start->ia_primitives;
234 p_stats->vs_invocations = end->vs_invocations - start->vs_invocations;
235 p_stats->gs_invocations = end->gs_invocations - start->gs_invocations;
236 p_stats->gs_primitives = end->gs_primitives - start->gs_primitives;
237 p_stats->c_invocations = end->c_invocations - start->c_invocations;
238 p_stats->c_primitives = end->c_primitives - start->c_primitives;
239 p_stats->ps_invocations = end->ps_invocations - start->ps_invocations;
240 p_stats->hs_invocations = end->hs_invocations - start->hs_invocations;
241 p_stats->ds_invocations = end->ds_invocations - start->ds_invocations;
242 p_stats->cs_invocations = end->cs_invocations - start->cs_invocations;
243 } break;
244 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
245 struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
246 struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
247 uint64_t num_primitives_written =
248 end->num_primitives_written - start->num_primitives_written;
249 uint64_t primitives_storage_needed =
250 end->primitives_storage_needed - start->primitives_storage_needed;
251 result->b = num_primitives_written > primitives_storage_needed;
252 } break;
253 default:
254 assert(0 && "Unsupported query");
255 break;
256 }
257
258 return TRUE;
259 }
260
261 static boolean
262 swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
263 {
264 struct swr_context *ctx = swr_context(pipe);
265 struct swr_query *pq = swr_query(q);
266
267 /* Initialize Results */
268 memset(&pq->start, 0, sizeof(pq->start));
269 memset(&pq->end, 0, sizeof(pq->end));
270
271 /* Gather start stats and enable SwrCore counters */
272 pq->result = &pq->start;
273 pq->enable_stats = TRUE;
274 swr_gather_stats(pipe, pq);
275 ctx->active_queries++;
276
277 /* override start timestamp to 0 for TIMESTAMP query */
278 if (pq->type == PIPE_QUERY_TIMESTAMP)
279 pq->start.u64 = 0;
280
281 return true;
282 }
283
284 static void
285 swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
286 {
287 struct swr_context *ctx = swr_context(pipe);
288 struct swr_query *pq = swr_query(q);
289
290 assert(ctx->active_queries
291 && "swr_end_query, there are no active queries!");
292 ctx->active_queries--;
293
294 /* Gather end stats and disable SwrCore counters */
295 pq->result = &pq->end;
296 pq->enable_stats = FALSE;
297 swr_gather_stats(pipe, pq);
298 }
299
300
301 boolean
302 swr_check_render_cond(struct pipe_context *pipe)
303 {
304 struct swr_context *ctx = swr_context(pipe);
305 boolean b, wait;
306 uint64_t result;
307
308 if (!ctx->render_cond_query)
309 return TRUE; /* no query predicate, draw normally */
310
311 wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
312 || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
313
314 b = pipe->get_query_result(
315 pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
316 if (b)
317 return (!result == ctx->render_cond_cond);
318 else
319 return TRUE;
320 }
321
322 void
323 swr_query_init(struct pipe_context *pipe)
324 {
325 struct swr_context *ctx = swr_context(pipe);
326
327 pipe->create_query = swr_create_query;
328 pipe->destroy_query = swr_destroy_query;
329 pipe->begin_query = swr_begin_query;
330 pipe->end_query = swr_end_query;
331 pipe->get_query_result = swr_get_query_result;
332
333 ctx->active_queries = 0;
334 }