Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/llvmpipe/lp_scene.c
4570 views
1
/**************************************************************************
2
*
3
* Copyright 2009 VMware, Inc.
4
* All Rights Reserved.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
13
*
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
16
* of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
*
26
**************************************************************************/
27
28
#include "util/u_framebuffer.h"
29
#include "util/u_math.h"
30
#include "util/u_memory.h"
31
#include "util/u_inlines.h"
32
#include "util/simple_list.h"
33
#include "util/format/u_format.h"
34
#include "lp_scene.h"
35
#include "lp_fence.h"
36
#include "lp_debug.h"
37
#include "lp_context.h"
38
#include "lp_state_fs.h"
39
40
41
#define RESOURCE_REF_SZ 32
42
43
/** List of resource references */
44
struct resource_ref {
45
struct pipe_resource *resource[RESOURCE_REF_SZ];
46
int count;
47
struct resource_ref *next;
48
};
49
50
#define SHADER_REF_SZ 32
51
/** List of shader variant references */
52
struct shader_ref {
53
struct lp_fragment_shader_variant *variant[SHADER_REF_SZ];
54
int count;
55
struct shader_ref *next;
56
};
57
58
59
/**
60
* Create a new scene object.
61
* \param queue the queue to put newly rendered/emptied scenes into
62
*/
63
struct lp_scene *
64
lp_scene_create( struct pipe_context *pipe )
65
{
66
struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
67
if (!scene)
68
return NULL;
69
70
scene->pipe = pipe;
71
72
scene->data.head =
73
CALLOC_STRUCT(data_block);
74
75
(void) mtx_init(&scene->mutex, mtx_plain);
76
77
#ifdef DEBUG
78
/* Do some scene limit sanity checks here */
79
{
80
size_t maxBins = TILES_X * TILES_Y;
81
size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;
82
size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;
83
/* We'll need at least one command block per bin. Make sure that's
84
* less than the max allowed scene size.
85
*/
86
assert(maxCommandBytes < LP_SCENE_MAX_SIZE);
87
/* We'll also need space for at least one other data block */
88
assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);
89
}
90
#endif
91
92
return scene;
93
}
94
95
96
/**
97
* Free all data associated with the given scene, and the scene itself.
98
*/
99
void
100
lp_scene_destroy(struct lp_scene *scene)
101
{
102
lp_fence_reference(&scene->fence, NULL);
103
mtx_destroy(&scene->mutex);
104
assert(scene->data.head->next == NULL);
105
FREE(scene->data.head);
106
FREE(scene);
107
}
108
109
110
/**
111
* Check if the scene's bins are all empty.
112
* For debugging purposes.
113
*/
114
boolean
115
lp_scene_is_empty(struct lp_scene *scene )
116
{
117
unsigned x, y;
118
119
for (y = 0; y < scene->tiles_y; y++) {
120
for (x = 0; x < scene->tiles_x; x++) {
121
const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
122
if (bin->head) {
123
return FALSE;
124
}
125
}
126
}
127
return TRUE;
128
}
129
130
131
/* Returns true if there has ever been a failed allocation attempt in
132
* this scene. Used in triangle emit to avoid having to check success
133
* at each bin.
134
*/
135
boolean
136
lp_scene_is_oom(struct lp_scene *scene)
137
{
138
return scene->alloc_failed;
139
}
140
141
142
/* Remove all commands from a bin. Tries to reuse some of the memory
143
* allocated to the bin, however.
144
*/
145
void
146
lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
147
{
148
struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
149
150
bin->last_state = NULL;
151
bin->head = bin->tail;
152
if (bin->tail) {
153
bin->tail->next = NULL;
154
bin->tail->count = 0;
155
}
156
}
157
158
static void
159
init_scene_texture(struct lp_scene_surface *ssurf, struct pipe_surface *psurf)
160
{
161
if (!psurf) {
162
ssurf->stride = 0;
163
ssurf->layer_stride = 0;
164
ssurf->sample_stride = 0;
165
ssurf->nr_samples = 0;
166
ssurf->map = NULL;
167
return;
168
}
169
170
if (llvmpipe_resource_is_texture(psurf->texture)) {
171
ssurf->stride = llvmpipe_resource_stride(psurf->texture,
172
psurf->u.tex.level);
173
ssurf->layer_stride = llvmpipe_layer_stride(psurf->texture,
174
psurf->u.tex.level);
175
ssurf->sample_stride = llvmpipe_sample_stride(psurf->texture);
176
177
ssurf->map = llvmpipe_resource_map(psurf->texture,
178
psurf->u.tex.level,
179
psurf->u.tex.first_layer,
180
LP_TEX_USAGE_READ_WRITE);
181
ssurf->format_bytes = util_format_get_blocksize(psurf->format);
182
ssurf->nr_samples = util_res_sample_count(psurf->texture);
183
}
184
else {
185
struct llvmpipe_resource *lpr = llvmpipe_resource(psurf->texture);
186
unsigned pixstride = util_format_get_blocksize(psurf->format);
187
ssurf->stride = psurf->texture->width0;
188
ssurf->layer_stride = 0;
189
ssurf->sample_stride = 0;
190
ssurf->nr_samples = 1;
191
ssurf->map = lpr->data;
192
ssurf->map += psurf->u.buf.first_element * pixstride;
193
ssurf->format_bytes = util_format_get_blocksize(psurf->format);
194
}
195
}
196
197
void
198
lp_scene_begin_rasterization(struct lp_scene *scene)
199
{
200
const struct pipe_framebuffer_state *fb = &scene->fb;
201
int i;
202
203
//LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
204
205
for (i = 0; i < scene->fb.nr_cbufs; i++) {
206
struct pipe_surface *cbuf = scene->fb.cbufs[i];
207
init_scene_texture(&scene->cbufs[i], cbuf);
208
}
209
210
if (fb->zsbuf) {
211
struct pipe_surface *zsbuf = scene->fb.zsbuf;
212
init_scene_texture(&scene->zsbuf, zsbuf);
213
}
214
}
215
216
217
218
219
/**
220
* Free all the temporary data in a scene.
221
*/
222
void
223
lp_scene_end_rasterization(struct lp_scene *scene )
224
{
225
int i, j;
226
227
/* Unmap color buffers */
228
for (i = 0; i < scene->fb.nr_cbufs; i++) {
229
if (scene->cbufs[i].map) {
230
struct pipe_surface *cbuf = scene->fb.cbufs[i];
231
if (llvmpipe_resource_is_texture(cbuf->texture)) {
232
llvmpipe_resource_unmap(cbuf->texture,
233
cbuf->u.tex.level,
234
cbuf->u.tex.first_layer);
235
}
236
scene->cbufs[i].map = NULL;
237
}
238
}
239
240
/* Unmap z/stencil buffer */
241
if (scene->zsbuf.map) {
242
struct pipe_surface *zsbuf = scene->fb.zsbuf;
243
llvmpipe_resource_unmap(zsbuf->texture,
244
zsbuf->u.tex.level,
245
zsbuf->u.tex.first_layer);
246
scene->zsbuf.map = NULL;
247
}
248
249
/* Reset all command lists:
250
*/
251
for (i = 0; i < scene->tiles_x; i++) {
252
for (j = 0; j < scene->tiles_y; j++) {
253
struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
254
bin->head = NULL;
255
bin->tail = NULL;
256
bin->last_state = NULL;
257
}
258
}
259
260
/* If there are any bins which weren't cleared by the loop above,
261
* they will be caught (on debug builds at least) by this assert:
262
*/
263
assert(lp_scene_is_empty(scene));
264
265
/* Decrement texture ref counts
266
*/
267
{
268
struct resource_ref *ref;
269
int i, j = 0;
270
271
for (ref = scene->resources; ref; ref = ref->next) {
272
for (i = 0; i < ref->count; i++) {
273
if (LP_DEBUG & DEBUG_SETUP)
274
debug_printf("resource %d: %p %dx%d sz %d\n",
275
j,
276
(void *) ref->resource[i],
277
ref->resource[i]->width0,
278
ref->resource[i]->height0,
279
llvmpipe_resource_size(ref->resource[i]));
280
j++;
281
llvmpipe_resource_unmap(ref->resource[i], 0, 0);
282
pipe_resource_reference(&ref->resource[i], NULL);
283
}
284
}
285
286
if (LP_DEBUG & DEBUG_SETUP)
287
debug_printf("scene %d resources, sz %d\n",
288
j, scene->resource_reference_size);
289
}
290
291
/* Decrement shader variant ref counts
292
*/
293
{
294
struct shader_ref *ref;
295
int i, j = 0;
296
297
for (ref = scene->frag_shaders; ref; ref = ref->next) {
298
for (i = 0; i < ref->count; i++) {
299
if (LP_DEBUG & DEBUG_SETUP)
300
debug_printf("shader %d: %p\n", j, (void *) ref->variant[i]);
301
j++;
302
lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[i], NULL);
303
}
304
}
305
}
306
307
/* Free all scene data blocks:
308
*/
309
{
310
struct data_block_list *list = &scene->data;
311
struct data_block *block, *tmp;
312
313
for (block = list->head->next; block; block = tmp) {
314
tmp = block->next;
315
FREE(block);
316
}
317
318
list->head->next = NULL;
319
list->head->used = 0;
320
}
321
322
lp_fence_reference(&scene->fence, NULL);
323
324
scene->resources = NULL;
325
scene->frag_shaders = NULL;
326
scene->scene_size = 0;
327
scene->resource_reference_size = 0;
328
329
scene->alloc_failed = FALSE;
330
331
util_unreference_framebuffer_state( &scene->fb );
332
}
333
334
335
336
337
338
339
struct cmd_block *
340
lp_scene_new_cmd_block( struct lp_scene *scene,
341
struct cmd_bin *bin )
342
{
343
struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
344
if (block) {
345
if (bin->tail) {
346
bin->tail->next = block;
347
bin->tail = block;
348
}
349
else {
350
bin->head = block;
351
bin->tail = block;
352
}
353
//memset(block, 0, sizeof *block);
354
block->next = NULL;
355
block->count = 0;
356
}
357
return block;
358
}
359
360
361
struct data_block *
362
lp_scene_new_data_block( struct lp_scene *scene )
363
{
364
if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
365
if (0) debug_printf("%s: failed\n", __FUNCTION__);
366
scene->alloc_failed = TRUE;
367
return NULL;
368
}
369
else {
370
struct data_block *block = MALLOC_STRUCT(data_block);
371
if (!block)
372
return NULL;
373
374
scene->scene_size += sizeof *block;
375
376
block->used = 0;
377
block->next = scene->data.head;
378
scene->data.head = block;
379
380
return block;
381
}
382
}
383
384
385
/**
386
* Return number of bytes used for all bin data within a scene.
387
* This does not include resources (textures) referenced by the scene.
388
*/
389
static unsigned
390
lp_scene_data_size( const struct lp_scene *scene )
391
{
392
unsigned size = 0;
393
const struct data_block *block;
394
for (block = scene->data.head; block; block = block->next) {
395
size += block->used;
396
}
397
return size;
398
}
399
400
401
402
/**
403
* Add a reference to a resource by the scene.
404
*/
405
boolean
406
lp_scene_add_resource_reference(struct lp_scene *scene,
407
struct pipe_resource *resource,
408
boolean initializing_scene)
409
{
410
struct resource_ref *ref, **last = &scene->resources;
411
int i;
412
413
/* Look at existing resource blocks:
414
*/
415
for (ref = scene->resources; ref; ref = ref->next) {
416
last = &ref->next;
417
418
/* Search for this resource:
419
*/
420
for (i = 0; i < ref->count; i++)
421
if (ref->resource[i] == resource)
422
return TRUE;
423
424
if (ref->count < RESOURCE_REF_SZ) {
425
/* If the block is half-empty, then append the reference here.
426
*/
427
break;
428
}
429
}
430
431
/* Create a new block if no half-empty block was found.
432
*/
433
if (!ref) {
434
assert(*last == NULL);
435
*last = lp_scene_alloc(scene, sizeof *ref);
436
if (*last == NULL)
437
return FALSE;
438
439
ref = *last;
440
memset(ref, 0, sizeof *ref);
441
}
442
443
/* Map resource again to increment the map count. We likely use the
444
* already-mapped pointer in a texture of the jit context, and that pointer
445
* needs to stay mapped during rasterization. This map is unmap'ed when
446
* finalizing scene rasterization. */
447
llvmpipe_resource_map(resource, 0, 0, LP_TEX_USAGE_READ);
448
449
/* Append the reference to the reference block.
450
*/
451
pipe_resource_reference(&ref->resource[ref->count++], resource);
452
scene->resource_reference_size += llvmpipe_resource_size(resource);
453
454
/* Heuristic to advise scene flushes. This isn't helpful in the
455
* initial setup of the scene, but after that point flush on the
456
* next resource added which exceeds 64MB in referenced texture
457
* data.
458
*/
459
if (!initializing_scene &&
460
scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
461
return FALSE;
462
463
return TRUE;
464
}
465
466
467
/**
468
* Add a reference to a fragment shader variant
469
*/
470
boolean
471
lp_scene_add_frag_shader_reference(struct lp_scene *scene,
472
struct lp_fragment_shader_variant *variant)
473
{
474
struct shader_ref *ref, **last = &scene->frag_shaders;
475
int i;
476
477
/* Look at existing resource blocks:
478
*/
479
for (ref = scene->frag_shaders; ref; ref = ref->next) {
480
last = &ref->next;
481
482
/* Search for this resource:
483
*/
484
for (i = 0; i < ref->count; i++)
485
if (ref->variant[i] == variant)
486
return TRUE;
487
488
if (ref->count < SHADER_REF_SZ) {
489
/* If the block is half-empty, then append the reference here.
490
*/
491
break;
492
}
493
}
494
495
/* Create a new block if no half-empty block was found.
496
*/
497
if (!ref) {
498
assert(*last == NULL);
499
*last = lp_scene_alloc(scene, sizeof *ref);
500
if (*last == NULL)
501
return FALSE;
502
503
ref = *last;
504
memset(ref, 0, sizeof *ref);
505
}
506
507
/* Append the reference to the reference block.
508
*/
509
lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[ref->count++], variant);
510
511
return TRUE;
512
}
513
514
/**
515
* Does this scene have a reference to the given resource?
516
*/
517
boolean
518
lp_scene_is_resource_referenced(const struct lp_scene *scene,
519
const struct pipe_resource *resource)
520
{
521
const struct resource_ref *ref;
522
int i;
523
524
for (ref = scene->resources; ref; ref = ref->next) {
525
for (i = 0; i < ref->count; i++)
526
if (ref->resource[i] == resource)
527
return TRUE;
528
}
529
530
return FALSE;
531
}
532
533
534
535
536
/** advance curr_x,y to the next bin */
537
static boolean
538
next_bin(struct lp_scene *scene)
539
{
540
scene->curr_x++;
541
if (scene->curr_x >= scene->tiles_x) {
542
scene->curr_x = 0;
543
scene->curr_y++;
544
}
545
if (scene->curr_y >= scene->tiles_y) {
546
/* no more bins */
547
return FALSE;
548
}
549
return TRUE;
550
}
551
552
553
void
554
lp_scene_bin_iter_begin( struct lp_scene *scene )
555
{
556
scene->curr_x = scene->curr_y = -1;
557
}
558
559
560
/**
561
* Return pointer to next bin to be rendered.
562
* The lp_scene::curr_x and ::curr_y fields will be advanced.
563
* Multiple rendering threads will call this function to get a chunk
564
* of work (a bin) to work on.
565
*/
566
struct cmd_bin *
567
lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
568
{
569
struct cmd_bin *bin = NULL;
570
571
mtx_lock(&scene->mutex);
572
573
if (scene->curr_x < 0) {
574
/* first bin */
575
scene->curr_x = 0;
576
scene->curr_y = 0;
577
}
578
else if (!next_bin(scene)) {
579
/* no more bins left */
580
goto end;
581
}
582
583
bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
584
*x = scene->curr_x;
585
*y = scene->curr_y;
586
587
end:
588
/*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
589
mtx_unlock(&scene->mutex);
590
return bin;
591
}
592
593
594
void lp_scene_begin_binning(struct lp_scene *scene,
595
struct pipe_framebuffer_state *fb)
596
{
597
int i;
598
unsigned max_layer = ~0;
599
600
assert(lp_scene_is_empty(scene));
601
602
util_copy_framebuffer_state(&scene->fb, fb);
603
604
scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
605
scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
606
assert(scene->tiles_x <= TILES_X);
607
assert(scene->tiles_y <= TILES_Y);
608
609
/*
610
* Determine how many layers the fb has (used for clamping layer value).
611
* OpenGL (but not d3d10) permits different amount of layers per rt, however
612
* results are undefined if layer exceeds the amount of layers of ANY
613
* attachment hence don't need separate per cbuf and zsbuf max.
614
*/
615
for (i = 0; i < scene->fb.nr_cbufs; i++) {
616
struct pipe_surface *cbuf = scene->fb.cbufs[i];
617
if (cbuf) {
618
if (llvmpipe_resource_is_texture(cbuf->texture)) {
619
max_layer = MIN2(max_layer,
620
cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
621
}
622
else {
623
max_layer = 0;
624
}
625
}
626
}
627
if (fb->zsbuf) {
628
struct pipe_surface *zsbuf = scene->fb.zsbuf;
629
max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
630
}
631
scene->fb_max_layer = max_layer;
632
scene->fb_max_samples = util_framebuffer_get_num_samples(fb);
633
if (scene->fb_max_samples == 4) {
634
for (unsigned i = 0; i < 4; i++) {
635
scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE);
636
scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE);
637
}
638
}
639
}
640
641
642
void lp_scene_end_binning( struct lp_scene *scene )
643
{
644
if (LP_DEBUG & DEBUG_SCENE) {
645
debug_printf("rasterize scene:\n");
646
debug_printf(" scene_size: %u\n",
647
scene->scene_size);
648
debug_printf(" data size: %u\n",
649
lp_scene_data_size(scene));
650
651
if (0)
652
lp_debug_bins( scene );
653
}
654
}
655
656