Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/llvmpipe/lp_query.c
4570 views
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
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 *
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
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
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
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 unflushed = false;
218
bool unsignalled = false;
219
if (pq->fence) {
220
/* only have a fence if there was a scene */
221
if (!lp_fence_signalled(pq->fence)) {
222
unsignalled = true;
223
if (!lp_fence_issued(pq->fence))
224
unflushed = true;
225
}
226
}
227
228
229
uint64_t value = 0, value2 = 0;
230
unsigned num_values = 1;
231
if (index == -1)
232
if (unsignalled)
233
value = 0;
234
else
235
value = 1;
236
else {
237
unsigned i;
238
239
if (unflushed) {
240
llvmpipe_flush(pipe, NULL, __FUNCTION__);
241
242
if (!wait)
243
return;
244
245
lp_fence_wait(pq->fence);
246
}
247
248
switch (pq->type) {
249
case PIPE_QUERY_OCCLUSION_COUNTER:
250
for (i = 0; i < num_threads; i++) {
251
value += pq->end[i];
252
}
253
break;
254
case PIPE_QUERY_OCCLUSION_PREDICATE:
255
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
256
for (i = 0; i < num_threads; i++) {
257
/* safer (still not guaranteed) when there's an overflow */
258
value = value || pq->end[i];
259
}
260
break;
261
case PIPE_QUERY_PRIMITIVES_GENERATED:
262
value = pq->num_primitives_generated[0];
263
break;
264
case PIPE_QUERY_PRIMITIVES_EMITTED:
265
value = pq->num_primitives_written[0];
266
break;
267
case PIPE_QUERY_TIMESTAMP:
268
for (i = 0; i < num_threads; i++) {
269
if (pq->end[i] > value) {
270
value = pq->end[i];
271
}
272
}
273
break;
274
case PIPE_QUERY_TIME_ELAPSED: {
275
uint64_t start = (uint64_t)-1, end = 0;
276
for (i = 0; i < num_threads; i++) {
277
if (pq->start[i] && pq->start[i] < start)
278
start = pq->start[i];
279
if (pq->end[i] && pq->end[i] > end)
280
end = pq->end[i];
281
}
282
value = end - start;
283
break;
284
}
285
case PIPE_QUERY_SO_STATISTICS:
286
value = pq->num_primitives_written[0];
287
value2 = pq->num_primitives_generated[0];
288
num_values = 2;
289
break;
290
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
291
value = 0;
292
for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)
293
value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]);
294
break;
295
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
296
value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]);
297
break;
298
case PIPE_QUERY_PIPELINE_STATISTICS:
299
switch ((enum pipe_statistics_query_index)index) {
300
case PIPE_STAT_QUERY_IA_VERTICES:
301
value = pq->stats.ia_vertices;
302
break;
303
case PIPE_STAT_QUERY_IA_PRIMITIVES:
304
value = pq->stats.ia_primitives;
305
break;
306
case PIPE_STAT_QUERY_VS_INVOCATIONS:
307
value = pq->stats.vs_invocations;
308
break;
309
case PIPE_STAT_QUERY_GS_INVOCATIONS:
310
value = pq->stats.gs_invocations;
311
break;
312
case PIPE_STAT_QUERY_GS_PRIMITIVES:
313
value = pq->stats.gs_primitives;
314
break;
315
case PIPE_STAT_QUERY_C_INVOCATIONS:
316
value = pq->stats.c_invocations;
317
break;
318
case PIPE_STAT_QUERY_C_PRIMITIVES:
319
value = pq->stats.c_primitives;
320
break;
321
case PIPE_STAT_QUERY_PS_INVOCATIONS:
322
value = 0;
323
for (i = 0; i < num_threads; i++) {
324
value += pq->end[i];
325
}
326
value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
327
break;
328
case PIPE_STAT_QUERY_HS_INVOCATIONS:
329
value = pq->stats.hs_invocations;
330
break;
331
case PIPE_STAT_QUERY_DS_INVOCATIONS:
332
value = pq->stats.ds_invocations;
333
break;
334
case PIPE_STAT_QUERY_CS_INVOCATIONS:
335
value = pq->stats.cs_invocations;
336
break;
337
}
338
break;
339
default:
340
fprintf(stderr, "Unknown query type %d\n", pq->type);
341
break;
342
}
343
}
344
345
void *dst = (uint8_t *)lpr->data + offset;
346
347
for (unsigned i = 0; i < num_values; i++) {
348
349
if (i == 1) {
350
value = value2;
351
dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 ||
352
result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4);
353
}
354
switch (result_type) {
355
case PIPE_QUERY_TYPE_I32: {
356
int32_t *iptr = (int32_t *)dst;
357
if (value > 0x7fffffff)
358
*iptr = 0x7fffffff;
359
else
360
*iptr = (int32_t)value;
361
break;
362
}
363
case PIPE_QUERY_TYPE_U32: {
364
uint32_t *uptr = (uint32_t *)dst;
365
if (value > 0xffffffff)
366
*uptr = 0xffffffff;
367
else
368
*uptr = (uint32_t)value;
369
break;
370
}
371
case PIPE_QUERY_TYPE_I64: {
372
int64_t *iptr = (int64_t *)dst;
373
*iptr = (int64_t)value;
374
break;
375
}
376
case PIPE_QUERY_TYPE_U64: {
377
uint64_t *uptr = (uint64_t *)dst;
378
*uptr = (uint64_t)value;
379
break;
380
}
381
}
382
}
383
}
384
385
static bool
386
llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
387
{
388
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
389
struct llvmpipe_query *pq = llvmpipe_query(q);
390
391
/* Check if the query is already in the scene. If so, we need to
392
* flush the scene now. Real apps shouldn't re-use a query in a
393
* frame of rendering.
394
*/
395
if (pq->fence && !lp_fence_issued(pq->fence)) {
396
llvmpipe_finish(pipe, __FUNCTION__);
397
}
398
399
400
memset(pq->start, 0, sizeof(pq->start));
401
memset(pq->end, 0, sizeof(pq->end));
402
lp_setup_begin_query(llvmpipe->setup, pq);
403
404
switch (pq->type) {
405
case PIPE_QUERY_PRIMITIVES_EMITTED:
406
pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
407
break;
408
case PIPE_QUERY_PRIMITIVES_GENERATED:
409
pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
410
llvmpipe->active_primgen_queries++;
411
break;
412
case PIPE_QUERY_SO_STATISTICS:
413
pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
414
pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
415
break;
416
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
417
for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
418
pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written;
419
pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed;
420
}
421
break;
422
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
423
pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
424
pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
425
break;
426
case PIPE_QUERY_PIPELINE_STATISTICS:
427
/* reset our cache */
428
if (llvmpipe->active_statistics_queries == 0) {
429
memset(&llvmpipe->pipeline_statistics, 0,
430
sizeof(llvmpipe->pipeline_statistics));
431
}
432
memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
433
llvmpipe->active_statistics_queries++;
434
break;
435
case PIPE_QUERY_OCCLUSION_COUNTER:
436
case PIPE_QUERY_OCCLUSION_PREDICATE:
437
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
438
llvmpipe->active_occlusion_queries++;
439
llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
440
break;
441
default:
442
break;
443
}
444
return true;
445
}
446
447
448
static bool
449
llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
450
{
451
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
452
struct llvmpipe_query *pq = llvmpipe_query(q);
453
454
lp_setup_end_query(llvmpipe->setup, pq);
455
456
switch (pq->type) {
457
458
case PIPE_QUERY_PRIMITIVES_EMITTED:
459
pq->num_primitives_written[0] =
460
llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
461
break;
462
case PIPE_QUERY_PRIMITIVES_GENERATED:
463
assert(llvmpipe->active_primgen_queries);
464
llvmpipe->active_primgen_queries--;
465
pq->num_primitives_generated[0] =
466
llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
467
break;
468
case PIPE_QUERY_SO_STATISTICS:
469
pq->num_primitives_written[0] =
470
llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
471
pq->num_primitives_generated[0] =
472
llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
473
break;
474
case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
475
for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
476
pq->num_primitives_written[s] =
477
llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s];
478
pq->num_primitives_generated[s] =
479
llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s];
480
}
481
break;
482
case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
483
pq->num_primitives_written[0] =
484
llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
485
pq->num_primitives_generated[0] =
486
llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
487
break;
488
case PIPE_QUERY_PIPELINE_STATISTICS:
489
pq->stats.ia_vertices =
490
llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
491
pq->stats.ia_primitives =
492
llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
493
pq->stats.vs_invocations =
494
llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
495
pq->stats.gs_invocations =
496
llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
497
pq->stats.gs_primitives =
498
llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
499
pq->stats.c_invocations =
500
llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
501
pq->stats.c_primitives =
502
llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
503
pq->stats.ps_invocations =
504
llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
505
pq->stats.cs_invocations =
506
llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations;
507
pq->stats.hs_invocations =
508
llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations;
509
pq->stats.ds_invocations =
510
llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations;
511
llvmpipe->active_statistics_queries--;
512
break;
513
case PIPE_QUERY_OCCLUSION_COUNTER:
514
case PIPE_QUERY_OCCLUSION_PREDICATE:
515
case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
516
assert(llvmpipe->active_occlusion_queries);
517
llvmpipe->active_occlusion_queries--;
518
llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
519
break;
520
default:
521
break;
522
}
523
524
return true;
525
}
526
527
boolean
528
llvmpipe_check_render_cond(struct llvmpipe_context *lp)
529
{
530
struct pipe_context *pipe = &lp->pipe;
531
boolean b, wait;
532
uint64_t result;
533
534
if (lp->render_cond_buffer) {
535
uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset);
536
return (!data) == lp->render_cond_cond;
537
}
538
if (!lp->render_cond_query)
539
return TRUE; /* no query predicate, draw normally */
540
541
wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
542
lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
543
544
b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
545
if (b)
546
return ((!result) == lp->render_cond_cond);
547
else
548
return TRUE;
549
}
550
551
static void
552
llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable)
553
{
554
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
555
556
llvmpipe->queries_disabled = !enable;
557
/* for OQs we need to regenerate the fragment shader */
558
llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
559
}
560
561
void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
562
{
563
llvmpipe->pipe.create_query = llvmpipe_create_query;
564
llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
565
llvmpipe->pipe.begin_query = llvmpipe_begin_query;
566
llvmpipe->pipe.end_query = llvmpipe_end_query;
567
llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
568
llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource;
569
llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
570
}
571
572
573
574