Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/panfrost/lib/pan_cs.c
4560 views
1
/*
2
* Copyright (C) 2021 Collabora, Ltd.
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
* Alyssa Rosenzweig <[email protected]>
25
* Boris Brezillon <[email protected]>
26
*/
27
28
#include "util/macros.h"
29
30
#include "panfrost-quirks.h"
31
32
#include "pan_cs.h"
33
#include "pan_encoder.h"
34
#include "pan_texture.h"
35
36
static void
37
pan_prepare_crc(const struct panfrost_device *dev,
38
const struct pan_fb_info *fb, int rt_crc,
39
struct MALI_ZS_CRC_EXTENSION *ext)
40
{
41
if (rt_crc < 0)
42
return;
43
44
assert(rt_crc < fb->rt_count);
45
46
const struct pan_image_view *rt = fb->rts[rt_crc].view;
47
const struct pan_image_slice_layout *slice = &rt->image->layout.slices[rt->first_level];
48
ext->crc_base = (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND ?
49
(rt->image->data.bo->ptr.gpu + rt->image->data.offset) :
50
(rt->image->crc.bo->ptr.gpu + rt->image->crc.offset)) +
51
slice->crc.offset;
52
ext->crc_row_stride = slice->crc.stride;
53
54
if (dev->arch == 7)
55
ext->crc_render_target = rt_crc;
56
57
if (fb->rts[rt_crc].clear) {
58
uint32_t clear_val = fb->rts[rt_crc].clear_value[0];
59
ext->crc_clear_color = clear_val | 0xc000000000000000 |
60
(((uint64_t)clear_val & 0xffff) << 32);
61
}
62
}
63
64
static enum mali_block_format_v7
65
mod_to_block_fmt_v7(uint64_t mod)
66
{
67
switch (mod) {
68
case DRM_FORMAT_MOD_LINEAR:
69
return MALI_BLOCK_FORMAT_V7_LINEAR;
70
case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
71
return MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED;
72
default:
73
if (drm_is_afbc(mod))
74
return MALI_BLOCK_FORMAT_V7_AFBC;
75
76
unreachable("Unsupported modifer");
77
}
78
}
79
80
static enum mali_block_format
81
mod_to_block_fmt(uint64_t mod)
82
{
83
switch (mod) {
84
case DRM_FORMAT_MOD_LINEAR:
85
return MALI_BLOCK_FORMAT_LINEAR;
86
case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
87
return MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
88
default:
89
if (drm_is_afbc(mod))
90
return MALI_BLOCK_FORMAT_AFBC;
91
92
unreachable("Unsupported modifer");
93
}
94
}
95
96
static enum mali_zs_format
97
translate_zs_format(enum pipe_format in)
98
{
99
switch (in) {
100
case PIPE_FORMAT_Z16_UNORM: return MALI_ZS_FORMAT_D16;
101
case PIPE_FORMAT_Z24_UNORM_S8_UINT: return MALI_ZS_FORMAT_D24S8;
102
case PIPE_FORMAT_Z24X8_UNORM: return MALI_ZS_FORMAT_D24X8;
103
case PIPE_FORMAT_Z32_FLOAT: return MALI_ZS_FORMAT_D32;
104
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: return MALI_ZS_FORMAT_D32_S8X24;
105
default: unreachable("Unsupported depth/stencil format.");
106
}
107
}
108
109
static enum mali_s_format
110
translate_s_format(enum pipe_format in)
111
{
112
switch (in) {
113
case PIPE_FORMAT_S8_UINT: return MALI_S_FORMAT_S8;
114
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
115
case PIPE_FORMAT_S8X24_UINT:
116
return MALI_S_FORMAT_S8X24;
117
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
118
case PIPE_FORMAT_X24S8_UINT:
119
return MALI_S_FORMAT_X24S8;
120
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
121
return MALI_S_FORMAT_X32_S8X24;
122
default:
123
unreachable("Unsupported stencil format.");
124
}
125
}
126
127
static enum mali_msaa
128
mali_sampling_mode(const struct pan_image_view *view)
129
{
130
if (view->image->layout.nr_samples > 1) {
131
assert(view->nr_samples == view->image->layout.nr_samples);
132
assert(view->image->layout.slices[0].surface_stride != 0);
133
return MALI_MSAA_LAYERED;
134
}
135
136
if (view->nr_samples > view->image->layout.nr_samples) {
137
assert(view->image->layout.nr_samples == 1);
138
return MALI_MSAA_AVERAGE;
139
}
140
141
assert(view->nr_samples == view->image->layout.nr_samples);
142
assert(view->nr_samples == 1);
143
144
return MALI_MSAA_SINGLE;
145
}
146
147
static void
148
pan_prepare_s(const struct panfrost_device *dev,
149
const struct pan_fb_info *fb,
150
struct MALI_ZS_CRC_EXTENSION *ext)
151
{
152
const struct pan_image_view *s = fb->zs.view.s;
153
154
if (!s)
155
return;
156
157
unsigned level = s->first_level;
158
159
if (dev->arch < 7)
160
ext->s_msaa = mali_sampling_mode(s);
161
else
162
ext->s_msaa_v7 = mali_sampling_mode(s);
163
164
struct pan_surface surf;
165
pan_iview_get_surface(s, 0, 0, 0, &surf);
166
167
assert(s->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
168
s->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
169
ext->s_writeback_base = surf.data;
170
ext->s_writeback_row_stride = s->image->layout.slices[level].row_stride;
171
ext->s_writeback_surface_stride =
172
(s->image->layout.nr_samples > 1) ?
173
s->image->layout.slices[level].surface_stride : 0;
174
175
if (dev->arch >= 7)
176
ext->s_block_format_v7 = mod_to_block_fmt_v7(s->image->layout.modifier);
177
else
178
ext->s_block_format = mod_to_block_fmt(s->image->layout.modifier);
179
180
ext->s_write_format = translate_s_format(s->format);
181
}
182
183
static void
184
pan_prepare_zs(const struct panfrost_device *dev,
185
const struct pan_fb_info *fb,
186
struct MALI_ZS_CRC_EXTENSION *ext)
187
{
188
const struct pan_image_view *zs = fb->zs.view.zs;
189
190
if (!zs)
191
return;
192
193
unsigned level = zs->first_level;
194
195
if (dev->arch < 7)
196
ext->zs_msaa = mali_sampling_mode(zs);
197
else
198
ext->zs_msaa_v7 = mali_sampling_mode(zs);
199
200
struct pan_surface surf;
201
pan_iview_get_surface(zs, 0, 0, 0, &surf);
202
203
if (drm_is_afbc(zs->image->layout.modifier)) {
204
const struct pan_image_slice_layout *slice = &zs->image->layout.slices[level];
205
206
ext->zs_afbc_header = surf.afbc.header;
207
ext->zs_afbc_body = surf.afbc.body;
208
209
if (pan_is_bifrost(dev)) {
210
ext->zs_afbc_row_stride = slice->afbc.row_stride /
211
AFBC_HEADER_BYTES_PER_TILE;
212
} else {
213
ext->zs_block_format = MALI_BLOCK_FORMAT_AFBC;
214
ext->zs_afbc_body_size = 0x1000;
215
ext->zs_afbc_chunk_size = 9;
216
ext->zs_afbc_sparse = true;
217
}
218
} else {
219
assert(zs->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
220
zs->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
221
222
/* TODO: Z32F(S8) support, which is always linear */
223
224
ext->zs_writeback_base = surf.data;
225
ext->zs_writeback_row_stride =
226
zs->image->layout.slices[level].row_stride;
227
ext->zs_writeback_surface_stride =
228
(zs->image->layout.nr_samples > 1) ?
229
zs->image->layout.slices[level].surface_stride : 0;
230
}
231
232
if (dev->arch >= 7)
233
ext->zs_block_format_v7 = mod_to_block_fmt_v7(zs->image->layout.modifier);
234
else
235
ext->zs_block_format = mod_to_block_fmt(zs->image->layout.modifier);
236
237
ext->zs_write_format = translate_zs_format(zs->format);
238
if (ext->zs_write_format == MALI_ZS_FORMAT_D24S8)
239
ext->s_writeback_base = ext->zs_writeback_base;
240
}
241
242
static void
243
pan_emit_zs_crc_ext(const struct panfrost_device *dev,
244
const struct pan_fb_info *fb, int rt_crc,
245
void *zs_crc_ext)
246
{
247
pan_pack(zs_crc_ext, ZS_CRC_EXTENSION, cfg) {
248
pan_prepare_crc(dev, fb, rt_crc, &cfg);
249
cfg.zs_clean_pixel_write_enable = fb->zs.clear.z || fb->zs.clear.s;
250
pan_prepare_zs(dev, fb, &cfg);
251
pan_prepare_s(dev, fb, &cfg);
252
}
253
}
254
255
/* Measure format as it appears in the tile buffer */
256
257
static unsigned
258
pan_bytes_per_pixel_tib(enum pipe_format format)
259
{
260
if (panfrost_blendable_formats_v7[format].internal) {
261
/* Blendable formats are always 32-bits in the tile buffer,
262
* extra bits are used as padding or to dither */
263
return 4;
264
} else {
265
/* Non-blendable formats are raw, rounded up to the nearest
266
* power-of-two size */
267
unsigned bytes = util_format_get_blocksize(format);
268
return util_next_power_of_two(bytes);
269
}
270
}
271
272
static unsigned
273
pan_internal_cbuf_size(const struct pan_fb_info *fb,
274
unsigned *tile_size)
275
{
276
unsigned total_size = 0;
277
278
*tile_size = 16 * 16;
279
for (int cb = 0; cb < fb->rt_count; ++cb) {
280
const struct pan_image_view *rt = fb->rts[cb].view;
281
282
if (!rt)
283
continue;
284
285
total_size += pan_bytes_per_pixel_tib(rt->format) *
286
rt->nr_samples * (*tile_size);
287
}
288
289
/* We have a 4KB budget, let's reduce the tile size until it fits. */
290
while (total_size > 4096) {
291
total_size >>= 1;
292
*tile_size >>= 1;
293
}
294
295
/* Align on 1k. */
296
total_size = ALIGN_POT(total_size, 1024);
297
298
/* Minimum tile size is 4x4. */
299
assert(*tile_size >= 4 * 4);
300
return total_size;
301
}
302
303
static inline enum mali_sample_pattern
304
pan_sample_pattern(unsigned samples)
305
{
306
switch (samples) {
307
case 1: return MALI_SAMPLE_PATTERN_SINGLE_SAMPLED;
308
case 4: return MALI_SAMPLE_PATTERN_ROTATED_4X_GRID;
309
case 8: return MALI_SAMPLE_PATTERN_D3D_8X_GRID;
310
case 16: return MALI_SAMPLE_PATTERN_D3D_16X_GRID;
311
default: unreachable("Unsupported sample count");
312
}
313
}
314
315
int
316
pan_select_crc_rt(const struct panfrost_device *dev, const struct pan_fb_info *fb)
317
{
318
if (dev->arch < 7) {
319
if (fb->rt_count == 1 && fb->rts[0].view && !fb->rts[0].discard &&
320
fb->rts[0].view->image->layout.crc_mode != PAN_IMAGE_CRC_NONE)
321
return 0;
322
323
return -1;
324
}
325
326
bool best_rt_valid = false;
327
int best_rt = -1;
328
329
for (unsigned i = 0; i < fb->rt_count; i++) {
330
if (!fb->rts[i].view || fb->rts[0].discard ||
331
fb->rts[i].view->image->layout.crc_mode == PAN_IMAGE_CRC_NONE)
332
continue;
333
334
bool valid = *(fb->rts[i].crc_valid);
335
bool full = !fb->extent.minx && !fb->extent.miny &&
336
fb->extent.maxx == (fb->width - 1) &&
337
fb->extent.maxy == (fb->height - 1);
338
if (!full && !valid)
339
continue;
340
341
if (best_rt < 0 || (valid && !best_rt_valid)) {
342
best_rt = i;
343
best_rt_valid = valid;
344
}
345
346
if (valid)
347
break;
348
}
349
350
return best_rt;
351
}
352
353
bool
354
pan_fbd_has_zs_crc_ext(const struct panfrost_device *dev,
355
const struct pan_fb_info *fb)
356
{
357
if (dev->quirks & MIDGARD_SFBD)
358
return false;
359
360
return fb->zs.view.zs || fb->zs.view.s || pan_select_crc_rt(dev, fb) >= 0;
361
}
362
363
static enum mali_mfbd_color_format
364
pan_mfbd_raw_format(unsigned bits)
365
{
366
switch (bits) {
367
case 8: return MALI_MFBD_COLOR_FORMAT_RAW8;
368
case 16: return MALI_MFBD_COLOR_FORMAT_RAW16;
369
case 24: return MALI_MFBD_COLOR_FORMAT_RAW24;
370
case 32: return MALI_MFBD_COLOR_FORMAT_RAW32;
371
case 48: return MALI_MFBD_COLOR_FORMAT_RAW48;
372
case 64: return MALI_MFBD_COLOR_FORMAT_RAW64;
373
case 96: return MALI_MFBD_COLOR_FORMAT_RAW96;
374
case 128: return MALI_MFBD_COLOR_FORMAT_RAW128;
375
case 192: return MALI_MFBD_COLOR_FORMAT_RAW192;
376
case 256: return MALI_MFBD_COLOR_FORMAT_RAW256;
377
case 384: return MALI_MFBD_COLOR_FORMAT_RAW384;
378
case 512: return MALI_MFBD_COLOR_FORMAT_RAW512;
379
case 768: return MALI_MFBD_COLOR_FORMAT_RAW768;
380
case 1024: return MALI_MFBD_COLOR_FORMAT_RAW1024;
381
case 1536: return MALI_MFBD_COLOR_FORMAT_RAW1536;
382
case 2048: return MALI_MFBD_COLOR_FORMAT_RAW2048;
383
default: unreachable("invalid raw bpp");
384
}
385
}
386
387
static void
388
pan_rt_init_format(const struct panfrost_device *dev,
389
const struct pan_image_view *rt,
390
struct MALI_RENDER_TARGET *cfg)
391
{
392
/* Explode details on the format */
393
394
const struct util_format_description *desc =
395
util_format_description(rt->format);
396
397
/* The swizzle for rendering is inverted from texturing */
398
399
unsigned char swizzle[4];
400
panfrost_invert_swizzle(desc->swizzle, swizzle);
401
402
cfg->swizzle = panfrost_translate_swizzle_4(swizzle);
403
404
/* Fill in accordingly, defaulting to 8-bit UNORM */
405
406
if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
407
cfg->srgb = true;
408
409
struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format];
410
411
if (fmt.internal) {
412
cfg->internal_format = fmt.internal;
413
cfg->writeback_format = fmt.writeback;
414
} else {
415
/* Construct RAW internal/writeback, where internal is
416
* specified logarithmically (round to next power-of-two).
417
* Offset specified from RAW8, where 8 = 2^3 */
418
419
unsigned bits = desc->block.bits;
420
unsigned offset = util_logbase2_ceil(bits) - 3;
421
assert(offset <= 4);
422
423
cfg->internal_format =
424
MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW8 + offset;
425
426
cfg->writeback_format = pan_mfbd_raw_format(bits);
427
}
428
}
429
430
static void
431
pan_prepare_rt(const struct panfrost_device *dev,
432
const struct pan_fb_info *fb, unsigned idx,
433
unsigned cbuf_offset,
434
struct MALI_RENDER_TARGET *cfg)
435
{
436
cfg->clean_pixel_write_enable = fb->rts[idx].clear;
437
cfg->internal_buffer_offset = cbuf_offset;
438
if (fb->rts[idx].clear) {
439
cfg->clear.color_0 = fb->rts[idx].clear_value[0];
440
cfg->clear.color_1 = fb->rts[idx].clear_value[1];
441
cfg->clear.color_2 = fb->rts[idx].clear_value[2];
442
cfg->clear.color_3 = fb->rts[idx].clear_value[3];
443
}
444
445
const struct pan_image_view *rt = fb->rts[idx].view;
446
if (!rt || fb->rts[idx].discard) {
447
cfg->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8;
448
cfg->internal_buffer_offset = cbuf_offset;
449
if (dev->arch >= 7) {
450
cfg->bifrost_v7.writeback_block_format = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED;
451
cfg->dithering_enable = true;
452
}
453
454
return;
455
}
456
457
cfg->write_enable = true;
458
cfg->dithering_enable = true;
459
460
unsigned level = rt->first_level;
461
assert(rt->last_level == rt->first_level);
462
assert(rt->last_layer == rt->first_layer);
463
464
int row_stride = rt->image->layout.slices[level].row_stride;
465
466
/* Only set layer_stride for layered MSAA rendering */
467
468
unsigned layer_stride =
469
(rt->image->layout.nr_samples > 1) ?
470
rt->image->layout.slices[level].surface_stride : 0;
471
472
cfg->writeback_msaa = mali_sampling_mode(rt);
473
474
pan_rt_init_format(dev, rt, cfg);
475
476
if (dev->arch >= 7)
477
cfg->bifrost_v7.writeback_block_format = mod_to_block_fmt_v7(rt->image->layout.modifier);
478
else
479
cfg->midgard.writeback_block_format = mod_to_block_fmt(rt->image->layout.modifier);
480
481
struct pan_surface surf;
482
pan_iview_get_surface(rt, 0, 0, 0, &surf);
483
484
if (drm_is_afbc(rt->image->layout.modifier)) {
485
const struct pan_image_slice_layout *slice = &rt->image->layout.slices[level];
486
487
if (pan_is_bifrost(dev)) {
488
cfg->afbc.row_stride = slice->afbc.row_stride /
489
AFBC_HEADER_BYTES_PER_TILE;
490
cfg->bifrost_afbc.afbc_wide_block_enable =
491
panfrost_block_dim(rt->image->layout.modifier, true, 0) > 16;
492
} else {
493
cfg->afbc.chunk_size = 9;
494
cfg->midgard_afbc.sparse = true;
495
cfg->afbc.body_size = slice->afbc.body_size;
496
}
497
498
cfg->afbc.header = surf.afbc.header;
499
cfg->afbc.body = surf.afbc.body;
500
501
if (rt->image->layout.modifier & AFBC_FORMAT_MOD_YTR)
502
cfg->afbc.yuv_transform_enable = true;
503
} else {
504
assert(rt->image->layout.modifier == DRM_FORMAT_MOD_LINEAR ||
505
rt->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
506
cfg->rgb.base = surf.data;
507
cfg->rgb.row_stride = row_stride;
508
cfg->rgb.surface_stride = layer_stride;
509
}
510
}
511
512
static void
513
pan_emit_rt(const struct panfrost_device *dev,
514
const struct pan_fb_info *fb,
515
unsigned idx, unsigned cbuf_offset, void *out)
516
{
517
pan_pack(out, RENDER_TARGET, cfg) {
518
pan_prepare_rt(dev, fb, idx, cbuf_offset, &cfg);
519
}
520
}
521
522
static unsigned
523
pan_wls_instances(const struct pan_compute_dim *dim)
524
{
525
return util_next_power_of_two(dim->x) *
526
util_next_power_of_two(dim->y) *
527
util_next_power_of_two(dim->z);
528
}
529
530
static unsigned
531
pan_wls_adjust_size(unsigned wls_size)
532
{
533
return util_next_power_of_two(MAX2(wls_size, 128));
534
}
535
536
unsigned
537
pan_wls_mem_size(const struct panfrost_device *dev,
538
const struct pan_compute_dim *dim,
539
unsigned wls_size)
540
{
541
unsigned instances = pan_wls_instances(dim);
542
543
return pan_wls_adjust_size(wls_size) * instances * dev->core_count;
544
}
545
546
void
547
pan_emit_tls(const struct panfrost_device *dev,
548
const struct pan_tls_info *info,
549
void *out)
550
{
551
pan_pack(out, LOCAL_STORAGE, cfg) {
552
if (info->tls.size) {
553
unsigned shift =
554
panfrost_get_stack_shift(info->tls.size);
555
556
/* TODO: Why do we need to make the stack bigger than other platforms? */
557
if (dev->quirks & MIDGARD_SFBD)
558
shift = MAX2(shift, 512);
559
560
cfg.tls_size = shift;
561
cfg.tls_base_pointer = info->tls.ptr;
562
}
563
564
if (info->wls.size) {
565
assert(!(info->wls.ptr & 4095));
566
assert((info->wls.ptr & 0xffffffff00000000ULL) == ((info->wls.ptr + info->wls.size - 1) & 0xffffffff00000000ULL));
567
cfg.wls_base_pointer = info->wls.ptr;
568
unsigned wls_size = pan_wls_adjust_size(info->wls.size);
569
cfg.wls_instances = pan_wls_instances(&info->wls.dim);
570
cfg.wls_size_scale = util_logbase2(wls_size) + 1;
571
} else {
572
cfg.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
573
}
574
}
575
}
576
577
static void
578
pan_emit_bifrost_mfbd_params(const struct panfrost_device *dev,
579
const struct pan_fb_info *fb,
580
void *fbd)
581
{
582
pan_section_pack(fbd, MULTI_TARGET_FRAMEBUFFER, BIFROST_PARAMETERS, params) {
583
params.sample_locations =
584
panfrost_sample_positions(dev, pan_sample_pattern(fb->nr_samples));
585
params.pre_frame_0 = fb->bifrost.pre_post.modes[0];
586
params.pre_frame_1 = fb->bifrost.pre_post.modes[1];
587
params.post_frame = fb->bifrost.pre_post.modes[2];
588
params.frame_shader_dcds = fb->bifrost.pre_post.dcds.gpu;
589
}
590
}
591
592
static void
593
pan_emit_mfbd_bifrost_tiler(const struct pan_tiler_context *ctx, void *fbd)
594
{
595
pan_section_pack(fbd, MULTI_TARGET_FRAMEBUFFER, BIFROST_TILER_POINTER, cfg) {
596
cfg.address = ctx->bifrost;
597
}
598
pan_section_pack(fbd, MULTI_TARGET_FRAMEBUFFER, BIFROST_PADDING, padding);
599
}
600
601
static void
602
pan_emit_midgard_tiler(const struct panfrost_device *dev,
603
const struct pan_fb_info *fb,
604
const struct pan_tiler_context *tiler_ctx,
605
void *out)
606
{
607
bool hierarchy = !(dev->quirks & MIDGARD_NO_HIER_TILING);
608
609
assert(tiler_ctx->midgard.polygon_list->ptr.gpu);
610
611
pan_pack(out, MIDGARD_TILER, cfg) {
612
unsigned header_size;
613
614
if (tiler_ctx->midgard.disable) {
615
cfg.hierarchy_mask =
616
hierarchy ?
617
MALI_MIDGARD_TILER_DISABLED :
618
MALI_MIDGARD_TILER_USER;
619
header_size = MALI_MIDGARD_TILER_MINIMUM_HEADER_SIZE;
620
cfg.polygon_list_size = header_size + (hierarchy ? 0 : 4);
621
cfg.heap_start = tiler_ctx->midgard.polygon_list->ptr.gpu;
622
cfg.heap_end = tiler_ctx->midgard.polygon_list->ptr.gpu;
623
} else {
624
cfg.hierarchy_mask =
625
panfrost_choose_hierarchy_mask(fb->width,
626
fb->height,
627
1, hierarchy);
628
header_size = panfrost_tiler_header_size(fb->width,
629
fb->height,
630
cfg.hierarchy_mask,
631
hierarchy);
632
cfg.polygon_list_size =
633
panfrost_tiler_full_size(fb->width, fb->height,
634
cfg.hierarchy_mask,
635
hierarchy);
636
cfg.heap_start = dev->tiler_heap->ptr.gpu;
637
cfg.heap_end = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size;
638
}
639
640
cfg.polygon_list = tiler_ctx->midgard.polygon_list->ptr.gpu;
641
cfg.polygon_list_body = cfg.polygon_list + header_size;
642
}
643
}
644
645
static void
646
pan_emit_mfbd_midgard_tiler(const struct panfrost_device *dev,
647
const struct pan_fb_info *fb,
648
const struct pan_tiler_context *ctx,
649
void *fbd)
650
{
651
pan_emit_midgard_tiler(dev, fb, ctx,
652
pan_section_ptr(fbd, MULTI_TARGET_FRAMEBUFFER, TILER));
653
654
/* All weights set to 0, nothing to do here */
655
pan_section_pack(fbd, MULTI_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w);
656
}
657
658
static void
659
pan_emit_sfbd_tiler(const struct panfrost_device *dev,
660
const struct pan_fb_info *fb,
661
const struct pan_tiler_context *ctx,
662
void *fbd)
663
{
664
pan_emit_midgard_tiler(dev, fb, ctx,
665
pan_section_ptr(fbd, SINGLE_TARGET_FRAMEBUFFER, TILER));
666
667
/* All weights set to 0, nothing to do here */
668
pan_section_pack(fbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_1, padding);
669
pan_section_pack(fbd, SINGLE_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w);
670
}
671
672
static unsigned
673
pan_emit_mfbd(const struct panfrost_device *dev,
674
const struct pan_fb_info *fb,
675
const struct pan_tls_info *tls,
676
const struct pan_tiler_context *tiler_ctx,
677
void *out)
678
{
679
unsigned tags = MALI_FBD_TAG_IS_MFBD;
680
void *fbd = out;
681
void *rtd = out + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH;
682
683
if (pan_is_bifrost(dev)) {
684
pan_emit_bifrost_mfbd_params(dev, fb, fbd);
685
} else {
686
pan_emit_tls(dev, tls,
687
pan_section_ptr(fbd, MULTI_TARGET_FRAMEBUFFER,
688
LOCAL_STORAGE));
689
}
690
691
unsigned tile_size;
692
unsigned internal_cbuf_size = pan_internal_cbuf_size(fb, &tile_size);
693
int crc_rt = pan_select_crc_rt(dev, fb);
694
bool has_zs_crc_ext = pan_fbd_has_zs_crc_ext(dev, fb);
695
696
pan_section_pack(fbd, MULTI_TARGET_FRAMEBUFFER, PARAMETERS, cfg) {
697
cfg.width = fb->width;
698
cfg.height = fb->height;
699
cfg.bound_max_x = fb->width - 1;
700
cfg.bound_max_y = fb->height - 1;
701
702
cfg.effective_tile_size = tile_size;
703
cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
704
cfg.render_target_count = MAX2(fb->rt_count, 1);
705
706
/* Default to 24 bit depth if there's no surface. */
707
cfg.z_internal_format =
708
fb->zs.view.zs ?
709
panfrost_get_z_internal_format(fb->zs.view.zs->format) :
710
MALI_Z_INTERNAL_FORMAT_D24;
711
712
cfg.z_clear = fb->zs.clear_value.depth;
713
cfg.s_clear = fb->zs.clear_value.stencil;
714
cfg.color_buffer_allocation = internal_cbuf_size;
715
cfg.sample_count = fb->nr_samples;
716
cfg.sample_pattern = pan_sample_pattern(fb->nr_samples);
717
cfg.z_write_enable = (fb->zs.view.zs && !fb->zs.discard.z);
718
cfg.s_write_enable = (fb->zs.view.s && !fb->zs.discard.s);
719
cfg.has_zs_crc_extension = has_zs_crc_ext;
720
721
if (crc_rt >= 0) {
722
bool *valid = fb->rts[crc_rt].crc_valid;
723
bool full = !fb->extent.minx && !fb->extent.miny &&
724
fb->extent.maxx == (fb->width - 1) &&
725
fb->extent.maxy == (fb->height - 1);
726
727
cfg.crc_read_enable = *valid;
728
729
/* If the data is currently invalid, still write CRC
730
* data if we are doing a full write, so that it is
731
* valid for next time. */
732
cfg.crc_write_enable = *valid || full;
733
734
*valid |= full;
735
}
736
}
737
738
if (pan_is_bifrost(dev))
739
pan_emit_mfbd_bifrost_tiler(tiler_ctx, fbd);
740
else
741
pan_emit_mfbd_midgard_tiler(dev, fb, tiler_ctx, fbd);
742
743
if (has_zs_crc_ext) {
744
pan_emit_zs_crc_ext(dev, fb, crc_rt,
745
out + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH);
746
rtd += MALI_ZS_CRC_EXTENSION_LENGTH;
747
tags |= MALI_FBD_TAG_HAS_ZS_RT;
748
}
749
750
unsigned rt_count = MAX2(fb->rt_count, 1);
751
unsigned cbuf_offset = 0;
752
for (unsigned i = 0; i < rt_count; i++) {
753
pan_emit_rt(dev, fb, i, cbuf_offset, rtd);
754
rtd += MALI_RENDER_TARGET_LENGTH;
755
if (!fb->rts[i].view)
756
continue;
757
758
cbuf_offset += pan_bytes_per_pixel_tib(fb->rts[i].view->format) *
759
tile_size * fb->rts[i].view->image->layout.nr_samples;
760
761
if (i != crc_rt)
762
*(fb->rts[i].crc_valid) = false;
763
}
764
tags |= MALI_POSITIVE(MAX2(fb->rt_count, 1)) << 2;
765
766
return tags;
767
}
768
769
static void
770
pan_emit_sfbd(const struct panfrost_device *dev,
771
const struct pan_fb_info *fb,
772
const struct pan_tls_info *tls,
773
const struct pan_tiler_context *tiler_ctx,
774
void *fbd)
775
{
776
pan_emit_tls(dev, tls,
777
pan_section_ptr(fbd, SINGLE_TARGET_FRAMEBUFFER,
778
LOCAL_STORAGE));
779
pan_section_pack(fbd, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, cfg) {
780
cfg.bound_max_x = fb->width - 1;
781
cfg.bound_max_y = fb->height - 1;
782
cfg.dithering_enable = true;
783
cfg.clean_pixel_write_enable = true;
784
cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
785
if (fb->rts[0].clear) {
786
cfg.clear_color_0 = fb->rts[0].clear_value[0];
787
cfg.clear_color_1 = fb->rts[0].clear_value[1];
788
cfg.clear_color_2 = fb->rts[0].clear_value[2];
789
cfg.clear_color_3 = fb->rts[0].clear_value[3];
790
}
791
792
if (fb->zs.clear.z)
793
cfg.z_clear = fb->zs.clear_value.depth;
794
795
if (fb->zs.clear.s)
796
cfg.s_clear = fb->zs.clear_value.stencil;
797
798
if (fb->rt_count && fb->rts[0].view) {
799
const struct pan_image_view *rt = fb->rts[0].view;
800
801
const struct util_format_description *desc =
802
util_format_description(rt->format);
803
804
/* The swizzle for rendering is inverted from texturing */
805
unsigned char swizzle[4];
806
panfrost_invert_swizzle(desc->swizzle, swizzle);
807
cfg.swizzle = panfrost_translate_swizzle_4(swizzle);
808
809
struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format];
810
if (fmt.internal) {
811
cfg.internal_format = fmt.internal;
812
cfg.color_writeback_format = fmt.writeback;
813
} else {
814
unreachable("raw formats not finished for SFBD");
815
}
816
817
unsigned level = rt->first_level;
818
struct pan_surface surf;
819
820
pan_iview_get_surface(rt, 0, 0, 0, &surf);
821
822
cfg.color_write_enable = !fb->rts[0].discard;
823
cfg.color_writeback.base = surf.data;
824
cfg.color_writeback.row_stride =
825
rt->image->layout.slices[level].row_stride;
826
827
cfg.color_block_format = mod_to_block_fmt(rt->image->layout.modifier);
828
assert(cfg.color_block_format == MALI_BLOCK_FORMAT_LINEAR ||
829
cfg.color_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED);
830
831
if (rt->image->layout.crc_mode != PAN_IMAGE_CRC_NONE) {
832
const struct pan_image_slice_layout *slice =
833
&rt->image->layout.slices[level];
834
835
cfg.crc_buffer.row_stride = slice->crc.stride;
836
if (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND) {
837
cfg.crc_buffer.base = rt->image->data.bo->ptr.gpu +
838
rt->image->data.offset +
839
slice->crc.offset;
840
} else {
841
cfg.crc_buffer.base = rt->image->crc.bo->ptr.gpu +
842
rt->image->crc.offset +
843
slice->crc.offset;
844
}
845
}
846
}
847
848
if (fb->zs.view.zs) {
849
const struct pan_image_view *zs = fb->zs.view.zs;
850
unsigned level = zs->first_level;
851
struct pan_surface surf;
852
853
pan_iview_get_surface(zs, 0, 0, 0, &surf);
854
855
cfg.zs_write_enable = !fb->zs.discard.z;
856
cfg.zs_writeback.base = surf.data;
857
cfg.zs_writeback.row_stride =
858
zs->image->layout.slices[level].row_stride;
859
cfg.zs_block_format = mod_to_block_fmt(zs->image->layout.modifier);
860
assert(cfg.zs_block_format == MALI_BLOCK_FORMAT_LINEAR ||
861
cfg.zs_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED);
862
863
cfg.zs_format = translate_zs_format(zs->format);
864
}
865
866
cfg.sample_count = fb->nr_samples;
867
868
/* XXX: different behaviour from MFBD and probably wrong... */
869
cfg.msaa = mali_sampling_mode(fb->rts[0].view);
870
}
871
pan_emit_sfbd_tiler(dev, fb, tiler_ctx, fbd);
872
pan_section_pack(fbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding);
873
}
874
875
unsigned
876
pan_emit_fbd(const struct panfrost_device *dev,
877
const struct pan_fb_info *fb,
878
const struct pan_tls_info *tls,
879
const struct pan_tiler_context *tiler_ctx,
880
void *out)
881
{
882
if (dev->quirks & MIDGARD_SFBD) {
883
assert(fb->rt_count <= 1);
884
pan_emit_sfbd(dev, fb, tls, tiler_ctx, out);
885
return 0;
886
} else {
887
return pan_emit_mfbd(dev, fb, tls, tiler_ctx, out);
888
}
889
}
890
891
void
892
pan_emit_bifrost_tiler_heap(const struct panfrost_device *dev,
893
void *out)
894
{
895
pan_pack(out, BIFROST_TILER_HEAP, heap) {
896
heap.size = dev->tiler_heap->size;
897
heap.base = dev->tiler_heap->ptr.gpu;
898
heap.bottom = dev->tiler_heap->ptr.gpu;
899
heap.top = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size;
900
}
901
}
902
903
void
904
pan_emit_bifrost_tiler(const struct panfrost_device *dev,
905
unsigned fb_width, unsigned fb_height,
906
unsigned nr_samples,
907
mali_ptr heap,
908
void *out)
909
{
910
unsigned max_levels = dev->tiler_features.max_levels;
911
assert(max_levels >= 2);
912
913
pan_pack(out, BIFROST_TILER, tiler) {
914
/* TODO: Select hierarchy mask more effectively */
915
tiler.hierarchy_mask = (max_levels >= 8) ? 0xFF : 0x28;
916
tiler.fb_width = fb_width;
917
tiler.fb_height = fb_height;
918
tiler.heap = heap;
919
tiler.sample_pattern = pan_sample_pattern(nr_samples);
920
}
921
}
922
923
void
924
pan_emit_fragment_job(const struct panfrost_device *dev,
925
const struct pan_fb_info *fb,
926
mali_ptr fbd,
927
void *out)
928
{
929
pan_section_pack(out, FRAGMENT_JOB, HEADER, header) {
930
header.type = MALI_JOB_TYPE_FRAGMENT;
931
header.index = 1;
932
}
933
934
pan_section_pack(out, FRAGMENT_JOB, PAYLOAD, payload) {
935
payload.bound_min_x = fb->extent.minx >> MALI_TILE_SHIFT;
936
payload.bound_min_y = fb->extent.miny >> MALI_TILE_SHIFT;
937
payload.bound_max_x = fb->extent.maxx >> MALI_TILE_SHIFT;
938
payload.bound_max_y = fb->extent.maxy >> MALI_TILE_SHIFT;
939
payload.framebuffer = fbd;
940
941
if (fb->tile_map.base) {
942
payload.has_tile_enable_map = true;
943
payload.tile_enable_map = fb->tile_map.base;
944
payload.tile_enable_map_row_stride = fb->tile_map.stride;
945
}
946
}
947
}
948
949