17ec681f3Smrg/* 27ec681f3Smrg * Copyright (C) 2021 Collabora, Ltd. 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217ec681f3Smrg * SOFTWARE. 227ec681f3Smrg * 237ec681f3Smrg * Authors: 247ec681f3Smrg * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> 257ec681f3Smrg * Boris Brezillon <boris.brezillon@collabora.com> 267ec681f3Smrg */ 277ec681f3Smrg 287ec681f3Smrg#include "util/macros.h" 297ec681f3Smrg 307ec681f3Smrg#include "panfrost-quirks.h" 317ec681f3Smrg 327ec681f3Smrg#include "pan_cs.h" 337ec681f3Smrg#include "pan_encoder.h" 347ec681f3Smrg#include "pan_texture.h" 357ec681f3Smrg 367ec681f3Smrgstatic unsigned 377ec681f3Smrgmod_to_block_fmt(uint64_t mod) 387ec681f3Smrg{ 397ec681f3Smrg switch (mod) { 407ec681f3Smrg case DRM_FORMAT_MOD_LINEAR: 417ec681f3Smrg return MALI_BLOCK_FORMAT_LINEAR; 427ec681f3Smrg case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED: 437ec681f3Smrg return MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED; 447ec681f3Smrg default: 457ec681f3Smrg#if PAN_ARCH >= 5 467ec681f3Smrg if (drm_is_afbc(mod)) 477ec681f3Smrg return MALI_BLOCK_FORMAT_AFBC; 487ec681f3Smrg#endif 497ec681f3Smrg 507ec681f3Smrg unreachable("Unsupported modifer"); 517ec681f3Smrg } 527ec681f3Smrg} 537ec681f3Smrg 547ec681f3Smrgstatic enum mali_msaa 557ec681f3Smrgmali_sampling_mode(const struct pan_image_view *view) 567ec681f3Smrg{ 577ec681f3Smrg if (view->image->layout.nr_samples > 1) { 587ec681f3Smrg assert(view->nr_samples == view->image->layout.nr_samples); 597ec681f3Smrg assert(view->image->layout.slices[0].surface_stride != 0); 607ec681f3Smrg return MALI_MSAA_LAYERED; 617ec681f3Smrg } 627ec681f3Smrg 637ec681f3Smrg if (view->nr_samples > view->image->layout.nr_samples) { 647ec681f3Smrg assert(view->image->layout.nr_samples == 1); 657ec681f3Smrg return MALI_MSAA_AVERAGE; 667ec681f3Smrg } 677ec681f3Smrg 687ec681f3Smrg assert(view->nr_samples == view->image->layout.nr_samples); 697ec681f3Smrg assert(view->nr_samples == 1); 707ec681f3Smrg 717ec681f3Smrg return MALI_MSAA_SINGLE; 727ec681f3Smrg} 737ec681f3Smrg 747ec681f3Smrgstatic inline enum mali_sample_pattern 757ec681f3Smrgpan_sample_pattern(unsigned samples) 767ec681f3Smrg{ 777ec681f3Smrg switch (samples) { 787ec681f3Smrg case 1: return MALI_SAMPLE_PATTERN_SINGLE_SAMPLED; 797ec681f3Smrg case 4: return MALI_SAMPLE_PATTERN_ROTATED_4X_GRID; 807ec681f3Smrg case 8: return MALI_SAMPLE_PATTERN_D3D_8X_GRID; 817ec681f3Smrg case 16: return MALI_SAMPLE_PATTERN_D3D_16X_GRID; 827ec681f3Smrg default: unreachable("Unsupported sample count"); 837ec681f3Smrg } 847ec681f3Smrg} 857ec681f3Smrg 867ec681f3Smrgint 877ec681f3SmrgGENX(pan_select_crc_rt)(const struct pan_fb_info *fb) 887ec681f3Smrg{ 897ec681f3Smrg#if PAN_ARCH <= 6 907ec681f3Smrg if (fb->rt_count == 1 && fb->rts[0].view && !fb->rts[0].discard && 917ec681f3Smrg fb->rts[0].view->image->layout.crc_mode != PAN_IMAGE_CRC_NONE) 927ec681f3Smrg return 0; 937ec681f3Smrg 947ec681f3Smrg return -1; 957ec681f3Smrg#else 967ec681f3Smrg bool best_rt_valid = false; 977ec681f3Smrg int best_rt = -1; 987ec681f3Smrg 997ec681f3Smrg for (unsigned i = 0; i < fb->rt_count; i++) { 1007ec681f3Smrg if (!fb->rts[i].view || fb->rts[0].discard || 1017ec681f3Smrg fb->rts[i].view->image->layout.crc_mode == PAN_IMAGE_CRC_NONE) 1027ec681f3Smrg continue; 1037ec681f3Smrg 1047ec681f3Smrg bool valid = *(fb->rts[i].crc_valid); 1057ec681f3Smrg bool full = !fb->extent.minx && !fb->extent.miny && 1067ec681f3Smrg fb->extent.maxx == (fb->width - 1) && 1077ec681f3Smrg fb->extent.maxy == (fb->height - 1); 1087ec681f3Smrg if (!full && !valid) 1097ec681f3Smrg continue; 1107ec681f3Smrg 1117ec681f3Smrg if (best_rt < 0 || (valid && !best_rt_valid)) { 1127ec681f3Smrg best_rt = i; 1137ec681f3Smrg best_rt_valid = valid; 1147ec681f3Smrg } 1157ec681f3Smrg 1167ec681f3Smrg if (valid) 1177ec681f3Smrg break; 1187ec681f3Smrg } 1197ec681f3Smrg 1207ec681f3Smrg return best_rt; 1217ec681f3Smrg#endif 1227ec681f3Smrg} 1237ec681f3Smrg 1247ec681f3Smrgstatic enum mali_zs_format 1257ec681f3Smrgtranslate_zs_format(enum pipe_format in) 1267ec681f3Smrg{ 1277ec681f3Smrg switch (in) { 1287ec681f3Smrg case PIPE_FORMAT_Z16_UNORM: return MALI_ZS_FORMAT_D16; 1297ec681f3Smrg case PIPE_FORMAT_Z24_UNORM_S8_UINT: return MALI_ZS_FORMAT_D24S8; 1307ec681f3Smrg case PIPE_FORMAT_Z24X8_UNORM: return MALI_ZS_FORMAT_D24X8; 1317ec681f3Smrg case PIPE_FORMAT_Z32_FLOAT: return MALI_ZS_FORMAT_D32; 1327ec681f3Smrg case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: return MALI_ZS_FORMAT_D32_S8X24; 1337ec681f3Smrg default: unreachable("Unsupported depth/stencil format."); 1347ec681f3Smrg } 1357ec681f3Smrg} 1367ec681f3Smrg 1377ec681f3Smrg#if PAN_ARCH >= 5 1387ec681f3Smrgstatic enum mali_s_format 1397ec681f3Smrgtranslate_s_format(enum pipe_format in) 1407ec681f3Smrg{ 1417ec681f3Smrg switch (in) { 1427ec681f3Smrg case PIPE_FORMAT_S8_UINT: return MALI_S_FORMAT_S8; 1437ec681f3Smrg case PIPE_FORMAT_S8_UINT_Z24_UNORM: 1447ec681f3Smrg case PIPE_FORMAT_S8X24_UINT: 1457ec681f3Smrg return MALI_S_FORMAT_S8X24; 1467ec681f3Smrg case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1477ec681f3Smrg case PIPE_FORMAT_X24S8_UINT: 1487ec681f3Smrg return MALI_S_FORMAT_X24S8; 1497ec681f3Smrg case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1507ec681f3Smrg return MALI_S_FORMAT_X32_S8X24; 1517ec681f3Smrg default: 1527ec681f3Smrg unreachable("Unsupported stencil format."); 1537ec681f3Smrg } 1547ec681f3Smrg} 1557ec681f3Smrg 1567ec681f3Smrgstatic void 1577ec681f3Smrgpan_prepare_s(const struct pan_fb_info *fb, 1587ec681f3Smrg struct MALI_ZS_CRC_EXTENSION *ext) 1597ec681f3Smrg{ 1607ec681f3Smrg const struct pan_image_view *s = fb->zs.view.s; 1617ec681f3Smrg 1627ec681f3Smrg if (!s) 1637ec681f3Smrg return; 1647ec681f3Smrg 1657ec681f3Smrg unsigned level = s->first_level; 1667ec681f3Smrg 1677ec681f3Smrg ext->s_msaa = mali_sampling_mode(s); 1687ec681f3Smrg 1697ec681f3Smrg struct pan_surface surf; 1707ec681f3Smrg pan_iview_get_surface(s, 0, 0, 0, &surf); 1717ec681f3Smrg 1727ec681f3Smrg assert(s->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED || 1737ec681f3Smrg s->image->layout.modifier == DRM_FORMAT_MOD_LINEAR); 1747ec681f3Smrg ext->s_writeback_base = surf.data; 1757ec681f3Smrg ext->s_writeback_row_stride = s->image->layout.slices[level].row_stride; 1767ec681f3Smrg ext->s_writeback_surface_stride = 1777ec681f3Smrg (s->image->layout.nr_samples > 1) ? 1787ec681f3Smrg s->image->layout.slices[level].surface_stride : 0; 1797ec681f3Smrg ext->s_block_format = mod_to_block_fmt(s->image->layout.modifier); 1807ec681f3Smrg ext->s_write_format = translate_s_format(s->format); 1817ec681f3Smrg} 1827ec681f3Smrg 1837ec681f3Smrgstatic void 1847ec681f3Smrgpan_prepare_zs(const struct pan_fb_info *fb, 1857ec681f3Smrg struct MALI_ZS_CRC_EXTENSION *ext) 1867ec681f3Smrg{ 1877ec681f3Smrg const struct pan_image_view *zs = fb->zs.view.zs; 1887ec681f3Smrg 1897ec681f3Smrg if (!zs) 1907ec681f3Smrg return; 1917ec681f3Smrg 1927ec681f3Smrg unsigned level = zs->first_level; 1937ec681f3Smrg 1947ec681f3Smrg ext->zs_msaa = mali_sampling_mode(zs); 1957ec681f3Smrg 1967ec681f3Smrg struct pan_surface surf; 1977ec681f3Smrg pan_iview_get_surface(zs, 0, 0, 0, &surf); 1987ec681f3Smrg 1997ec681f3Smrg if (drm_is_afbc(zs->image->layout.modifier)) { 2007ec681f3Smrg#if PAN_ARCH >= 6 2017ec681f3Smrg const struct pan_image_slice_layout *slice = &zs->image->layout.slices[level]; 2027ec681f3Smrg 2037ec681f3Smrg ext->zs_afbc_row_stride = slice->afbc.row_stride / 2047ec681f3Smrg AFBC_HEADER_BYTES_PER_TILE; 2057ec681f3Smrg#else 2067ec681f3Smrg ext->zs_block_format = MALI_BLOCK_FORMAT_AFBC; 2077ec681f3Smrg ext->zs_afbc_body_size = 0x1000; 2087ec681f3Smrg ext->zs_afbc_chunk_size = 9; 2097ec681f3Smrg ext->zs_afbc_sparse = true; 2107ec681f3Smrg#endif 2117ec681f3Smrg 2127ec681f3Smrg ext->zs_afbc_header = surf.afbc.header; 2137ec681f3Smrg ext->zs_afbc_body = surf.afbc.body; 2147ec681f3Smrg } else { 2157ec681f3Smrg assert(zs->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED || 2167ec681f3Smrg zs->image->layout.modifier == DRM_FORMAT_MOD_LINEAR); 2177ec681f3Smrg 2187ec681f3Smrg /* TODO: Z32F(S8) support, which is always linear */ 2197ec681f3Smrg 2207ec681f3Smrg ext->zs_writeback_base = surf.data; 2217ec681f3Smrg ext->zs_writeback_row_stride = 2227ec681f3Smrg zs->image->layout.slices[level].row_stride; 2237ec681f3Smrg ext->zs_writeback_surface_stride = 2247ec681f3Smrg (zs->image->layout.nr_samples > 1) ? 2257ec681f3Smrg zs->image->layout.slices[level].surface_stride : 0; 2267ec681f3Smrg } 2277ec681f3Smrg 2287ec681f3Smrg ext->zs_block_format = mod_to_block_fmt(zs->image->layout.modifier); 2297ec681f3Smrg ext->zs_write_format = translate_zs_format(zs->format); 2307ec681f3Smrg if (ext->zs_write_format == MALI_ZS_FORMAT_D24S8) 2317ec681f3Smrg ext->s_writeback_base = ext->zs_writeback_base; 2327ec681f3Smrg} 2337ec681f3Smrg 2347ec681f3Smrgstatic void 2357ec681f3Smrgpan_prepare_crc(const struct pan_fb_info *fb, int rt_crc, 2367ec681f3Smrg struct MALI_ZS_CRC_EXTENSION *ext) 2377ec681f3Smrg{ 2387ec681f3Smrg if (rt_crc < 0) 2397ec681f3Smrg return; 2407ec681f3Smrg 2417ec681f3Smrg assert(rt_crc < fb->rt_count); 2427ec681f3Smrg 2437ec681f3Smrg const struct pan_image_view *rt = fb->rts[rt_crc].view; 2447ec681f3Smrg const struct pan_image_slice_layout *slice = &rt->image->layout.slices[rt->first_level]; 2457ec681f3Smrg ext->crc_base = (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND ? 2467ec681f3Smrg (rt->image->data.bo->ptr.gpu + rt->image->data.offset) : 2477ec681f3Smrg (rt->image->crc.bo->ptr.gpu + rt->image->crc.offset)) + 2487ec681f3Smrg slice->crc.offset; 2497ec681f3Smrg ext->crc_row_stride = slice->crc.stride; 2507ec681f3Smrg 2517ec681f3Smrg#if PAN_ARCH >= 7 2527ec681f3Smrg ext->crc_render_target = rt_crc; 2537ec681f3Smrg 2547ec681f3Smrg if (fb->rts[rt_crc].clear) { 2557ec681f3Smrg uint32_t clear_val = fb->rts[rt_crc].clear_value[0]; 2567ec681f3Smrg ext->crc_clear_color = clear_val | 0xc000000000000000 | 2577ec681f3Smrg (((uint64_t)clear_val & 0xffff) << 32); 2587ec681f3Smrg } 2597ec681f3Smrg#endif 2607ec681f3Smrg} 2617ec681f3Smrg 2627ec681f3Smrgstatic void 2637ec681f3Smrgpan_emit_zs_crc_ext(const struct pan_fb_info *fb, int rt_crc, 2647ec681f3Smrg void *zs_crc_ext) 2657ec681f3Smrg{ 2667ec681f3Smrg pan_pack(zs_crc_ext, ZS_CRC_EXTENSION, cfg) { 2677ec681f3Smrg pan_prepare_crc(fb, rt_crc, &cfg); 2687ec681f3Smrg cfg.zs_clean_pixel_write_enable = fb->zs.clear.z || fb->zs.clear.s; 2697ec681f3Smrg pan_prepare_zs(fb, &cfg); 2707ec681f3Smrg pan_prepare_s(fb, &cfg); 2717ec681f3Smrg } 2727ec681f3Smrg} 2737ec681f3Smrg 2747ec681f3Smrg/* Measure format as it appears in the tile buffer */ 2757ec681f3Smrg 2767ec681f3Smrgstatic unsigned 2777ec681f3Smrgpan_bytes_per_pixel_tib(enum pipe_format format) 2787ec681f3Smrg{ 2797ec681f3Smrg if (panfrost_blendable_formats_v7[format].internal) { 2807ec681f3Smrg /* Blendable formats are always 32-bits in the tile buffer, 2817ec681f3Smrg * extra bits are used as padding or to dither */ 2827ec681f3Smrg return 4; 2837ec681f3Smrg } else { 2847ec681f3Smrg /* Non-blendable formats are raw, rounded up to the nearest 2857ec681f3Smrg * power-of-two size */ 2867ec681f3Smrg unsigned bytes = util_format_get_blocksize(format); 2877ec681f3Smrg return util_next_power_of_two(bytes); 2887ec681f3Smrg } 2897ec681f3Smrg} 2907ec681f3Smrg 2917ec681f3Smrgstatic unsigned 2927ec681f3Smrgpan_internal_cbuf_size(const struct pan_fb_info *fb, 2937ec681f3Smrg unsigned *tile_size) 2947ec681f3Smrg{ 2957ec681f3Smrg unsigned total_size = 0; 2967ec681f3Smrg 2977ec681f3Smrg *tile_size = 16 * 16; 2987ec681f3Smrg for (int cb = 0; cb < fb->rt_count; ++cb) { 2997ec681f3Smrg const struct pan_image_view *rt = fb->rts[cb].view; 3007ec681f3Smrg 3017ec681f3Smrg if (!rt) 3027ec681f3Smrg continue; 3037ec681f3Smrg 3047ec681f3Smrg total_size += pan_bytes_per_pixel_tib(rt->format) * 3057ec681f3Smrg rt->nr_samples * (*tile_size); 3067ec681f3Smrg } 3077ec681f3Smrg 3087ec681f3Smrg /* We have a 4KB budget, let's reduce the tile size until it fits. */ 3097ec681f3Smrg while (total_size > 4096) { 3107ec681f3Smrg total_size >>= 1; 3117ec681f3Smrg *tile_size >>= 1; 3127ec681f3Smrg } 3137ec681f3Smrg 3147ec681f3Smrg /* Align on 1k. */ 3157ec681f3Smrg total_size = ALIGN_POT(total_size, 1024); 3167ec681f3Smrg 3177ec681f3Smrg /* Minimum tile size is 4x4. */ 3187ec681f3Smrg assert(*tile_size >= 4 * 4); 3197ec681f3Smrg return total_size; 3207ec681f3Smrg} 3217ec681f3Smrg 3227ec681f3Smrgstatic enum mali_color_format 3237ec681f3Smrgpan_mfbd_raw_format(unsigned bits) 3247ec681f3Smrg{ 3257ec681f3Smrg switch (bits) { 3267ec681f3Smrg case 8: return MALI_COLOR_FORMAT_RAW8; 3277ec681f3Smrg case 16: return MALI_COLOR_FORMAT_RAW16; 3287ec681f3Smrg case 24: return MALI_COLOR_FORMAT_RAW24; 3297ec681f3Smrg case 32: return MALI_COLOR_FORMAT_RAW32; 3307ec681f3Smrg case 48: return MALI_COLOR_FORMAT_RAW48; 3317ec681f3Smrg case 64: return MALI_COLOR_FORMAT_RAW64; 3327ec681f3Smrg case 96: return MALI_COLOR_FORMAT_RAW96; 3337ec681f3Smrg case 128: return MALI_COLOR_FORMAT_RAW128; 3347ec681f3Smrg case 192: return MALI_COLOR_FORMAT_RAW192; 3357ec681f3Smrg case 256: return MALI_COLOR_FORMAT_RAW256; 3367ec681f3Smrg case 384: return MALI_COLOR_FORMAT_RAW384; 3377ec681f3Smrg case 512: return MALI_COLOR_FORMAT_RAW512; 3387ec681f3Smrg case 768: return MALI_COLOR_FORMAT_RAW768; 3397ec681f3Smrg case 1024: return MALI_COLOR_FORMAT_RAW1024; 3407ec681f3Smrg case 1536: return MALI_COLOR_FORMAT_RAW1536; 3417ec681f3Smrg case 2048: return MALI_COLOR_FORMAT_RAW2048; 3427ec681f3Smrg default: unreachable("invalid raw bpp"); 3437ec681f3Smrg } 3447ec681f3Smrg} 3457ec681f3Smrg 3467ec681f3Smrgstatic void 3477ec681f3Smrgpan_rt_init_format(const struct pan_image_view *rt, 3487ec681f3Smrg struct MALI_RENDER_TARGET *cfg) 3497ec681f3Smrg{ 3507ec681f3Smrg /* Explode details on the format */ 3517ec681f3Smrg 3527ec681f3Smrg const struct util_format_description *desc = 3537ec681f3Smrg util_format_description(rt->format); 3547ec681f3Smrg 3557ec681f3Smrg /* The swizzle for rendering is inverted from texturing */ 3567ec681f3Smrg 3577ec681f3Smrg unsigned char swizzle[4] = { 3587ec681f3Smrg PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W, 3597ec681f3Smrg }; 3607ec681f3Smrg 3617ec681f3Smrg /* Fill in accordingly, defaulting to 8-bit UNORM */ 3627ec681f3Smrg 3637ec681f3Smrg if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) 3647ec681f3Smrg cfg->srgb = true; 3657ec681f3Smrg 3667ec681f3Smrg struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format]; 3677ec681f3Smrg 3687ec681f3Smrg if (fmt.internal) { 3697ec681f3Smrg cfg->internal_format = fmt.internal; 3707ec681f3Smrg cfg->writeback_format = fmt.writeback; 3717ec681f3Smrg panfrost_invert_swizzle(desc->swizzle, swizzle); 3727ec681f3Smrg } else { 3737ec681f3Smrg /* Construct RAW internal/writeback, where internal is 3747ec681f3Smrg * specified logarithmically (round to next power-of-two). 3757ec681f3Smrg * Offset specified from RAW8, where 8 = 2^3 */ 3767ec681f3Smrg 3777ec681f3Smrg unsigned bits = desc->block.bits; 3787ec681f3Smrg unsigned offset = util_logbase2_ceil(bits) - 3; 3797ec681f3Smrg assert(offset <= 4); 3807ec681f3Smrg 3817ec681f3Smrg cfg->internal_format = 3827ec681f3Smrg MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW8 + offset; 3837ec681f3Smrg 3847ec681f3Smrg cfg->writeback_format = pan_mfbd_raw_format(bits); 3857ec681f3Smrg } 3867ec681f3Smrg 3877ec681f3Smrg cfg->swizzle = panfrost_translate_swizzle_4(swizzle); 3887ec681f3Smrg} 3897ec681f3Smrg 3907ec681f3Smrgstatic void 3917ec681f3Smrgpan_prepare_rt(const struct pan_fb_info *fb, unsigned idx, 3927ec681f3Smrg unsigned cbuf_offset, 3937ec681f3Smrg struct MALI_RENDER_TARGET *cfg) 3947ec681f3Smrg{ 3957ec681f3Smrg cfg->clean_pixel_write_enable = fb->rts[idx].clear; 3967ec681f3Smrg cfg->internal_buffer_offset = cbuf_offset; 3977ec681f3Smrg if (fb->rts[idx].clear) { 3987ec681f3Smrg cfg->clear.color_0 = fb->rts[idx].clear_value[0]; 3997ec681f3Smrg cfg->clear.color_1 = fb->rts[idx].clear_value[1]; 4007ec681f3Smrg cfg->clear.color_2 = fb->rts[idx].clear_value[2]; 4017ec681f3Smrg cfg->clear.color_3 = fb->rts[idx].clear_value[3]; 4027ec681f3Smrg } 4037ec681f3Smrg 4047ec681f3Smrg const struct pan_image_view *rt = fb->rts[idx].view; 4057ec681f3Smrg if (!rt || fb->rts[idx].discard) { 4067ec681f3Smrg cfg->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8; 4077ec681f3Smrg cfg->internal_buffer_offset = cbuf_offset; 4087ec681f3Smrg#if PAN_ARCH >= 7 4097ec681f3Smrg cfg->writeback_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED; 4107ec681f3Smrg cfg->dithering_enable = true; 4117ec681f3Smrg#endif 4127ec681f3Smrg return; 4137ec681f3Smrg } 4147ec681f3Smrg 4157ec681f3Smrg cfg->write_enable = true; 4167ec681f3Smrg cfg->dithering_enable = true; 4177ec681f3Smrg 4187ec681f3Smrg unsigned level = rt->first_level; 4197ec681f3Smrg assert(rt->last_level == rt->first_level); 4207ec681f3Smrg assert(rt->last_layer == rt->first_layer); 4217ec681f3Smrg 4227ec681f3Smrg int row_stride = rt->image->layout.slices[level].row_stride; 4237ec681f3Smrg 4247ec681f3Smrg /* Only set layer_stride for layered MSAA rendering */ 4257ec681f3Smrg 4267ec681f3Smrg unsigned layer_stride = 4277ec681f3Smrg (rt->image->layout.nr_samples > 1) ? 4287ec681f3Smrg rt->image->layout.slices[level].surface_stride : 0; 4297ec681f3Smrg 4307ec681f3Smrg cfg->writeback_msaa = mali_sampling_mode(rt); 4317ec681f3Smrg 4327ec681f3Smrg pan_rt_init_format(rt, cfg); 4337ec681f3Smrg 4347ec681f3Smrg#if PAN_ARCH <= 5 4357ec681f3Smrg cfg->writeback_block_format = mod_to_block_fmt(rt->image->layout.modifier); 4367ec681f3Smrg#else 4377ec681f3Smrg cfg->writeback_block_format = mod_to_block_fmt(rt->image->layout.modifier); 4387ec681f3Smrg#endif 4397ec681f3Smrg 4407ec681f3Smrg struct pan_surface surf; 4417ec681f3Smrg pan_iview_get_surface(rt, 0, 0, 0, &surf); 4427ec681f3Smrg 4437ec681f3Smrg if (drm_is_afbc(rt->image->layout.modifier)) { 4447ec681f3Smrg const struct pan_image_slice_layout *slice = &rt->image->layout.slices[level]; 4457ec681f3Smrg 4467ec681f3Smrg#if PAN_ARCH >= 6 4477ec681f3Smrg cfg->afbc.row_stride = slice->afbc.row_stride / 4487ec681f3Smrg AFBC_HEADER_BYTES_PER_TILE; 4497ec681f3Smrg cfg->afbc.afbc_wide_block_enable = 4507ec681f3Smrg panfrost_block_dim(rt->image->layout.modifier, true, 0) > 16; 4517ec681f3Smrg#else 4527ec681f3Smrg cfg->afbc.chunk_size = 9; 4537ec681f3Smrg cfg->afbc.sparse = true; 4547ec681f3Smrg cfg->afbc.body_size = slice->afbc.body_size; 4557ec681f3Smrg#endif 4567ec681f3Smrg 4577ec681f3Smrg cfg->afbc.header = surf.afbc.header; 4587ec681f3Smrg cfg->afbc.body = surf.afbc.body; 4597ec681f3Smrg 4607ec681f3Smrg if (rt->image->layout.modifier & AFBC_FORMAT_MOD_YTR) 4617ec681f3Smrg cfg->afbc.yuv_transform_enable = true; 4627ec681f3Smrg } else { 4637ec681f3Smrg assert(rt->image->layout.modifier == DRM_FORMAT_MOD_LINEAR || 4647ec681f3Smrg rt->image->layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED); 4657ec681f3Smrg cfg->rgb.base = surf.data; 4667ec681f3Smrg cfg->rgb.row_stride = row_stride; 4677ec681f3Smrg cfg->rgb.surface_stride = layer_stride; 4687ec681f3Smrg } 4697ec681f3Smrg} 4707ec681f3Smrg#endif 4717ec681f3Smrg 4727ec681f3Smrgvoid 4737ec681f3SmrgGENX(pan_emit_tls)(const struct pan_tls_info *info, 4747ec681f3Smrg void *out) 4757ec681f3Smrg{ 4767ec681f3Smrg pan_pack(out, LOCAL_STORAGE, cfg) { 4777ec681f3Smrg if (info->tls.size) { 4787ec681f3Smrg unsigned shift = 4797ec681f3Smrg panfrost_get_stack_shift(info->tls.size); 4807ec681f3Smrg 4817ec681f3Smrg cfg.tls_size = shift; 4827ec681f3Smrg cfg.tls_base_pointer = info->tls.ptr; 4837ec681f3Smrg } 4847ec681f3Smrg 4857ec681f3Smrg if (info->wls.size) { 4867ec681f3Smrg assert(!(info->wls.ptr & 4095)); 4877ec681f3Smrg assert((info->wls.ptr & 0xffffffff00000000ULL) == ((info->wls.ptr + info->wls.size - 1) & 0xffffffff00000000ULL)); 4887ec681f3Smrg cfg.wls_base_pointer = info->wls.ptr; 4897ec681f3Smrg unsigned wls_size = pan_wls_adjust_size(info->wls.size); 4907ec681f3Smrg cfg.wls_instances = pan_wls_instances(&info->wls.dim); 4917ec681f3Smrg cfg.wls_size_scale = util_logbase2(wls_size) + 1; 4927ec681f3Smrg } else { 4937ec681f3Smrg cfg.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM; 4947ec681f3Smrg } 4957ec681f3Smrg } 4967ec681f3Smrg} 4977ec681f3Smrg 4987ec681f3Smrg#if PAN_ARCH <= 5 4997ec681f3Smrgstatic void 5007ec681f3Smrgpan_emit_midgard_tiler(const struct panfrost_device *dev, 5017ec681f3Smrg const struct pan_fb_info *fb, 5027ec681f3Smrg const struct pan_tiler_context *tiler_ctx, 5037ec681f3Smrg void *out) 5047ec681f3Smrg{ 5057ec681f3Smrg bool hierarchy = !(dev->quirks & MIDGARD_NO_HIER_TILING); 5067ec681f3Smrg 5077ec681f3Smrg assert(tiler_ctx->midgard.polygon_list->ptr.gpu); 5087ec681f3Smrg 5097ec681f3Smrg pan_pack(out, TILER_CONTEXT, cfg) { 5107ec681f3Smrg unsigned header_size; 5117ec681f3Smrg 5127ec681f3Smrg if (tiler_ctx->midgard.disable) { 5137ec681f3Smrg cfg.hierarchy_mask = 5147ec681f3Smrg hierarchy ? 5157ec681f3Smrg MALI_MIDGARD_TILER_DISABLED : 5167ec681f3Smrg MALI_MIDGARD_TILER_USER; 5177ec681f3Smrg header_size = MALI_MIDGARD_TILER_MINIMUM_HEADER_SIZE; 5187ec681f3Smrg cfg.polygon_list_size = header_size + (hierarchy ? 0 : 4); 5197ec681f3Smrg cfg.heap_start = tiler_ctx->midgard.polygon_list->ptr.gpu; 5207ec681f3Smrg cfg.heap_end = tiler_ctx->midgard.polygon_list->ptr.gpu; 5217ec681f3Smrg } else { 5227ec681f3Smrg cfg.hierarchy_mask = 5237ec681f3Smrg panfrost_choose_hierarchy_mask(fb->width, 5247ec681f3Smrg fb->height, 5257ec681f3Smrg 1, hierarchy); 5267ec681f3Smrg header_size = panfrost_tiler_header_size(fb->width, 5277ec681f3Smrg fb->height, 5287ec681f3Smrg cfg.hierarchy_mask, 5297ec681f3Smrg hierarchy); 5307ec681f3Smrg cfg.polygon_list_size = 5317ec681f3Smrg panfrost_tiler_full_size(fb->width, fb->height, 5327ec681f3Smrg cfg.hierarchy_mask, 5337ec681f3Smrg hierarchy); 5347ec681f3Smrg cfg.heap_start = dev->tiler_heap->ptr.gpu; 5357ec681f3Smrg cfg.heap_end = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size; 5367ec681f3Smrg } 5377ec681f3Smrg 5387ec681f3Smrg cfg.polygon_list = tiler_ctx->midgard.polygon_list->ptr.gpu; 5397ec681f3Smrg cfg.polygon_list_body = cfg.polygon_list + header_size; 5407ec681f3Smrg } 5417ec681f3Smrg} 5427ec681f3Smrg#endif 5437ec681f3Smrg 5447ec681f3Smrg#if PAN_ARCH >= 5 5457ec681f3Smrgstatic void 5467ec681f3Smrgpan_emit_rt(const struct pan_fb_info *fb, 5477ec681f3Smrg unsigned idx, unsigned cbuf_offset, void *out) 5487ec681f3Smrg{ 5497ec681f3Smrg pan_pack(out, RENDER_TARGET, cfg) { 5507ec681f3Smrg pan_prepare_rt(fb, idx, cbuf_offset, &cfg); 5517ec681f3Smrg } 5527ec681f3Smrg} 5537ec681f3Smrg 5547ec681f3Smrg#if PAN_ARCH >= 6 5557ec681f3Smrg/* All Bifrost and Valhall GPUs are affected by issue TSIX-2033: 5567ec681f3Smrg * 5577ec681f3Smrg * Forcing clean_tile_writes breaks INTERSECT readbacks 5587ec681f3Smrg * 5597ec681f3Smrg * To workaround, use the frame shader mode ALWAYS instead of INTERSECT if 5607ec681f3Smrg * clean tile writes is forced. Since INTERSECT is a hint that the hardware may 5617ec681f3Smrg * ignore, this cannot affect correctness, only performance */ 5627ec681f3Smrg 5637ec681f3Smrgstatic enum mali_pre_post_frame_shader_mode 5647ec681f3Smrgpan_fix_frame_shader_mode(enum mali_pre_post_frame_shader_mode mode, bool force_clean_tile) 5657ec681f3Smrg{ 5667ec681f3Smrg if (force_clean_tile && mode == MALI_PRE_POST_FRAME_SHADER_MODE_INTERSECT) 5677ec681f3Smrg return MALI_PRE_POST_FRAME_SHADER_MODE_ALWAYS; 5687ec681f3Smrg else 5697ec681f3Smrg return mode; 5707ec681f3Smrg} 5717ec681f3Smrg 5727ec681f3Smrg/* Regardless of clean_tile_write_enable, the hardware writes clean tiles if 5737ec681f3Smrg * the effective tile size differs from the superblock size of any enabled AFBC 5747ec681f3Smrg * render target. Check this condition. */ 5757ec681f3Smrg 5767ec681f3Smrgstatic bool 5777ec681f3Smrgpan_force_clean_write_rt(const struct pan_image_view *rt, unsigned tile_size) 5787ec681f3Smrg{ 5797ec681f3Smrg if (!drm_is_afbc(rt->image->layout.modifier)) 5807ec681f3Smrg return false; 5817ec681f3Smrg 5827ec681f3Smrg unsigned superblock = panfrost_block_dim(rt->image->layout.modifier, true, 0); 5837ec681f3Smrg 5847ec681f3Smrg assert(superblock >= 16); 5857ec681f3Smrg assert(tile_size <= 16*16); 5867ec681f3Smrg 5877ec681f3Smrg /* Tile size and superblock differ unless they are both 16x16 */ 5887ec681f3Smrg return !(superblock == 16 && tile_size == 16*16); 5897ec681f3Smrg} 5907ec681f3Smrg 5917ec681f3Smrgstatic bool 5927ec681f3Smrgpan_force_clean_write(const struct pan_fb_info *fb, unsigned tile_size) 5937ec681f3Smrg{ 5947ec681f3Smrg /* Maximum tile size */ 5957ec681f3Smrg assert(tile_size <= 16*16); 5967ec681f3Smrg 5977ec681f3Smrg for (unsigned i = 0; i < fb->rt_count; ++i) { 5987ec681f3Smrg if (fb->rts[i].view && !fb->rts[i].discard && 5997ec681f3Smrg pan_force_clean_write_rt(fb->rts[i].view, tile_size)) 6007ec681f3Smrg return true; 6017ec681f3Smrg } 6027ec681f3Smrg 6037ec681f3Smrg if (fb->zs.view.zs && !fb->zs.discard.z && 6047ec681f3Smrg pan_force_clean_write_rt(fb->zs.view.zs, tile_size)) 6057ec681f3Smrg return true; 6067ec681f3Smrg 6077ec681f3Smrg if (fb->zs.view.s && !fb->zs.discard.s && 6087ec681f3Smrg pan_force_clean_write_rt(fb->zs.view.s, tile_size)) 6097ec681f3Smrg return true; 6107ec681f3Smrg 6117ec681f3Smrg return false; 6127ec681f3Smrg} 6137ec681f3Smrg 6147ec681f3Smrg#endif 6157ec681f3Smrg 6167ec681f3Smrgstatic unsigned 6177ec681f3Smrgpan_emit_mfbd(const struct panfrost_device *dev, 6187ec681f3Smrg const struct pan_fb_info *fb, 6197ec681f3Smrg const struct pan_tls_info *tls, 6207ec681f3Smrg const struct pan_tiler_context *tiler_ctx, 6217ec681f3Smrg void *out) 6227ec681f3Smrg{ 6237ec681f3Smrg unsigned tags = MALI_FBD_TAG_IS_MFBD; 6247ec681f3Smrg void *fbd = out; 6257ec681f3Smrg void *rtd = out + pan_size(FRAMEBUFFER); 6267ec681f3Smrg 6277ec681f3Smrg#if PAN_ARCH <= 5 6287ec681f3Smrg GENX(pan_emit_tls)(tls, 6297ec681f3Smrg pan_section_ptr(fbd, FRAMEBUFFER, LOCAL_STORAGE)); 6307ec681f3Smrg#endif 6317ec681f3Smrg 6327ec681f3Smrg unsigned tile_size; 6337ec681f3Smrg unsigned internal_cbuf_size = pan_internal_cbuf_size(fb, &tile_size); 6347ec681f3Smrg int crc_rt = GENX(pan_select_crc_rt)(fb); 6357ec681f3Smrg bool has_zs_crc_ext = pan_fbd_has_zs_crc_ext(fb); 6367ec681f3Smrg 6377ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, PARAMETERS, cfg) { 6387ec681f3Smrg#if PAN_ARCH >= 6 6397ec681f3Smrg bool force_clean_write = pan_force_clean_write(fb, tile_size); 6407ec681f3Smrg 6417ec681f3Smrg cfg.sample_locations = 6427ec681f3Smrg panfrost_sample_positions(dev, pan_sample_pattern(fb->nr_samples)); 6437ec681f3Smrg cfg.pre_frame_0 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[0], force_clean_write); 6447ec681f3Smrg cfg.pre_frame_1 = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[1], force_clean_write); 6457ec681f3Smrg cfg.post_frame = pan_fix_frame_shader_mode(fb->bifrost.pre_post.modes[2], force_clean_write); 6467ec681f3Smrg cfg.frame_shader_dcds = fb->bifrost.pre_post.dcds.gpu; 6477ec681f3Smrg cfg.tiler = tiler_ctx->bifrost; 6487ec681f3Smrg#endif 6497ec681f3Smrg cfg.width = fb->width; 6507ec681f3Smrg cfg.height = fb->height; 6517ec681f3Smrg cfg.bound_max_x = fb->width - 1; 6527ec681f3Smrg cfg.bound_max_y = fb->height - 1; 6537ec681f3Smrg 6547ec681f3Smrg cfg.effective_tile_size = tile_size; 6557ec681f3Smrg cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT; 6567ec681f3Smrg cfg.render_target_count = MAX2(fb->rt_count, 1); 6577ec681f3Smrg 6587ec681f3Smrg /* Default to 24 bit depth if there's no surface. */ 6597ec681f3Smrg cfg.z_internal_format = 6607ec681f3Smrg fb->zs.view.zs ? 6617ec681f3Smrg panfrost_get_z_internal_format(fb->zs.view.zs->format) : 6627ec681f3Smrg MALI_Z_INTERNAL_FORMAT_D24; 6637ec681f3Smrg 6647ec681f3Smrg cfg.z_clear = fb->zs.clear_value.depth; 6657ec681f3Smrg cfg.s_clear = fb->zs.clear_value.stencil; 6667ec681f3Smrg cfg.color_buffer_allocation = internal_cbuf_size; 6677ec681f3Smrg cfg.sample_count = fb->nr_samples; 6687ec681f3Smrg cfg.sample_pattern = pan_sample_pattern(fb->nr_samples); 6697ec681f3Smrg cfg.z_write_enable = (fb->zs.view.zs && !fb->zs.discard.z); 6707ec681f3Smrg cfg.s_write_enable = (fb->zs.view.s && !fb->zs.discard.s); 6717ec681f3Smrg cfg.has_zs_crc_extension = has_zs_crc_ext; 6727ec681f3Smrg 6737ec681f3Smrg if (crc_rt >= 0) { 6747ec681f3Smrg bool *valid = fb->rts[crc_rt].crc_valid; 6757ec681f3Smrg bool full = !fb->extent.minx && !fb->extent.miny && 6767ec681f3Smrg fb->extent.maxx == (fb->width - 1) && 6777ec681f3Smrg fb->extent.maxy == (fb->height - 1); 6787ec681f3Smrg 6797ec681f3Smrg cfg.crc_read_enable = *valid; 6807ec681f3Smrg 6817ec681f3Smrg /* If the data is currently invalid, still write CRC 6827ec681f3Smrg * data if we are doing a full write, so that it is 6837ec681f3Smrg * valid for next time. */ 6847ec681f3Smrg cfg.crc_write_enable = *valid || full; 6857ec681f3Smrg 6867ec681f3Smrg *valid |= full; 6877ec681f3Smrg } 6887ec681f3Smrg } 6897ec681f3Smrg 6907ec681f3Smrg#if PAN_ARCH >= 6 6917ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, PADDING, padding); 6927ec681f3Smrg#else 6937ec681f3Smrg pan_emit_midgard_tiler(dev, fb, tiler_ctx, 6947ec681f3Smrg pan_section_ptr(fbd, FRAMEBUFFER, TILER)); 6957ec681f3Smrg 6967ec681f3Smrg /* All weights set to 0, nothing to do here */ 6977ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, TILER_WEIGHTS, w); 6987ec681f3Smrg#endif 6997ec681f3Smrg 7007ec681f3Smrg if (has_zs_crc_ext) { 7017ec681f3Smrg pan_emit_zs_crc_ext(fb, crc_rt, 7027ec681f3Smrg out + pan_size(FRAMEBUFFER)); 7037ec681f3Smrg rtd += pan_size(ZS_CRC_EXTENSION); 7047ec681f3Smrg tags |= MALI_FBD_TAG_HAS_ZS_RT; 7057ec681f3Smrg } 7067ec681f3Smrg 7077ec681f3Smrg unsigned rt_count = MAX2(fb->rt_count, 1); 7087ec681f3Smrg unsigned cbuf_offset = 0; 7097ec681f3Smrg for (unsigned i = 0; i < rt_count; i++) { 7107ec681f3Smrg pan_emit_rt(fb, i, cbuf_offset, rtd); 7117ec681f3Smrg rtd += pan_size(RENDER_TARGET); 7127ec681f3Smrg if (!fb->rts[i].view) 7137ec681f3Smrg continue; 7147ec681f3Smrg 7157ec681f3Smrg cbuf_offset += pan_bytes_per_pixel_tib(fb->rts[i].view->format) * 7167ec681f3Smrg tile_size * fb->rts[i].view->image->layout.nr_samples; 7177ec681f3Smrg 7187ec681f3Smrg if (i != crc_rt) 7197ec681f3Smrg *(fb->rts[i].crc_valid) = false; 7207ec681f3Smrg } 7217ec681f3Smrg tags |= MALI_POSITIVE(MAX2(fb->rt_count, 1)) << 2; 7227ec681f3Smrg 7237ec681f3Smrg return tags; 7247ec681f3Smrg} 7257ec681f3Smrg#else /* PAN_ARCH == 4 */ 7267ec681f3Smrgstatic void 7277ec681f3Smrgpan_emit_sfbd_tiler(const struct panfrost_device *dev, 7287ec681f3Smrg const struct pan_fb_info *fb, 7297ec681f3Smrg const struct pan_tiler_context *ctx, 7307ec681f3Smrg void *fbd) 7317ec681f3Smrg{ 7327ec681f3Smrg pan_emit_midgard_tiler(dev, fb, ctx, 7337ec681f3Smrg pan_section_ptr(fbd, FRAMEBUFFER, TILER)); 7347ec681f3Smrg 7357ec681f3Smrg /* All weights set to 0, nothing to do here */ 7367ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, PADDING_1, padding); 7377ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, TILER_WEIGHTS, w); 7387ec681f3Smrg} 7397ec681f3Smrg 7407ec681f3Smrgstatic void 7417ec681f3Smrgpan_emit_sfbd(const struct panfrost_device *dev, 7427ec681f3Smrg const struct pan_fb_info *fb, 7437ec681f3Smrg const struct pan_tls_info *tls, 7447ec681f3Smrg const struct pan_tiler_context *tiler_ctx, 7457ec681f3Smrg void *fbd) 7467ec681f3Smrg{ 7477ec681f3Smrg GENX(pan_emit_tls)(tls, 7487ec681f3Smrg pan_section_ptr(fbd, FRAMEBUFFER, 7497ec681f3Smrg LOCAL_STORAGE)); 7507ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, PARAMETERS, cfg) { 7517ec681f3Smrg cfg.bound_max_x = fb->width - 1; 7527ec681f3Smrg cfg.bound_max_y = fb->height - 1; 7537ec681f3Smrg cfg.dithering_enable = true; 7547ec681f3Smrg cfg.clean_pixel_write_enable = true; 7557ec681f3Smrg cfg.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT; 7567ec681f3Smrg if (fb->rts[0].clear) { 7577ec681f3Smrg cfg.clear_color_0 = fb->rts[0].clear_value[0]; 7587ec681f3Smrg cfg.clear_color_1 = fb->rts[0].clear_value[1]; 7597ec681f3Smrg cfg.clear_color_2 = fb->rts[0].clear_value[2]; 7607ec681f3Smrg cfg.clear_color_3 = fb->rts[0].clear_value[3]; 7617ec681f3Smrg } 7627ec681f3Smrg 7637ec681f3Smrg if (fb->zs.clear.z) 7647ec681f3Smrg cfg.z_clear = fb->zs.clear_value.depth; 7657ec681f3Smrg 7667ec681f3Smrg if (fb->zs.clear.s) 7677ec681f3Smrg cfg.s_clear = fb->zs.clear_value.stencil; 7687ec681f3Smrg 7697ec681f3Smrg if (fb->rt_count && fb->rts[0].view) { 7707ec681f3Smrg const struct pan_image_view *rt = fb->rts[0].view; 7717ec681f3Smrg 7727ec681f3Smrg const struct util_format_description *desc = 7737ec681f3Smrg util_format_description(rt->format); 7747ec681f3Smrg 7757ec681f3Smrg /* The swizzle for rendering is inverted from texturing */ 7767ec681f3Smrg unsigned char swizzle[4]; 7777ec681f3Smrg panfrost_invert_swizzle(desc->swizzle, swizzle); 7787ec681f3Smrg cfg.swizzle = panfrost_translate_swizzle_4(swizzle); 7797ec681f3Smrg 7807ec681f3Smrg struct pan_blendable_format fmt = panfrost_blendable_formats_v7[rt->format]; 7817ec681f3Smrg if (fmt.internal) { 7827ec681f3Smrg cfg.internal_format = fmt.internal; 7837ec681f3Smrg cfg.color_writeback_format = fmt.writeback; 7847ec681f3Smrg } else { 7857ec681f3Smrg unreachable("raw formats not finished for SFBD"); 7867ec681f3Smrg } 7877ec681f3Smrg 7887ec681f3Smrg unsigned level = rt->first_level; 7897ec681f3Smrg struct pan_surface surf; 7907ec681f3Smrg 7917ec681f3Smrg pan_iview_get_surface(rt, 0, 0, 0, &surf); 7927ec681f3Smrg 7937ec681f3Smrg cfg.color_write_enable = !fb->rts[0].discard; 7947ec681f3Smrg cfg.color_writeback.base = surf.data; 7957ec681f3Smrg cfg.color_writeback.row_stride = 7967ec681f3Smrg rt->image->layout.slices[level].row_stride; 7977ec681f3Smrg 7987ec681f3Smrg cfg.color_block_format = mod_to_block_fmt(rt->image->layout.modifier); 7997ec681f3Smrg assert(cfg.color_block_format == MALI_BLOCK_FORMAT_LINEAR || 8007ec681f3Smrg cfg.color_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED); 8017ec681f3Smrg 8027ec681f3Smrg if (rt->image->layout.crc_mode != PAN_IMAGE_CRC_NONE) { 8037ec681f3Smrg const struct pan_image_slice_layout *slice = 8047ec681f3Smrg &rt->image->layout.slices[level]; 8057ec681f3Smrg 8067ec681f3Smrg cfg.crc_buffer.row_stride = slice->crc.stride; 8077ec681f3Smrg if (rt->image->layout.crc_mode == PAN_IMAGE_CRC_INBAND) { 8087ec681f3Smrg cfg.crc_buffer.base = rt->image->data.bo->ptr.gpu + 8097ec681f3Smrg rt->image->data.offset + 8107ec681f3Smrg slice->crc.offset; 8117ec681f3Smrg } else { 8127ec681f3Smrg cfg.crc_buffer.base = rt->image->crc.bo->ptr.gpu + 8137ec681f3Smrg rt->image->crc.offset + 8147ec681f3Smrg slice->crc.offset; 8157ec681f3Smrg } 8167ec681f3Smrg } 8177ec681f3Smrg } 8187ec681f3Smrg 8197ec681f3Smrg if (fb->zs.view.zs) { 8207ec681f3Smrg const struct pan_image_view *zs = fb->zs.view.zs; 8217ec681f3Smrg unsigned level = zs->first_level; 8227ec681f3Smrg struct pan_surface surf; 8237ec681f3Smrg 8247ec681f3Smrg pan_iview_get_surface(zs, 0, 0, 0, &surf); 8257ec681f3Smrg 8267ec681f3Smrg cfg.zs_write_enable = !fb->zs.discard.z; 8277ec681f3Smrg cfg.zs_writeback.base = surf.data; 8287ec681f3Smrg cfg.zs_writeback.row_stride = 8297ec681f3Smrg zs->image->layout.slices[level].row_stride; 8307ec681f3Smrg cfg.zs_block_format = mod_to_block_fmt(zs->image->layout.modifier); 8317ec681f3Smrg assert(cfg.zs_block_format == MALI_BLOCK_FORMAT_LINEAR || 8327ec681f3Smrg cfg.zs_block_format == MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED); 8337ec681f3Smrg 8347ec681f3Smrg cfg.zs_format = translate_zs_format(zs->format); 8357ec681f3Smrg } 8367ec681f3Smrg 8377ec681f3Smrg cfg.sample_count = fb->nr_samples; 8387ec681f3Smrg 8397ec681f3Smrg if (fb->rt_count) 8407ec681f3Smrg cfg.msaa = mali_sampling_mode(fb->rts[0].view); 8417ec681f3Smrg } 8427ec681f3Smrg pan_emit_sfbd_tiler(dev, fb, tiler_ctx, fbd); 8437ec681f3Smrg pan_section_pack(fbd, FRAMEBUFFER, PADDING_2, padding); 8447ec681f3Smrg} 8457ec681f3Smrg#endif 8467ec681f3Smrg 8477ec681f3Smrgunsigned 8487ec681f3SmrgGENX(pan_emit_fbd)(const struct panfrost_device *dev, 8497ec681f3Smrg const struct pan_fb_info *fb, 8507ec681f3Smrg const struct pan_tls_info *tls, 8517ec681f3Smrg const struct pan_tiler_context *tiler_ctx, 8527ec681f3Smrg void *out) 8537ec681f3Smrg{ 8547ec681f3Smrg#if PAN_ARCH == 4 8557ec681f3Smrg assert(fb->rt_count <= 1); 8567ec681f3Smrg pan_emit_sfbd(dev, fb, tls, tiler_ctx, out); 8577ec681f3Smrg return 0; 8587ec681f3Smrg#else 8597ec681f3Smrg return pan_emit_mfbd(dev, fb, tls, tiler_ctx, out); 8607ec681f3Smrg#endif 8617ec681f3Smrg} 8627ec681f3Smrg 8637ec681f3Smrg#if PAN_ARCH >= 6 8647ec681f3Smrgvoid 8657ec681f3SmrgGENX(pan_emit_tiler_heap)(const struct panfrost_device *dev, 8667ec681f3Smrg void *out) 8677ec681f3Smrg{ 8687ec681f3Smrg pan_pack(out, TILER_HEAP, heap) { 8697ec681f3Smrg heap.size = dev->tiler_heap->size; 8707ec681f3Smrg heap.base = dev->tiler_heap->ptr.gpu; 8717ec681f3Smrg heap.bottom = dev->tiler_heap->ptr.gpu; 8727ec681f3Smrg heap.top = dev->tiler_heap->ptr.gpu + dev->tiler_heap->size; 8737ec681f3Smrg } 8747ec681f3Smrg} 8757ec681f3Smrg 8767ec681f3Smrgvoid 8777ec681f3SmrgGENX(pan_emit_tiler_ctx)(const struct panfrost_device *dev, 8787ec681f3Smrg unsigned fb_width, unsigned fb_height, 8797ec681f3Smrg unsigned nr_samples, 8807ec681f3Smrg mali_ptr heap, 8817ec681f3Smrg void *out) 8827ec681f3Smrg{ 8837ec681f3Smrg unsigned max_levels = dev->tiler_features.max_levels; 8847ec681f3Smrg assert(max_levels >= 2); 8857ec681f3Smrg 8867ec681f3Smrg pan_pack(out, TILER_CONTEXT, tiler) { 8877ec681f3Smrg /* TODO: Select hierarchy mask more effectively */ 8887ec681f3Smrg tiler.hierarchy_mask = (max_levels >= 8) ? 0xFF : 0x28; 8897ec681f3Smrg tiler.fb_width = fb_width; 8907ec681f3Smrg tiler.fb_height = fb_height; 8917ec681f3Smrg tiler.heap = heap; 8927ec681f3Smrg tiler.sample_pattern = pan_sample_pattern(nr_samples); 8937ec681f3Smrg } 8947ec681f3Smrg} 8957ec681f3Smrg#endif 8967ec681f3Smrg 8977ec681f3Smrgvoid 8987ec681f3SmrgGENX(pan_emit_fragment_job)(const struct pan_fb_info *fb, 8997ec681f3Smrg mali_ptr fbd, 9007ec681f3Smrg void *out) 9017ec681f3Smrg{ 9027ec681f3Smrg pan_section_pack(out, FRAGMENT_JOB, HEADER, header) { 9037ec681f3Smrg header.type = MALI_JOB_TYPE_FRAGMENT; 9047ec681f3Smrg header.index = 1; 9057ec681f3Smrg } 9067ec681f3Smrg 9077ec681f3Smrg pan_section_pack(out, FRAGMENT_JOB, PAYLOAD, payload) { 9087ec681f3Smrg payload.bound_min_x = fb->extent.minx >> MALI_TILE_SHIFT; 9097ec681f3Smrg payload.bound_min_y = fb->extent.miny >> MALI_TILE_SHIFT; 9107ec681f3Smrg payload.bound_max_x = fb->extent.maxx >> MALI_TILE_SHIFT; 9117ec681f3Smrg payload.bound_max_y = fb->extent.maxy >> MALI_TILE_SHIFT; 9127ec681f3Smrg payload.framebuffer = fbd; 9137ec681f3Smrg 9147ec681f3Smrg#if PAN_ARCH >= 5 9157ec681f3Smrg if (fb->tile_map.base) { 9167ec681f3Smrg payload.has_tile_enable_map = true; 9177ec681f3Smrg payload.tile_enable_map = fb->tile_map.base; 9187ec681f3Smrg payload.tile_enable_map_row_stride = fb->tile_map.stride; 9197ec681f3Smrg } 9207ec681f3Smrg#endif 9217ec681f3Smrg } 9227ec681f3Smrg} 923