1 /**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
4 * Copyright 2010 VMware, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 /* Authors:
30 * Keith Whitwell, Qicheng Christopher Li, Brian Paul
31 */
32
33 #include "draw/draw_context.h"
34 #include "pipe/p_defines.h"
35 #include "util/u_memory.h"
36 #include "util/os_time.h"
37 #include "lp_context.h"
38 #include "lp_flush.h"
39 #include "lp_fence.h"
40 #include "lp_query.h"
41 #include "lp_screen.h"
42 #include "lp_state.h"
43 #include "lp_rast.h"
44
45
llvmpipe_query(struct pipe_query * p)46 static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )
47 {
48 return (struct llvmpipe_query *)p;
49 }
50
51 static struct pipe_query *
llvmpipe_create_query(struct pipe_context * pipe,unsigned type,unsigned index)52 llvmpipe_create_query(struct pipe_context *pipe,
53 unsigned type,
54 unsigned index)
55 {
56 struct llvmpipe_query *pq;
57
58 assert(type < PIPE_QUERY_TYPES);
59
60 pq = CALLOC_STRUCT( llvmpipe_query );
61
62 if (pq) {
63 pq->type = type;
64 pq->index = index;
65 }
66
67 return (struct pipe_query *) pq;
68 }
69
70
71 static void
llvmpipe_destroy_query(struct pipe_context * pipe,struct pipe_query * q)72 llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
73 {
74 struct llvmpipe_query *pq = llvmpipe_query(q);
75
76 /* Ideally we would refcount queries & not get destroyed until the
77 * last scene had finished with us.
78 */
79 if (pq->fence) {
80 if (!lp_fence_issued(pq->fence))
81 llvmpipe_flush(pipe, NULL, __FUNCTION__);
82
83 if (!lp_fence_signalled(pq->fence))
84 lp_fence_wait(pq->fence);
85
86 lp_fence_reference(&pq->fence, NULL);
87 }
88
89 FREE(pq);
90 }
91
92
93 static bool
llvmpipe_get_query_result(struct pipe_context * pipe,struct pipe_query * q,bool wait,union pipe_query_result * vresult)94 llvmpipe_get_query_result(struct pipe_context *pipe,
95 struct pipe_query *q,
96 bool wait,
97 union pipe_query_result *vresult)
98 {
99 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
100 unsigned num_threads = MAX2(1, screen->num_threads);
101 struct llvmpipe_query *pq = llvmpipe_query(q);
102 uint64_t *result = (uint64_t *)vresult;
103 int i;
104
105 if (pq->fence) {
106 /* only have a fence if there was a scene */
107 if (!lp_fence_signalled(pq->fence)) {
108 if (!lp_fence_issued(pq->fence))
109 llvmpipe_flush(pipe, NULL, __FUNCTION__);
110
111 if (!wait)
112 return false;
113
114 lp_fence_wait(pq->fence);
115 }
116 }
117
118 /* Sum the results from each of the threads:
119 */
120 *result = 0;
121
122 switch (pq->type) {
123 case PIPE_QUERY_OCCLUSION_COUNTER:
124 for (i = 0; i < num_threads; i++) {
125 *result += pq->end[i];
126 }
127 break;
128 case PIPE_QUERY_OCCLUSION_PREDICATE:
129 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
130 for (i = 0; i < num_threads; i++) {
131 /* safer (still not guaranteed) when there's an overflow */
132 vresult->b = vresult->b || pq->end[i];
133 }
134 break;
135 case PIPE_QUERY_TIMESTAMP:
136 for (i = 0; i < num_threads; i++) {
137 if (pq->end[i] > *result) {
138 *result = pq->end[i];
139 }
140 }
141 break;
142 case PIPE_QUERY_TIME_ELAPSED: {
143 uint64_t start = (uint64_t)-1, end = 0;
144 for (i = 0; i < num_threads; i++) {
145 if (pq->start[i] && pq->start[i] < start)
146 start = pq->start[i];
147 if (pq->end[i] && pq->end[i] > end)
148 end = pq->end[i];
149 }
150 *result = end - start;
151 break;
152 }
153 case PIPE_QUERY_TIMESTAMP_DISJOINT: {
154 struct pipe_query_data_timestamp_disjoint *td =
155 (struct pipe_query_data_timestamp_disjoint *)vresult;
156 /* os_get_time_nano return nanoseconds */
157 td->frequency = UINT64_C(1000000000);
158 td->disjoint = false;
159 }
160 break;
161 case PIPE_QUERY_GPU_FINISHED:
162 vresult->b = true;
163 break;
164 case PIPE_QUERY_PRIMITIVES_GENERATED:
165 *result = pq->num_primitives_generated[0];
166 break;
167 case PIPE_QUERY_PRIMITIVES_EMITTED:
168 *result = pq->num_primitives_written[0];
169 break;
170 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
171 vresult->b = false;
172 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)
173 vresult->b |= pq->num_primitives_generated[s] > pq->num_primitives_written[s];
174 break;
175 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
176 vresult->b = pq->num_primitives_generated[0] > pq->num_primitives_written[0];
177 break;
178 case PIPE_QUERY_SO_STATISTICS: {
179 struct pipe_query_data_so_statistics *stats =
180 (struct pipe_query_data_so_statistics *)vresult;
181 stats->num_primitives_written = pq->num_primitives_written[0];
182 stats->primitives_storage_needed = pq->num_primitives_generated[0];
183 }
184 break;
185 case PIPE_QUERY_PIPELINE_STATISTICS: {
186 struct pipe_query_data_pipeline_statistics *stats =
187 (struct pipe_query_data_pipeline_statistics *)vresult;
188 /* only ps_invocations come from binned query */
189 for (i = 0; i < num_threads; i++) {
190 pq->stats.ps_invocations += pq->end[i];
191 }
192 pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
193 *stats = pq->stats;
194 }
195 break;
196 default:
197 assert(0);
198 break;
199 }
200
201 return true;
202 }
203
204 static void
llvmpipe_get_query_result_resource(struct pipe_context * pipe,struct pipe_query * q,bool wait,enum pipe_query_value_type result_type,int index,struct pipe_resource * resource,unsigned offset)205 llvmpipe_get_query_result_resource(struct pipe_context *pipe,
206 struct pipe_query *q,
207 bool wait,
208 enum pipe_query_value_type result_type,
209 int index,
210 struct pipe_resource *resource,
211 unsigned offset)
212 {
213 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
214 unsigned num_threads = MAX2(1, screen->num_threads);
215 struct llvmpipe_query *pq = llvmpipe_query(q);
216 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
217 bool unsignalled = false;
218 if (pq->fence) {
219 /* only have a fence if there was a scene */
220 if (!lp_fence_signalled(pq->fence)) {
221 if (!lp_fence_issued(pq->fence))
222 llvmpipe_flush(pipe, NULL, __FUNCTION__);
223
224 if (wait)
225 lp_fence_wait(pq->fence);
226 }
227 unsignalled = !lp_fence_signalled(pq->fence);
228 }
229
230
231 uint64_t value = 0, value2 = 0;
232 unsigned num_values = 1;
233 if (index == -1)
234 if (unsignalled)
235 value = 0;
236 else
237 value = 1;
238 else {
239 unsigned i;
240
241 switch (pq->type) {
242 case PIPE_QUERY_OCCLUSION_COUNTER:
243 for (i = 0; i < num_threads; i++) {
244 value += pq->end[i];
245 }
246 break;
247 case PIPE_QUERY_OCCLUSION_PREDICATE:
248 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
249 for (i = 0; i < num_threads; i++) {
250 /* safer (still not guaranteed) when there's an overflow */
251 value = value || pq->end[i];
252 }
253 break;
254 case PIPE_QUERY_PRIMITIVES_GENERATED:
255 value = pq->num_primitives_generated[0];
256 break;
257 case PIPE_QUERY_PRIMITIVES_EMITTED:
258 value = pq->num_primitives_written[0];
259 break;
260 case PIPE_QUERY_TIMESTAMP:
261 for (i = 0; i < num_threads; i++) {
262 if (pq->end[i] > value) {
263 value = pq->end[i];
264 }
265 }
266 break;
267 case PIPE_QUERY_TIME_ELAPSED: {
268 uint64_t start = (uint64_t)-1, end = 0;
269 for (i = 0; i < num_threads; i++) {
270 if (pq->start[i] && pq->start[i] < start)
271 start = pq->start[i];
272 if (pq->end[i] && pq->end[i] > end)
273 end = pq->end[i];
274 }
275 value = end - start;
276 break;
277 }
278 case PIPE_QUERY_SO_STATISTICS:
279 value = pq->num_primitives_written[0];
280 value2 = pq->num_primitives_generated[0];
281 num_values = 2;
282 break;
283 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
284 value = 0;
285 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)
286 value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]);
287 break;
288 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
289 value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]);
290 break;
291 case PIPE_QUERY_PIPELINE_STATISTICS:
292 switch ((enum pipe_statistics_query_index)index) {
293 case PIPE_STAT_QUERY_IA_VERTICES:
294 value = pq->stats.ia_vertices;
295 break;
296 case PIPE_STAT_QUERY_IA_PRIMITIVES:
297 value = pq->stats.ia_primitives;
298 break;
299 case PIPE_STAT_QUERY_VS_INVOCATIONS:
300 value = pq->stats.vs_invocations;
301 break;
302 case PIPE_STAT_QUERY_GS_INVOCATIONS:
303 value = pq->stats.gs_invocations;
304 break;
305 case PIPE_STAT_QUERY_GS_PRIMITIVES:
306 value = pq->stats.gs_primitives;
307 break;
308 case PIPE_STAT_QUERY_C_INVOCATIONS:
309 value = pq->stats.c_invocations;
310 break;
311 case PIPE_STAT_QUERY_C_PRIMITIVES:
312 value = pq->stats.c_primitives;
313 break;
314 case PIPE_STAT_QUERY_PS_INVOCATIONS:
315 value = 0;
316 for (i = 0; i < num_threads; i++) {
317 value += pq->end[i];
318 }
319 value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
320 break;
321 case PIPE_STAT_QUERY_HS_INVOCATIONS:
322 value = pq->stats.hs_invocations;
323 break;
324 case PIPE_STAT_QUERY_DS_INVOCATIONS:
325 value = pq->stats.ds_invocations;
326 break;
327 case PIPE_STAT_QUERY_CS_INVOCATIONS:
328 value = pq->stats.cs_invocations;
329 break;
330 }
331 break;
332 default:
333 fprintf(stderr, "Unknown query type %d\n", pq->type);
334 break;
335 }
336 }
337
338 void *dst = (uint8_t *)lpr->data + offset;
339
340 for (unsigned i = 0; i < num_values; i++) {
341
342 if (i == 1) {
343 value = value2;
344 dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 ||
345 result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4);
346 }
347 switch (result_type) {
348 case PIPE_QUERY_TYPE_I32: {
349 int32_t *iptr = (int32_t *)dst;
350 if (value > 0x7fffffff)
351 *iptr = 0x7fffffff;
352 else
353 *iptr = (int32_t)value;
354 break;
355 }
356 case PIPE_QUERY_TYPE_U32: {
357 uint32_t *uptr = (uint32_t *)dst;
358 if (value > 0xffffffff)
359 *uptr = 0xffffffff;
360 else
361 *uptr = (uint32_t)value;
362 break;
363 }
364 case PIPE_QUERY_TYPE_I64: {
365 int64_t *iptr = (int64_t *)dst;
366 *iptr = (int64_t)value;
367 break;
368 }
369 case PIPE_QUERY_TYPE_U64: {
370 uint64_t *uptr = (uint64_t *)dst;
371 *uptr = (uint64_t)value;
372 break;
373 }
374 }
375 }
376 }
377
378 static bool
llvmpipe_begin_query(struct pipe_context * pipe,struct pipe_query * q)379 llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
380 {
381 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
382 struct llvmpipe_query *pq = llvmpipe_query(q);
383
384 /* Check if the query is already in the scene. If so, we need to
385 * flush the scene now. Real apps shouldn't re-use a query in a
386 * frame of rendering.
387 */
388 if (pq->fence && !lp_fence_issued(pq->fence)) {
389 llvmpipe_finish(pipe, __FUNCTION__);
390 }
391
392
393 memset(pq->start, 0, sizeof(pq->start));
394 memset(pq->end, 0, sizeof(pq->end));
395 lp_setup_begin_query(llvmpipe->setup, pq);
396
397 switch (pq->type) {
398 case PIPE_QUERY_PRIMITIVES_EMITTED:
399 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
400 break;
401 case PIPE_QUERY_PRIMITIVES_GENERATED:
402 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
403 llvmpipe->active_primgen_queries++;
404 break;
405 case PIPE_QUERY_SO_STATISTICS:
406 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
407 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
408 break;
409 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
410 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
411 pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written;
412 pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed;
413 }
414 break;
415 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
416 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
417 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
418 break;
419 case PIPE_QUERY_PIPELINE_STATISTICS:
420 /* reset our cache */
421 if (llvmpipe->active_statistics_queries == 0) {
422 memset(&llvmpipe->pipeline_statistics, 0,
423 sizeof(llvmpipe->pipeline_statistics));
424 }
425 memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
426 llvmpipe->active_statistics_queries++;
427 break;
428 case PIPE_QUERY_OCCLUSION_COUNTER:
429 case PIPE_QUERY_OCCLUSION_PREDICATE:
430 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
431 llvmpipe->active_occlusion_queries++;
432 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
433 break;
434 default:
435 break;
436 }
437 return true;
438 }
439
440
441 static bool
llvmpipe_end_query(struct pipe_context * pipe,struct pipe_query * q)442 llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
443 {
444 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
445 struct llvmpipe_query *pq = llvmpipe_query(q);
446
447 lp_setup_end_query(llvmpipe->setup, pq);
448
449 switch (pq->type) {
450
451 case PIPE_QUERY_PRIMITIVES_EMITTED:
452 pq->num_primitives_written[0] =
453 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
454 break;
455 case PIPE_QUERY_PRIMITIVES_GENERATED:
456 assert(llvmpipe->active_primgen_queries);
457 llvmpipe->active_primgen_queries--;
458 pq->num_primitives_generated[0] =
459 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
460 break;
461 case PIPE_QUERY_SO_STATISTICS:
462 pq->num_primitives_written[0] =
463 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
464 pq->num_primitives_generated[0] =
465 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
466 break;
467 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
468 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
469 pq->num_primitives_written[s] =
470 llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s];
471 pq->num_primitives_generated[s] =
472 llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s];
473 }
474 break;
475 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
476 pq->num_primitives_written[0] =
477 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
478 pq->num_primitives_generated[0] =
479 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
480 break;
481 case PIPE_QUERY_PIPELINE_STATISTICS:
482 pq->stats.ia_vertices =
483 llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
484 pq->stats.ia_primitives =
485 llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
486 pq->stats.vs_invocations =
487 llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
488 pq->stats.gs_invocations =
489 llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
490 pq->stats.gs_primitives =
491 llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
492 pq->stats.c_invocations =
493 llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
494 pq->stats.c_primitives =
495 llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
496 pq->stats.ps_invocations =
497 llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
498 pq->stats.cs_invocations =
499 llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations;
500 pq->stats.hs_invocations =
501 llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations;
502 pq->stats.ds_invocations =
503 llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations;
504 llvmpipe->active_statistics_queries--;
505 break;
506 case PIPE_QUERY_OCCLUSION_COUNTER:
507 case PIPE_QUERY_OCCLUSION_PREDICATE:
508 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
509 assert(llvmpipe->active_occlusion_queries);
510 llvmpipe->active_occlusion_queries--;
511 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
512 break;
513 default:
514 break;
515 }
516
517 return true;
518 }
519
520 boolean
llvmpipe_check_render_cond(struct llvmpipe_context * lp)521 llvmpipe_check_render_cond(struct llvmpipe_context *lp)
522 {
523 struct pipe_context *pipe = &lp->pipe;
524 boolean b, wait;
525 uint64_t result;
526
527 if (lp->render_cond_buffer) {
528 uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset);
529 return (!data) == lp->render_cond_cond;
530 }
531 if (!lp->render_cond_query)
532 return TRUE; /* no query predicate, draw normally */
533
534 wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
535 lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
536
537 b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
538 if (b)
539 return ((!result) == lp->render_cond_cond);
540 else
541 return TRUE;
542 }
543
544 static void
llvmpipe_set_active_query_state(struct pipe_context * pipe,bool enable)545 llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable)
546 {
547 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
548
549 llvmpipe->queries_disabled = !enable;
550 /* for OQs we need to regenerate the fragment shader */
551 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
552 }
553
llvmpipe_init_query_funcs(struct llvmpipe_context * llvmpipe)554 void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
555 {
556 llvmpipe->pipe.create_query = llvmpipe_create_query;
557 llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
558 llvmpipe->pipe.begin_query = llvmpipe_begin_query;
559 llvmpipe->pipe.end_query = llvmpipe_end_query;
560 llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
561 llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource;
562 llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
563 }
564
565
566