Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_draw.c
4570 views
1
/*
2
* Copyright (C) 2012 Rob Clark <[email protected]>
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 FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
* SOFTWARE.
22
*
23
* Authors:
24
* Rob Clark <[email protected]>
25
*/
26
27
#include "pipe/p_state.h"
28
#include "util/format/u_format.h"
29
#include "util/u_draw.h"
30
#include "util/u_helpers.h"
31
#include "util/u_memory.h"
32
#include "util/u_prim.h"
33
#include "util/u_string.h"
34
35
#include "freedreno_blitter.h"
36
#include "freedreno_context.h"
37
#include "freedreno_draw.h"
38
#include "freedreno_fence.h"
39
#include "freedreno_query_acc.h"
40
#include "freedreno_query_hw.h"
41
#include "freedreno_resource.h"
42
#include "freedreno_state.h"
43
#include "freedreno_util.h"
44
45
static void
46
resource_read(struct fd_batch *batch, struct pipe_resource *prsc) assert_dt
47
{
48
if (!prsc)
49
return;
50
fd_batch_resource_read(batch, fd_resource(prsc));
51
}
52
53
static void
54
resource_written(struct fd_batch *batch, struct pipe_resource *prsc) assert_dt
55
{
56
if (!prsc)
57
return;
58
fd_batch_resource_write(batch, fd_resource(prsc));
59
}
60
61
static void
62
batch_draw_tracking_for_dirty_bits(struct fd_batch *batch) assert_dt
63
{
64
struct fd_context *ctx = batch->ctx;
65
struct pipe_framebuffer_state *pfb = &batch->framebuffer;
66
unsigned buffers = 0, restore_buffers = 0;
67
68
if (ctx->dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_ZSA)) {
69
if (fd_depth_enabled(ctx)) {
70
if (fd_resource(pfb->zsbuf->texture)->valid) {
71
restore_buffers |= FD_BUFFER_DEPTH;
72
} else {
73
batch->invalidated |= FD_BUFFER_DEPTH;
74
}
75
batch->gmem_reason |= FD_GMEM_DEPTH_ENABLED;
76
if (fd_depth_write_enabled(ctx)) {
77
buffers |= FD_BUFFER_DEPTH;
78
resource_written(batch, pfb->zsbuf->texture);
79
} else {
80
resource_read(batch, pfb->zsbuf->texture);
81
}
82
}
83
84
if (fd_stencil_enabled(ctx)) {
85
if (fd_resource(pfb->zsbuf->texture)->valid) {
86
restore_buffers |= FD_BUFFER_STENCIL;
87
} else {
88
batch->invalidated |= FD_BUFFER_STENCIL;
89
}
90
batch->gmem_reason |= FD_GMEM_STENCIL_ENABLED;
91
buffers |= FD_BUFFER_STENCIL;
92
resource_written(batch, pfb->zsbuf->texture);
93
}
94
}
95
96
if (ctx->dirty & FD_DIRTY_FRAMEBUFFER) {
97
for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
98
struct pipe_resource *surf;
99
100
if (!pfb->cbufs[i])
101
continue;
102
103
surf = pfb->cbufs[i]->texture;
104
105
if (fd_resource(surf)->valid) {
106
restore_buffers |= PIPE_CLEAR_COLOR0 << i;
107
} else {
108
batch->invalidated |= PIPE_CLEAR_COLOR0 << i;
109
}
110
111
buffers |= PIPE_CLEAR_COLOR0 << i;
112
113
if (ctx->dirty & FD_DIRTY_FRAMEBUFFER)
114
resource_written(batch, pfb->cbufs[i]->texture);
115
}
116
}
117
118
if (ctx->dirty & FD_DIRTY_BLEND) {
119
if (ctx->blend->logicop_enable)
120
batch->gmem_reason |= FD_GMEM_LOGICOP_ENABLED;
121
for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
122
if (ctx->blend->rt[i].blend_enable)
123
batch->gmem_reason |= FD_GMEM_BLEND_ENABLED;
124
}
125
}
126
127
/* Mark SSBOs */
128
if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_SSBO) {
129
const struct fd_shaderbuf_stateobj *so =
130
&ctx->shaderbuf[PIPE_SHADER_FRAGMENT];
131
132
u_foreach_bit (i, so->enabled_mask & so->writable_mask)
133
resource_written(batch, so->sb[i].buffer);
134
135
u_foreach_bit (i, so->enabled_mask & ~so->writable_mask)
136
resource_read(batch, so->sb[i].buffer);
137
}
138
139
if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_IMAGE) {
140
u_foreach_bit (i, ctx->shaderimg[PIPE_SHADER_FRAGMENT].enabled_mask) {
141
struct pipe_image_view *img =
142
&ctx->shaderimg[PIPE_SHADER_FRAGMENT].si[i];
143
if (img->access & PIPE_IMAGE_ACCESS_WRITE)
144
resource_written(batch, img->resource);
145
else
146
resource_read(batch, img->resource);
147
}
148
}
149
150
u_foreach_bit (s, ctx->bound_shader_stages) {
151
/* Mark constbuf as being read: */
152
if (ctx->dirty_shader[s] & FD_DIRTY_SHADER_CONST) {
153
u_foreach_bit (i, ctx->constbuf[s].enabled_mask)
154
resource_read(batch, ctx->constbuf[s].cb[i].buffer);
155
}
156
157
/* Mark textures as being read */
158
if (ctx->dirty_shader[s] & FD_DIRTY_SHADER_TEX) {
159
u_foreach_bit (i, ctx->tex[s].valid_textures)
160
resource_read(batch, ctx->tex[s].textures[i]->texture);
161
}
162
}
163
164
/* Mark VBOs as being read */
165
if (ctx->dirty & FD_DIRTY_VTXBUF) {
166
u_foreach_bit (i, ctx->vtx.vertexbuf.enabled_mask) {
167
assert(!ctx->vtx.vertexbuf.vb[i].is_user_buffer);
168
resource_read(batch, ctx->vtx.vertexbuf.vb[i].buffer.resource);
169
}
170
}
171
172
/* Mark streamout buffers as being written.. */
173
if (ctx->dirty & FD_DIRTY_STREAMOUT) {
174
for (unsigned i = 0; i < ctx->streamout.num_targets; i++)
175
if (ctx->streamout.targets[i])
176
resource_written(batch, ctx->streamout.targets[i]->buffer);
177
}
178
179
/* any buffers that haven't been cleared yet, we need to restore: */
180
batch->restore |= restore_buffers & (FD_BUFFER_ALL & ~batch->invalidated);
181
/* and any buffers used, need to be resolved: */
182
batch->resolve |= buffers;
183
}
184
185
static void
186
batch_draw_tracking(struct fd_batch *batch, const struct pipe_draw_info *info,
187
const struct pipe_draw_indirect_info *indirect) assert_dt
188
{
189
struct fd_context *ctx = batch->ctx;
190
191
/* NOTE: needs to be before resource_written(batch->query_buf), otherwise
192
* query_buf may not be created yet.
193
*/
194
fd_batch_update_queries(batch);
195
196
/*
197
* Figure out the buffers/features we need:
198
*/
199
200
fd_screen_lock(ctx->screen);
201
202
if (ctx->dirty & FD_DIRTY_RESOURCE)
203
batch_draw_tracking_for_dirty_bits(batch);
204
205
/* Mark index buffer as being read */
206
if (info->index_size)
207
resource_read(batch, info->index.resource);
208
209
/* Mark indirect draw buffer as being read */
210
if (indirect) {
211
if (indirect->buffer)
212
resource_read(batch, indirect->buffer);
213
if (indirect->count_from_stream_output)
214
resource_read(
215
batch, fd_stream_output_target(indirect->count_from_stream_output)
216
->offset_buf);
217
}
218
219
resource_written(batch, batch->query_buf);
220
221
list_for_each_entry (struct fd_acc_query, aq, &ctx->acc_active_queries, node)
222
resource_written(batch, aq->prsc);
223
224
fd_screen_unlock(ctx->screen);
225
}
226
227
static void
228
update_draw_stats(struct fd_context *ctx, const struct pipe_draw_info *info,
229
const struct pipe_draw_start_count_bias *draws,
230
unsigned num_draws) assert_dt
231
{
232
ctx->stats.draw_calls++;
233
234
if (ctx->screen->gpu_id < 600) {
235
/* Counting prims in sw doesn't work for GS and tesselation. For older
236
* gens we don't have those stages and don't have the hw counters enabled,
237
* so keep the count accurate for non-patch geometry.
238
*/
239
unsigned prims = 0;
240
if ((info->mode != PIPE_PRIM_PATCHES) && (info->mode != PIPE_PRIM_MAX)) {
241
for (unsigned i = 0; i < num_draws; i++) {
242
prims += u_reduced_prims_for_vertices(info->mode, draws[i].count);
243
}
244
}
245
246
ctx->stats.prims_generated += prims;
247
248
if (ctx->streamout.num_targets > 0) {
249
/* Clip the prims we're writing to the size of the SO buffers. */
250
enum pipe_prim_type tf_prim = u_decomposed_prim(info->mode);
251
unsigned verts_written = u_vertices_for_prims(tf_prim, prims);
252
unsigned remaining_vert_space =
253
ctx->streamout.max_tf_vtx - ctx->streamout.verts_written;
254
if (verts_written > remaining_vert_space) {
255
verts_written = remaining_vert_space;
256
u_trim_pipe_prim(tf_prim, &remaining_vert_space);
257
}
258
ctx->streamout.verts_written += verts_written;
259
260
ctx->stats.prims_emitted +=
261
u_reduced_prims_for_vertices(tf_prim, verts_written);
262
}
263
}
264
}
265
266
static void
267
fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
268
unsigned drawid_offset,
269
const struct pipe_draw_indirect_info *indirect,
270
const struct pipe_draw_start_count_bias *draws, unsigned num_draws) in_dt
271
{
272
struct fd_context *ctx = fd_context(pctx);
273
274
/* for debugging problems with indirect draw, it is convenient
275
* to be able to emulate it, to determine if game is feeding us
276
* bogus data:
277
*/
278
if (indirect && indirect->buffer && FD_DBG(NOINDR)) {
279
/* num_draws is only applicable for direct draws: */
280
assert(num_draws == 1);
281
util_draw_indirect(pctx, info, indirect);
282
return;
283
}
284
285
/* TODO: push down the region versions into the tiles */
286
if (!fd_render_condition_check(pctx))
287
return;
288
289
/* emulate unsupported primitives: */
290
if (!fd_supported_prim(ctx, info->mode)) {
291
if (ctx->streamout.num_targets > 0)
292
mesa_loge("stream-out with emulated prims");
293
util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
294
util_primconvert_draw_vbo(ctx->primconvert, info, drawid_offset, indirect, draws,
295
num_draws);
296
return;
297
}
298
299
/* Upload a user index buffer. */
300
struct pipe_resource *indexbuf = NULL;
301
unsigned index_offset = 0;
302
struct pipe_draw_info new_info;
303
if (info->index_size) {
304
if (info->has_user_indices) {
305
if (num_draws > 1) {
306
util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);
307
return;
308
}
309
if (!util_upload_index_buffer(pctx, info, &draws[0], &indexbuf,
310
&index_offset, 4))
311
return;
312
new_info = *info;
313
new_info.index.resource = indexbuf;
314
new_info.has_user_indices = false;
315
info = &new_info;
316
} else {
317
indexbuf = info->index.resource;
318
}
319
}
320
321
if ((ctx->streamout.num_targets > 0) && (num_draws > 1)) {
322
util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);
323
return;
324
}
325
326
struct fd_batch *batch = fd_context_batch(ctx);
327
328
batch_draw_tracking(batch, info, indirect);
329
330
while (unlikely(!fd_batch_lock_submit(batch))) {
331
/* The current batch was flushed in batch_draw_tracking()
332
* so start anew. We know this won't happen a second time
333
* since we are dealing with a fresh batch:
334
*/
335
fd_batch_reference(&batch, NULL);
336
batch = fd_context_batch(ctx);
337
batch_draw_tracking(batch, info, indirect);
338
assert(ctx->batch == batch);
339
}
340
341
batch->num_draws++;
342
343
/* Marking the batch as needing flush must come after the batch
344
* dependency tracking (resource_read()/resource_write()), as that
345
* can trigger a flush
346
*/
347
fd_batch_needs_flush(batch);
348
349
struct pipe_framebuffer_state *pfb = &batch->framebuffer;
350
DBG("%p: %ux%u num_draws=%u (%s/%s)", batch, pfb->width, pfb->height,
351
batch->num_draws,
352
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
353
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
354
355
batch->cost += ctx->draw_cost;
356
357
for (unsigned i = 0; i < num_draws; i++) {
358
ctx->draw_vbo(ctx, info, drawid_offset, indirect, &draws[i], index_offset);
359
360
batch->num_vertices += draws[i].count * info->instance_count;
361
}
362
363
if (unlikely(ctx->stats_users > 0))
364
update_draw_stats(ctx, info, draws, num_draws);
365
366
for (unsigned i = 0; i < ctx->streamout.num_targets; i++) {
367
assert(num_draws == 1);
368
ctx->streamout.offsets[i] += draws[0].count;
369
}
370
371
if (FD_DBG(DDRAW))
372
fd_context_all_dirty(ctx);
373
374
debug_assert(!batch->flushed);
375
376
fd_batch_unlock_submit(batch);
377
fd_batch_check_size(batch);
378
fd_batch_reference(&batch, NULL);
379
380
if (info == &new_info)
381
pipe_resource_reference(&indexbuf, NULL);
382
}
383
384
static void
385
batch_clear_tracking(struct fd_batch *batch, unsigned buffers) assert_dt
386
{
387
struct fd_context *ctx = batch->ctx;
388
struct pipe_framebuffer_state *pfb = &batch->framebuffer;
389
unsigned cleared_buffers;
390
391
/* pctx->clear() is only for full-surface clears, so scissor is
392
* equivalent to having GL_SCISSOR_TEST disabled:
393
*/
394
batch->max_scissor.minx = 0;
395
batch->max_scissor.miny = 0;
396
batch->max_scissor.maxx = pfb->width;
397
batch->max_scissor.maxy = pfb->height;
398
399
/* for bookkeeping about which buffers have been cleared (and thus
400
* can fully or partially skip mem2gmem) we need to ignore buffers
401
* that have already had a draw, in case apps do silly things like
402
* clear after draw (ie. if you only clear the color buffer, but
403
* something like alpha-test causes side effects from the draw in
404
* the depth buffer, etc)
405
*/
406
cleared_buffers = buffers & (FD_BUFFER_ALL & ~batch->restore);
407
batch->cleared |= buffers;
408
batch->invalidated |= cleared_buffers;
409
410
batch->resolve |= buffers;
411
412
fd_screen_lock(ctx->screen);
413
414
if (buffers & PIPE_CLEAR_COLOR)
415
for (unsigned i = 0; i < pfb->nr_cbufs; i++)
416
if (buffers & (PIPE_CLEAR_COLOR0 << i))
417
resource_written(batch, pfb->cbufs[i]->texture);
418
419
if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
420
resource_written(batch, pfb->zsbuf->texture);
421
batch->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL;
422
}
423
424
resource_written(batch, batch->query_buf);
425
426
list_for_each_entry (struct fd_acc_query, aq, &ctx->acc_active_queries, node)
427
resource_written(batch, aq->prsc);
428
429
fd_screen_unlock(ctx->screen);
430
}
431
432
static void
433
fd_clear(struct pipe_context *pctx, unsigned buffers,
434
const struct pipe_scissor_state *scissor_state,
435
const union pipe_color_union *color, double depth,
436
unsigned stencil) in_dt
437
{
438
struct fd_context *ctx = fd_context(pctx);
439
440
/* TODO: push down the region versions into the tiles */
441
if (!fd_render_condition_check(pctx))
442
return;
443
444
struct fd_batch *batch = fd_context_batch(ctx);
445
446
batch_clear_tracking(batch, buffers);
447
448
while (unlikely(!fd_batch_lock_submit(batch))) {
449
/* The current batch was flushed in batch_clear_tracking()
450
* so start anew. We know this won't happen a second time
451
* since we are dealing with a fresh batch:
452
*/
453
fd_batch_reference(&batch, NULL);
454
batch = fd_context_batch(ctx);
455
batch_clear_tracking(batch, buffers);
456
assert(ctx->batch == batch);
457
}
458
459
/* Marking the batch as needing flush must come after the batch
460
* dependency tracking (resource_read()/resource_write()), as that
461
* can trigger a flush
462
*/
463
fd_batch_needs_flush(batch);
464
465
struct pipe_framebuffer_state *pfb = &batch->framebuffer;
466
DBG("%p: %x %ux%u depth=%f, stencil=%u (%s/%s)", batch, buffers, pfb->width,
467
pfb->height, depth, stencil,
468
util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
469
util_format_short_name(pipe_surface_format(pfb->zsbuf)));
470
471
/* if per-gen backend doesn't implement ctx->clear() generic
472
* blitter clear:
473
*/
474
bool fallback = true;
475
476
if (ctx->clear) {
477
fd_batch_update_queries(batch);
478
479
if (ctx->clear(ctx, buffers, color, depth, stencil)) {
480
if (FD_DBG(DCLEAR))
481
fd_context_all_dirty(ctx);
482
483
fallback = false;
484
}
485
}
486
487
debug_assert(!batch->flushed);
488
489
fd_batch_unlock_submit(batch);
490
fd_batch_check_size(batch);
491
492
if (fallback) {
493
fd_blitter_clear(pctx, buffers, color, depth, stencil);
494
}
495
496
fd_batch_reference(&batch, NULL);
497
}
498
499
static void
500
fd_clear_render_target(struct pipe_context *pctx, struct pipe_surface *ps,
501
const union pipe_color_union *color, unsigned x,
502
unsigned y, unsigned w, unsigned h,
503
bool render_condition_enabled)
504
{
505
DBG("TODO: x=%u, y=%u, w=%u, h=%u", x, y, w, h);
506
}
507
508
static void
509
fd_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *ps,
510
unsigned buffers, double depth, unsigned stencil,
511
unsigned x, unsigned y, unsigned w, unsigned h,
512
bool render_condition_enabled)
513
{
514
DBG("TODO: buffers=%u, depth=%f, stencil=%u, x=%u, y=%u, w=%u, h=%u",
515
buffers, depth, stencil, x, y, w, h);
516
}
517
518
static void
519
fd_launch_grid(struct pipe_context *pctx,
520
const struct pipe_grid_info *info) in_dt
521
{
522
struct fd_context *ctx = fd_context(pctx);
523
const struct fd_shaderbuf_stateobj *so =
524
&ctx->shaderbuf[PIPE_SHADER_COMPUTE];
525
struct fd_batch *batch, *save_batch = NULL;
526
527
batch = fd_bc_alloc_batch(ctx, true);
528
fd_batch_reference(&save_batch, ctx->batch);
529
fd_batch_reference(&ctx->batch, batch);
530
fd_context_all_dirty(ctx);
531
532
fd_screen_lock(ctx->screen);
533
534
/* Mark SSBOs */
535
u_foreach_bit (i, so->enabled_mask & so->writable_mask)
536
resource_written(batch, so->sb[i].buffer);
537
538
u_foreach_bit (i, so->enabled_mask & ~so->writable_mask)
539
resource_read(batch, so->sb[i].buffer);
540
541
u_foreach_bit (i, ctx->shaderimg[PIPE_SHADER_COMPUTE].enabled_mask) {
542
struct pipe_image_view *img = &ctx->shaderimg[PIPE_SHADER_COMPUTE].si[i];
543
if (img->access & PIPE_IMAGE_ACCESS_WRITE)
544
resource_written(batch, img->resource);
545
else
546
resource_read(batch, img->resource);
547
}
548
549
/* UBO's are read */
550
u_foreach_bit (i, ctx->constbuf[PIPE_SHADER_COMPUTE].enabled_mask)
551
resource_read(batch, ctx->constbuf[PIPE_SHADER_COMPUTE].cb[i].buffer);
552
553
/* Mark textures as being read */
554
u_foreach_bit (i, ctx->tex[PIPE_SHADER_COMPUTE].valid_textures)
555
resource_read(batch, ctx->tex[PIPE_SHADER_COMPUTE].textures[i]->texture);
556
557
/* For global buffers, we don't really know if read or written, so assume
558
* the worst:
559
*/
560
u_foreach_bit (i, ctx->global_bindings.enabled_mask)
561
resource_written(batch, ctx->global_bindings.buf[i]);
562
563
if (info->indirect)
564
resource_read(batch, info->indirect);
565
566
fd_screen_unlock(ctx->screen);
567
568
DBG("%p: work_dim=%u, block=%ux%ux%u, grid=%ux%ux%u",
569
batch, info->work_dim,
570
info->block[0], info->block[1], info->block[2],
571
info->grid[0], info->grid[1], info->grid[2]);
572
573
fd_batch_needs_flush(batch);
574
ctx->launch_grid(ctx, info);
575
576
fd_batch_flush(batch);
577
578
fd_batch_reference(&ctx->batch, save_batch);
579
fd_context_all_dirty(ctx);
580
fd_batch_reference(&save_batch, NULL);
581
fd_batch_reference(&batch, NULL);
582
}
583
584
void
585
fd_draw_init(struct pipe_context *pctx)
586
{
587
pctx->draw_vbo = fd_draw_vbo;
588
pctx->clear = fd_clear;
589
pctx->clear_render_target = fd_clear_render_target;
590
pctx->clear_depth_stencil = fd_clear_depth_stencil;
591
592
if (has_compute(fd_screen(pctx->screen))) {
593
pctx->launch_grid = fd_launch_grid;
594
}
595
}
596
597