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, &params.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