1 /*
2 * Copyright (C) 2019-2020 Collabora, Ltd.
3 * Copyright 2018-2019 Alyssa Rosenzweig
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 */
25
26 #include "pan_bo.h"
27 #include "pan_context.h"
28 #include "pan_cmdstream.h"
29 #include "pan_util.h"
30 #include "panfrost-quirks.h"
31
32
33 static bool
panfrost_mfbd_has_zs_crc_ext(struct panfrost_batch * batch)34 panfrost_mfbd_has_zs_crc_ext(struct panfrost_batch *batch)
35 {
36 if (batch->key.nr_cbufs == 1) {
37 struct pipe_surface *surf = batch->key.cbufs[0];
38 struct panfrost_resource *rsrc = pan_resource(surf->texture);
39
40 if (rsrc->checksummed)
41 return true;
42 }
43
44 if (batch->key.zsbuf &&
45 ((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL))
46 return true;
47
48 return false;
49 }
50
51 static unsigned
panfrost_mfbd_size(struct panfrost_batch * batch)52 panfrost_mfbd_size(struct panfrost_batch *batch)
53 {
54 unsigned rt_count = MAX2(batch->key.nr_cbufs, 1);
55
56 return MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH +
57 (panfrost_mfbd_has_zs_crc_ext(batch) * MALI_ZS_CRC_EXTENSION_LENGTH) +
58 (rt_count * MALI_RENDER_TARGET_LENGTH);
59 }
60
61 static enum mali_mfbd_color_format
panfrost_mfbd_raw_format(unsigned bits)62 panfrost_mfbd_raw_format(unsigned bits)
63 {
64 switch (bits) {
65 case 8: return MALI_MFBD_COLOR_FORMAT_RAW8;
66 case 16: return MALI_MFBD_COLOR_FORMAT_RAW16;
67 case 24: return MALI_MFBD_COLOR_FORMAT_RAW24;
68 case 32: return MALI_MFBD_COLOR_FORMAT_RAW32;
69 case 48: return MALI_MFBD_COLOR_FORMAT_RAW48;
70 case 64: return MALI_MFBD_COLOR_FORMAT_RAW64;
71 case 96: return MALI_MFBD_COLOR_FORMAT_RAW96;
72 case 128: return MALI_MFBD_COLOR_FORMAT_RAW128;
73 case 192: return MALI_MFBD_COLOR_FORMAT_RAW192;
74 case 256: return MALI_MFBD_COLOR_FORMAT_RAW256;
75 case 384: return MALI_MFBD_COLOR_FORMAT_RAW384;
76 case 512: return MALI_MFBD_COLOR_FORMAT_RAW512;
77 case 768: return MALI_MFBD_COLOR_FORMAT_RAW768;
78 case 1024: return MALI_MFBD_COLOR_FORMAT_RAW1024;
79 case 1536: return MALI_MFBD_COLOR_FORMAT_RAW1536;
80 case 2048: return MALI_MFBD_COLOR_FORMAT_RAW2048;
81 default: unreachable("invalid raw bpp");
82 }
83 }
84
85 static void
panfrost_mfbd_rt_init_format(struct pipe_surface * surf,struct MALI_RENDER_TARGET * rt)86 panfrost_mfbd_rt_init_format(struct pipe_surface *surf,
87 struct MALI_RENDER_TARGET *rt)
88 {
89 /* Explode details on the format */
90
91 const struct util_format_description *desc =
92 util_format_description(surf->format);
93
94 /* The swizzle for rendering is inverted from texturing */
95
96 unsigned char swizzle[4];
97 panfrost_invert_swizzle(desc->swizzle, swizzle);
98
99 rt->swizzle = panfrost_translate_swizzle_4(swizzle);
100
101 /* Fill in accordingly, defaulting to 8-bit UNORM */
102
103 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
104 rt->srgb = true;
105
106 struct pan_blendable_format fmt = panfrost_blend_format(surf->format);
107
108 if (fmt.internal) {
109 rt->internal_format = fmt.internal;
110 rt->writeback_format = fmt.writeback;
111 } else {
112 /* Construct RAW internal/writeback, where internal is
113 * specified logarithmically (round to next power-of-two).
114 * Offset specified from RAW8, where 8 = 2^3 */
115
116 unsigned bits = desc->block.bits;
117 unsigned offset = util_logbase2_ceil(bits) - 3;
118 assert(offset <= 4);
119
120 rt->internal_format =
121 MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW8 + offset;
122
123 rt->writeback_format = panfrost_mfbd_raw_format(bits);
124 }
125 }
126
127 static void
panfrost_mfbd_rt_set_buf(struct pipe_surface * surf,struct MALI_RENDER_TARGET * rt)128 panfrost_mfbd_rt_set_buf(struct pipe_surface *surf,
129 struct MALI_RENDER_TARGET *rt)
130 {
131 struct panfrost_device *dev = pan_device(surf->context->screen);
132 unsigned version = dev->gpu_id >> 12;
133 struct panfrost_resource *rsrc = pan_resource(surf->texture);
134 unsigned level = surf->u.tex.level;
135 unsigned first_layer = surf->u.tex.first_layer;
136 assert(surf->u.tex.last_layer == first_layer);
137 int stride = rsrc->slices[level].stride;
138
139 /* Only set layer_stride for layered MSAA rendering */
140
141 unsigned nr_samples = surf->texture->nr_samples;
142 unsigned layer_stride = (nr_samples > 1) ? rsrc->slices[level].size0 : 0;
143 mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
144
145 if (layer_stride)
146 rt->writeback_msaa = MALI_MSAA_LAYERED;
147 else if (surf->nr_samples)
148 rt->writeback_msaa = MALI_MSAA_AVERAGE;
149 else
150 rt->writeback_msaa = MALI_MSAA_SINGLE;
151
152 panfrost_mfbd_rt_init_format(surf, rt);
153
154 if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) {
155 if (version >= 7)
156 rt->bifrost_v7.writeback_block_format = MALI_BLOCK_FORMAT_V7_LINEAR;
157 else
158 rt->midgard.writeback_block_format = MALI_BLOCK_FORMAT_LINEAR;
159
160 rt->rgb.base = base;
161 rt->rgb.row_stride = stride;
162 rt->rgb.surface_stride = layer_stride;
163 } else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
164 if (version >= 7)
165 rt->bifrost_v7.writeback_block_format = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED;
166 else
167 rt->midgard.writeback_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
168
169 rt->rgb.base = base;
170 rt->rgb.row_stride = stride * 16;
171 rt->rgb.surface_stride = layer_stride;
172 } else if (drm_is_afbc(rsrc->modifier)) {
173 if (version >= 7)
174 rt->bifrost_v7.writeback_block_format = MALI_BLOCK_FORMAT_V7_AFBC;
175 else
176 rt->midgard.writeback_block_format = MALI_BLOCK_FORMAT_AFBC;
177
178 unsigned header_size = rsrc->slices[level].header_size;
179
180 rt->afbc.header = base;
181 rt->afbc.chunk_size = 9;
182 rt->afbc.body = base + header_size;
183
184 if (!(dev->quirks & IS_BIFROST))
185 rt->midgard_afbc.sparse = true;
186
187 if (rsrc->modifier & AFBC_FORMAT_MOD_YTR)
188 rt->afbc.yuv_transform_enable = true;
189
190 /* TODO: The blob sets this to something nonzero, but it's not
191 * clear what/how to calculate/if it matters */
192 rt->afbc.body_size = 0;
193 } else {
194 unreachable("Invalid mod");
195 }
196 }
197
198 static void
panfrost_mfbd_emit_rt(struct panfrost_batch * batch,void * rtp,struct pipe_surface * surf,unsigned rt_offset,unsigned rt_idx)199 panfrost_mfbd_emit_rt(struct panfrost_batch *batch,
200 void *rtp, struct pipe_surface *surf,
201 unsigned rt_offset, unsigned rt_idx)
202 {
203 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
204 unsigned version = dev->gpu_id >> 12;
205
206 pan_pack(rtp, RENDER_TARGET, rt) {
207 rt.clean_pixel_write_enable = true;
208 if (surf) {
209 rt.write_enable = true;
210 rt.dithering_enable = true;
211 rt.internal_buffer_offset = rt_offset;
212 panfrost_mfbd_rt_set_buf(surf, &rt);
213 } else {
214 rt.internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8;
215 rt.internal_buffer_offset = rt_offset;
216 if (version >= 7) {
217 rt.bifrost_v7.writeback_block_format = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED;
218 rt.dithering_enable = true;
219 }
220 }
221
222 if (batch->clear & (PIPE_CLEAR_COLOR0 << rt_idx)) {
223 rt.clear.color_0 = batch->clear_color[rt_idx][0];
224 rt.clear.color_1 = batch->clear_color[rt_idx][1];
225 rt.clear.color_2 = batch->clear_color[rt_idx][2];
226 rt.clear.color_3 = batch->clear_color[rt_idx][3];
227 }
228 }
229 }
230
231 static enum mali_z_internal_format
get_z_internal_format(struct panfrost_batch * batch)232 get_z_internal_format(struct panfrost_batch *batch)
233 {
234 struct pipe_surface *zs_surf = batch->key.zsbuf;
235
236 /* Default to 24 bit depth if there's no surface. */
237 if (!zs_surf || !((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL))
238 return MALI_Z_INTERNAL_FORMAT_D24;
239
240 return panfrost_get_z_internal_format(zs_surf->format);
241 }
242
243 static void
panfrost_mfbd_zs_crc_ext_set_bufs(struct panfrost_batch * batch,struct MALI_ZS_CRC_EXTENSION * ext)244 panfrost_mfbd_zs_crc_ext_set_bufs(struct panfrost_batch *batch,
245 struct MALI_ZS_CRC_EXTENSION *ext)
246 {
247 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
248 unsigned version = dev->gpu_id >> 12;
249
250 /* Checksumming only works with a single render target */
251 if (batch->key.nr_cbufs == 1) {
252 struct pipe_surface *c_surf = batch->key.cbufs[0];
253 struct panfrost_resource *rsrc = pan_resource(c_surf->texture);
254
255 if (rsrc->checksummed) {
256 unsigned level = c_surf->u.tex.level;
257 struct panfrost_slice *slice = &rsrc->slices[level];
258
259 ext->crc_row_stride = slice->checksum_stride;
260 if (slice->checksum_bo)
261 ext->crc_base = slice->checksum_bo->ptr.gpu;
262 else
263 ext->crc_base = rsrc->bo->ptr.gpu + slice->checksum_offset;
264
265 if ((batch->clear & PIPE_CLEAR_COLOR0) && version >= 7) {
266 ext->crc_clear_color = batch->clear_color[0][0] |
267 0xc000000000000000 |
268 ((uint64_t)batch->clear_color[0][0] & 0xffff) << 32;
269 }
270 }
271 }
272
273 struct pipe_surface *zs_surf = batch->key.zsbuf;
274
275 if (!((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL))
276 zs_surf = NULL;
277
278 if (!zs_surf)
279 return;
280
281 struct panfrost_resource *rsrc = pan_resource(zs_surf->texture);
282 unsigned nr_samples = MAX2(zs_surf->texture->nr_samples, 1);
283 unsigned level = zs_surf->u.tex.level;
284 unsigned first_layer = zs_surf->u.tex.first_layer;
285 assert(zs_surf->u.tex.last_layer == first_layer);
286
287 mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
288
289 ext->zs_msaa = nr_samples > 1 ? MALI_MSAA_LAYERED : MALI_MSAA_SINGLE;
290
291 if (drm_is_afbc(rsrc->modifier)) {
292 unsigned header_size = rsrc->slices[level].header_size;
293 ext->zs_afbc_header = base;
294 ext->zs_afbc_body = base + header_size;
295 ext->zs_afbc_body_size = 0x1000;
296 ext->zs_afbc_chunk_size = 9;
297 ext->zs_afbc_sparse = true;
298
299 if (version >= 7)
300 ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_AFBC;
301 else
302 ext->zs_block_format = MALI_BLOCK_FORMAT_AFBC;
303 } else {
304 assert(rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
305 rsrc->modifier == DRM_FORMAT_MOD_LINEAR);
306 /* TODO: Z32F(S8) support, which is always linear */
307
308 int stride = rsrc->slices[level].stride;
309
310 unsigned layer_stride = (nr_samples > 1) ? rsrc->slices[level].size0 : 0;
311
312 ext->zs_writeback_base = base;
313 ext->zs_writeback_row_stride = stride;
314 ext->zs_writeback_surface_stride = layer_stride;
315
316 if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) {
317 if (version >= 7)
318 ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_LINEAR;
319 else
320 ext->zs_block_format = MALI_BLOCK_FORMAT_LINEAR;
321 } else {
322 ext->zs_writeback_row_stride *= 16;
323 if (version >= 7)
324 ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED;
325 else
326 ext->zs_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
327 }
328 }
329
330 switch (zs_surf->format) {
331 case PIPE_FORMAT_Z16_UNORM:
332 ext->zs_write_format = MALI_ZS_FORMAT_D16;
333 break;
334 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
335 ext->zs_write_format = MALI_ZS_FORMAT_D24S8;
336 break;
337 case PIPE_FORMAT_Z24X8_UNORM:
338 ext->zs_write_format = MALI_ZS_FORMAT_D24X8;
339 break;
340 case PIPE_FORMAT_Z32_FLOAT:
341 ext->zs_write_format = MALI_ZS_FORMAT_D32;
342 break;
343 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
344 /* Midgard/Bifrost support interleaved depth/stencil
345 * buffers, but we always treat them as multu-planar.
346 */
347 ext->zs_write_format = MALI_ZS_FORMAT_D32;
348 ext->s_write_format = MALI_S_FORMAT_S8;
349
350 struct panfrost_resource *stencil = rsrc->separate_stencil;
351 struct panfrost_slice stencil_slice = stencil->slices[level];
352 unsigned stencil_layer_stride = (nr_samples > 1) ? stencil_slice.size0 : 0;
353
354 ext->s_writeback_base = panfrost_get_texture_address(stencil, level, first_layer, 0);
355 ext->s_writeback_row_stride = stencil_slice.stride;
356 if (rsrc->modifier != DRM_FORMAT_MOD_LINEAR)
357 ext->s_writeback_row_stride *= 16;
358 ext->s_writeback_surface_stride = stencil_layer_stride;
359 break;
360 default:
361 unreachable("Unsupported depth/stencil format.");
362 }
363 }
364
365 static void
panfrost_mfbd_emit_zs_crc_ext(struct panfrost_batch * batch,void * extp)366 panfrost_mfbd_emit_zs_crc_ext(struct panfrost_batch *batch, void *extp)
367 {
368 pan_pack(extp, ZS_CRC_EXTENSION, ext) {
369 ext.zs_clean_pixel_write_enable = true;
370 panfrost_mfbd_zs_crc_ext_set_bufs(batch, &ext);
371 }
372 }
373
374 /* Measure format as it appears in the tile buffer */
375
376 static unsigned
pan_bytes_per_pixel_tib(enum pipe_format format)377 pan_bytes_per_pixel_tib(enum pipe_format format)
378 {
379 if (panfrost_blend_format(format).internal) {
380 /* Blendable formats are always 32-bits in the tile buffer,
381 * extra bits are used as padding or to dither */
382 return 4;
383 } else {
384 /* Non-blendable formats are raw, rounded up to the nearest
385 * power-of-two size */
386 unsigned bytes = util_format_get_blocksize(format);
387 return util_next_power_of_two(bytes);
388 }
389 }
390
391 /* Calculates the internal color buffer size and tile size based on the number
392 * of RT, the format and the number of pixels. If things do not fit in 4KB, we
393 * shrink the tile size to make it fit.
394 */
395
396 static unsigned
pan_internal_cbuf_size(struct panfrost_batch * batch,unsigned * tile_size)397 pan_internal_cbuf_size(struct panfrost_batch *batch, unsigned *tile_size)
398 {
399 unsigned total_size = 0;
400
401 *tile_size = 16 * 16;
402 for (int cb = 0; cb < batch->key.nr_cbufs; ++cb) {
403 struct pipe_surface *surf = batch->key.cbufs[cb];
404 assert(surf);
405
406 unsigned nr_samples = MAX3(surf->nr_samples, surf->texture->nr_samples, 1);
407 total_size += pan_bytes_per_pixel_tib(surf->format) *
408 nr_samples * (*tile_size);
409 }
410
411 /* We have a 4KB budget, let's reduce the tile size until it fits. */
412 while (total_size > 4096) {
413 total_size >>= 1;
414 *tile_size >>= 1;
415 }
416
417 /* Align on 1k. */
418 total_size = ALIGN_POT(total_size, 1024);
419
420 /* Minimum tile size is 4x4. */
421 assert(*tile_size > 4 * 4);
422 return total_size;
423 }
424
425 static void
panfrost_mfbd_emit_local_storage(struct panfrost_batch * batch,void * fb)426 panfrost_mfbd_emit_local_storage(struct panfrost_batch *batch, void *fb)
427 {
428 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
429
430 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, LOCAL_STORAGE, ls) {
431 if (batch->stack_size) {
432 unsigned shift =
433 panfrost_get_stack_shift(batch->stack_size);
434 struct panfrost_bo *bo =
435 panfrost_batch_get_scratchpad(batch,
436 batch->stack_size,
437 dev->thread_tls_alloc,
438 dev->core_count);
439 ls.tls_size = shift;
440 ls.tls_base_pointer = bo->ptr.gpu;
441 }
442
443 ls.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
444 }
445 }
446
447 static void
panfrost_mfbd_emit_midgard_tiler(struct panfrost_batch * batch,void * fb,unsigned vertex_count)448 panfrost_mfbd_emit_midgard_tiler(struct panfrost_batch *batch, void *fb,
449 unsigned vertex_count)
450 {
451 void *t = pan_section_ptr(fb, MULTI_TARGET_FRAMEBUFFER, TILER);
452
453 panfrost_emit_midg_tiler(batch, t, vertex_count);
454
455 /* All weights set to 0, nothing to do here */
456 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w);
457 }
458
459 static void
panfrost_mfbd_emit_bifrost_parameters(struct panfrost_batch * batch,void * fb)460 panfrost_mfbd_emit_bifrost_parameters(struct panfrost_batch *batch, void *fb)
461 {
462 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_PARAMETERS, params) {
463 params.sample_locations = panfrost_emit_sample_locations(batch);
464 }
465 }
466
467 static void
panfrost_mfbd_emit_bifrost_tiler(struct panfrost_batch * batch,void * fb,unsigned vertex_count)468 panfrost_mfbd_emit_bifrost_tiler(struct panfrost_batch *batch, void *fb,
469 unsigned vertex_count)
470 {
471 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_TILER_POINTER, tiler) {
472 tiler.address = panfrost_batch_get_bifrost_tiler(batch, vertex_count);
473 }
474 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_PADDING, padding);
475 }
476
477 void
panfrost_attach_mfbd(struct panfrost_batch * batch,unsigned vertex_count)478 panfrost_attach_mfbd(struct panfrost_batch *batch, unsigned vertex_count)
479 {
480 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
481 void *fb = batch->framebuffer.cpu;
482
483 panfrost_mfbd_emit_local_storage(batch, fb);
484
485 if (dev->quirks & IS_BIFROST)
486 return;
487
488 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, PARAMETERS, params) {
489 params.width = batch->key.width;
490 params.height = batch->key.height;
491 params.bound_max_x = batch->key.width - 1;
492 params.bound_max_y = batch->key.height - 1;
493 params.color_buffer_allocation =
494 pan_internal_cbuf_size(batch, ¶ms.effective_tile_size);
495 params.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
496 params.render_target_count = MAX2(batch->key.nr_cbufs, 1);
497 }
498
499 panfrost_mfbd_emit_midgard_tiler(batch, fb, vertex_count);
500 }
501
502 /* Creates an MFBD for the FRAGMENT section of the bound framebuffer */
503
504 mali_ptr
panfrost_mfbd_fragment(struct panfrost_batch * batch,bool has_draws)505 panfrost_mfbd_fragment(struct panfrost_batch *batch, bool has_draws)
506 {
507 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
508 unsigned vertex_count = has_draws;
509 struct panfrost_ptr t =
510 panfrost_pool_alloc_aligned(&batch->pool,
511 panfrost_mfbd_size(batch), 64);
512 void *fb = t.cpu, *zs_crc_ext, *rts;
513
514 if (panfrost_mfbd_has_zs_crc_ext(batch)) {
515 zs_crc_ext = fb + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH;
516 rts = zs_crc_ext + MALI_ZS_CRC_EXTENSION_LENGTH;
517 } else {
518 zs_crc_ext = NULL;
519 rts = fb + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH;
520 }
521
522 /* When scanning out, the depth buffer is immediately invalidated, so
523 * we don't need to waste bandwidth writing it out. This can improve
524 * performance substantially (Z24X8_UNORM 1080p @ 60fps is 475 MB/s of
525 * memory bandwidth!).
526 *
527 * The exception is ReadPixels, but this is not supported on GLES so we
528 * can safely ignore it. */
529
530 if (panfrost_batch_is_scanout(batch))
531 batch->requirements &= ~PAN_REQ_DEPTH_WRITE;
532
533 if (zs_crc_ext) {
534 if (batch->key.zsbuf &&
535 MAX2(batch->key.zsbuf->nr_samples, batch->key.zsbuf->nr_samples) > 1)
536 batch->requirements |= PAN_REQ_MSAA;
537
538 panfrost_mfbd_emit_zs_crc_ext(batch, zs_crc_ext);
539 }
540
541 /* We always upload at least one dummy GL_NONE render target */
542
543 unsigned rt_descriptors = MAX2(batch->key.nr_cbufs, 1);
544
545 /* Upload either the render target or a dummy GL_NONE target */
546
547 unsigned rt_offset = 0, tib_size;
548 unsigned internal_cbuf_size = pan_internal_cbuf_size(batch, &tib_size);
549
550 for (int cb = 0; cb < rt_descriptors; ++cb) {
551 struct pipe_surface *surf = batch->key.cbufs[cb];
552 void *rt = rts + (cb * MALI_RENDER_TARGET_LENGTH);
553
554 if (!((batch->clear | batch->draws) & (PIPE_CLEAR_COLOR0 << cb)))
555 surf = NULL;
556
557 panfrost_mfbd_emit_rt(batch, rt, surf, rt_offset, cb);
558
559 if (surf) {
560 if (MAX2(surf->nr_samples, surf->texture->nr_samples) > 1)
561 batch->requirements |= PAN_REQ_MSAA;
562
563 rt_offset += pan_bytes_per_pixel_tib(surf->format) * tib_size;
564 }
565 }
566
567 if (dev->quirks & IS_BIFROST)
568 panfrost_mfbd_emit_bifrost_parameters(batch, fb);
569 else
570 panfrost_mfbd_emit_local_storage(batch, fb);
571
572 pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, PARAMETERS, params) {
573 params.width = batch->key.width;
574 params.height = batch->key.height;
575 params.bound_max_x = batch->key.width - 1;
576 params.bound_max_y = batch->key.height - 1;
577 params.effective_tile_size = tib_size;
578 params.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
579 params.render_target_count = rt_descriptors;
580 params.z_internal_format = get_z_internal_format(batch);
581
582 if (batch->clear & PIPE_CLEAR_DEPTH)
583 params.z_clear = batch->clear_depth;
584 if (batch->clear & PIPE_CLEAR_STENCIL)
585 params.s_clear = batch->clear_stencil & 0xff;
586
587 params.color_buffer_allocation = internal_cbuf_size;
588
589 if (batch->requirements & PAN_REQ_MSAA) {
590 /* MSAA 4x */
591 params.sample_count = 4;
592 params.sample_pattern = MALI_SAMPLE_PATTERN_ROTATED_4X_GRID;
593 }
594
595 if (batch->key.zsbuf &&
596 ((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) {
597 params.z_write_enable = true;
598 if (batch->key.zsbuf->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)
599 params.s_write_enable = true;
600 }
601
602 params.has_zs_crc_extension = !!zs_crc_ext;
603 }
604
605 if (dev->quirks & IS_BIFROST)
606 panfrost_mfbd_emit_bifrost_tiler(batch, fb, vertex_count);
607 else
608 panfrost_mfbd_emit_midgard_tiler(batch, fb, vertex_count);
609
610 /* Return pointer suitable for the fragment section */
611 unsigned tag =
612 MALI_FBD_TAG_IS_MFBD |
613 (zs_crc_ext ? MALI_FBD_TAG_HAS_ZS_RT : 0) |
614 (MALI_POSITIVE(rt_descriptors) << 2);
615
616 return t.gpu | tag;
617 }
618