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