swr: [rasterizer jitter] fetch support for offsetting VertexID
[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 void
75 swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq)
76 {
77 struct swr_context *ctx = swr_context(pipe);
78
79 assert(pq->result);
80 struct swr_query_result *result = pq->result;
81 boolean enable_stats = pq->enable_stats;
82
83 /* A few results don't require the core, so don't involve it */
84 switch (pq->type) {
85 case PIPE_QUERY_TIMESTAMP:
86 case PIPE_QUERY_TIME_ELAPSED:
87 result->timestamp = swr_get_timestamp(pipe->screen);
88 break;
89 case PIPE_QUERY_TIMESTAMP_DISJOINT:
90 case PIPE_QUERY_GPU_FINISHED:
91 /* nothing to do here */
92 break;
93 default:
94 /* TODO: should fence instead of stalling pipeline */
95 SwrWaitForIdle(ctx->swrContext);
96 memcpy(&result->core, &ctx->stats, sizeof(result->core));
97
98 #if 0
99 if (!pq->fence) {
100 struct swr_screen *screen = swr_screen(pipe->screen);
101 swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence);
102 }
103 swr_fence_submit(ctx, pq->fence);
104 #endif
105
106 /* Only change stat collection if there are no active queries */
107 if (ctx->active_queries == 0)
108 SwrEnableStats(ctx->swrContext, enable_stats);
109
110 break;
111 }
112 }
113
114
115 static boolean
116 swr_get_query_result(struct pipe_context *pipe,
117 struct pipe_query *q,
118 boolean wait,
119 union pipe_query_result *result)
120 {
121 struct swr_query *pq = swr_query(q);
122 struct swr_query_result *start = &pq->start;
123 struct swr_query_result *end = &pq->end;
124 unsigned index = pq->index;
125
126 if (pq->fence) {
127 if (!wait && !swr_is_fence_done(pq->fence))
128 return FALSE;
129
130 swr_fence_finish(pipe->screen, NULL, pq->fence, 0);
131 swr_fence_reference(pipe->screen, &pq->fence, NULL);
132 }
133
134 /* XXX: Need to handle counter rollover */
135
136 switch (pq->type) {
137 /* Booleans */
138 case PIPE_QUERY_OCCLUSION_PREDICATE:
139 result->b = end->core.DepthPassCount != start->core.DepthPassCount;
140 break;
141 case PIPE_QUERY_GPU_FINISHED:
142 result->b = TRUE;
143 break;
144 /* Counters */
145 case PIPE_QUERY_OCCLUSION_COUNTER:
146 result->u64 = end->core.DepthPassCount - start->core.DepthPassCount;
147 break;
148 case PIPE_QUERY_TIMESTAMP:
149 case PIPE_QUERY_TIME_ELAPSED:
150 result->u64 = end->timestamp - start->timestamp;
151 break;
152 case PIPE_QUERY_PRIMITIVES_GENERATED:
153 result->u64 = end->core.IaPrimitives - start->core.IaPrimitives;
154 break;
155 case PIPE_QUERY_PRIMITIVES_EMITTED:
156 result->u64 = end->core.SoNumPrimsWritten[index]
157 - start->core.SoNumPrimsWritten[index];
158 break;
159 /* Structures */
160 case PIPE_QUERY_SO_STATISTICS: {
161 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
162 struct SWR_STATS *start = &pq->start.core;
163 struct SWR_STATS *end = &pq->end.core;
164 so_stats->num_primitives_written =
165 end->SoNumPrimsWritten[index] - start->SoNumPrimsWritten[index];
166 so_stats->primitives_storage_needed =
167 end->SoPrimStorageNeeded[index] - start->SoPrimStorageNeeded[index];
168 } break;
169 case PIPE_QUERY_TIMESTAMP_DISJOINT:
170 /* os_get_time_nano returns nanoseconds */
171 result->timestamp_disjoint.frequency = UINT64_C(1000000000);
172 result->timestamp_disjoint.disjoint = FALSE;
173 break;
174 case PIPE_QUERY_PIPELINE_STATISTICS: {
175 struct pipe_query_data_pipeline_statistics *p_stats =
176 &result->pipeline_statistics;
177 struct SWR_STATS *start = &pq->start.core;
178 struct SWR_STATS *end = &pq->end.core;
179 p_stats->ia_vertices = end->IaVertices - start->IaVertices;
180 p_stats->ia_primitives = end->IaPrimitives - start->IaPrimitives;
181 p_stats->vs_invocations = end->VsInvocations - start->VsInvocations;
182 p_stats->gs_invocations = end->GsInvocations - start->GsInvocations;
183 p_stats->gs_primitives = end->GsPrimitives - start->GsPrimitives;
184 p_stats->c_invocations = end->CPrimitives - start->CPrimitives;
185 p_stats->c_primitives = end->CPrimitives - start->CPrimitives;
186 p_stats->ps_invocations = end->PsInvocations - start->PsInvocations;
187 p_stats->hs_invocations = end->HsInvocations - start->HsInvocations;
188 p_stats->ds_invocations = end->DsInvocations - start->DsInvocations;
189 p_stats->cs_invocations = end->CsInvocations - start->CsInvocations;
190 } break;
191 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
192 struct SWR_STATS *start = &pq->start.core;
193 struct SWR_STATS *end = &pq->end.core;
194 uint64_t num_primitives_written =
195 end->SoNumPrimsWritten[index] - start->SoNumPrimsWritten[index];
196 uint64_t primitives_storage_needed =
197 end->SoPrimStorageNeeded[index] - start->SoPrimStorageNeeded[index];
198 result->b = num_primitives_written > primitives_storage_needed;
199 }
200 break;
201 default:
202 assert(0 && "Unsupported query");
203 break;
204 }
205
206 return TRUE;
207 }
208
209 static boolean
210 swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
211 {
212 struct swr_context *ctx = swr_context(pipe);
213 struct swr_query *pq = swr_query(q);
214
215 assert(!pq->enable_stats && "swr_begin_query: Query is already active!");
216
217 /* Initialize Results */
218 memset(&pq->start, 0, sizeof(pq->start));
219 memset(&pq->end, 0, sizeof(pq->end));
220
221 /* Gather start stats and enable SwrCore counters */
222 pq->result = &pq->start;
223 pq->enable_stats = TRUE;
224 swr_gather_stats(pipe, pq);
225 ctx->active_queries++;
226
227 /* override start timestamp to 0 for TIMESTAMP query */
228 if (pq->type == PIPE_QUERY_TIMESTAMP)
229 pq->start.timestamp = 0;
230
231 return true;
232 }
233
234 static bool
235 swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
236 {
237 struct swr_context *ctx = swr_context(pipe);
238 struct swr_query *pq = swr_query(q);
239
240 assert(ctx->active_queries
241 && "swr_end_query, there are no active queries!");
242 ctx->active_queries--;
243
244 /* Gather end stats and disable SwrCore counters */
245 pq->result = &pq->end;
246 pq->enable_stats = FALSE;
247 swr_gather_stats(pipe, pq);
248 return true;
249 }
250
251
252 boolean
253 swr_check_render_cond(struct pipe_context *pipe)
254 {
255 struct swr_context *ctx = swr_context(pipe);
256 boolean b, wait;
257 uint64_t result;
258
259 if (!ctx->render_cond_query)
260 return TRUE; /* no query predicate, draw normally */
261
262 wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
263 || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
264
265 b = pipe->get_query_result(
266 pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
267 if (b)
268 return ((!result) == ctx->render_cond_cond);
269 else
270 return TRUE;
271 }
272
273
274 static void
275 swr_set_active_query_state(struct pipe_context *pipe, boolean enable)
276 {
277 }
278
279 void
280 swr_query_init(struct pipe_context *pipe)
281 {
282 struct swr_context *ctx = swr_context(pipe);
283
284 pipe->create_query = swr_create_query;
285 pipe->destroy_query = swr_destroy_query;
286 pipe->begin_query = swr_begin_query;
287 pipe->end_query = swr_end_query;
288 pipe->get_query_result = swr_get_query_result;
289 pipe->set_active_query_state = swr_set_active_query_state;
290
291 ctx->active_queries = 0;
292 }