| /* |
| * Copyright 2018-2019 Alyssa Rosenzweig |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| */ |
| |
| #include "pan_bo.h" |
| #include "pan_context.h" |
| #include "pan_cmdstream.h" |
| #include "pan_util.h" |
| #include "panfrost-quirks.h" |
| |
| |
| static bool |
| panfrost_mfbd_has_zs_crc_ext(struct panfrost_batch *batch) |
| { |
| if (batch->key.nr_cbufs == 1) { |
| struct pipe_surface *surf = batch->key.cbufs[0]; |
| struct panfrost_resource *rsrc = pan_resource(surf->texture); |
| |
| if (rsrc->checksummed) |
| return true; |
| } |
| |
| if (batch->key.zsbuf && |
| ((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) |
| return true; |
| |
| return false; |
| } |
| |
| static unsigned |
| panfrost_mfbd_size(struct panfrost_batch *batch) |
| { |
| unsigned rt_count = MAX2(batch->key.nr_cbufs, 1); |
| |
| return MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH + |
| (panfrost_mfbd_has_zs_crc_ext(batch) * MALI_ZS_CRC_EXTENSION_LENGTH) + |
| (rt_count * MALI_RENDER_TARGET_LENGTH); |
| } |
| |
| static void |
| panfrost_mfbd_rt_init_format(struct pipe_surface *surf, |
| struct MALI_RENDER_TARGET *rt) |
| { |
| /* Explode details on the format */ |
| |
| const struct util_format_description *desc = |
| util_format_description(surf->format); |
| |
| /* The swizzle for rendering is inverted from texturing */ |
| |
| unsigned char swizzle[4]; |
| panfrost_invert_swizzle(desc->swizzle, swizzle); |
| |
| rt->swizzle = panfrost_translate_swizzle_4(swizzle); |
| |
| /* Fill in accordingly, defaulting to 8-bit UNORM */ |
| |
| if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) |
| rt->srgb = true; |
| |
| /* sRGB handled as a dedicated flag */ |
| enum pipe_format linearized = util_format_linear(surf->format); |
| |
| if (util_format_is_unorm8(desc)) { |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8; |
| switch (desc->nr_channels) { |
| case 1: |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R8; |
| break; |
| case 2: |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R8G8; |
| break; |
| case 3: |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R8G8B8; |
| break; |
| case 4: |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R8G8B8A8; |
| break; |
| default: |
| unreachable("Invalid number of channels"); |
| } |
| |
| /* If RGB, we're good to go */ |
| return; |
| } |
| |
| /* Set flags for alternative formats */ |
| |
| switch (linearized) { |
| case PIPE_FORMAT_B5G6R5_UNORM: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R5G6B5A0; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R5G6B5; |
| break; |
| |
| case PIPE_FORMAT_A4B4G4R4_UNORM: |
| case PIPE_FORMAT_B4G4R4A4_UNORM: |
| case PIPE_FORMAT_R4G4B4A4_UNORM: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R4G4B4A4; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R4G4B4A4; |
| break; |
| |
| case PIPE_FORMAT_R10G10B10A2_UNORM: |
| case PIPE_FORMAT_B10G10R10A2_UNORM: |
| case PIPE_FORMAT_R10G10B10X2_UNORM: |
| case PIPE_FORMAT_B10G10R10X2_UNORM: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R10G10B10A2; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R10G10B10A2; |
| break; |
| |
| case PIPE_FORMAT_B5G5R5A1_UNORM: |
| case PIPE_FORMAT_R5G5B5A1_UNORM: |
| case PIPE_FORMAT_B5G5R5X1_UNORM: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R5G5B5A1; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_R5G5B5A1; |
| break; |
| |
| /* Generic 8-bit */ |
| case PIPE_FORMAT_R8_UINT: |
| case PIPE_FORMAT_R8_SINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW8; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW8; |
| break; |
| |
| /* Generic 32-bit */ |
| case PIPE_FORMAT_R11G11B10_FLOAT: |
| case PIPE_FORMAT_R8G8B8A8_UINT: |
| case PIPE_FORMAT_R8G8B8A8_SINT: |
| case PIPE_FORMAT_R16G16_FLOAT: |
| case PIPE_FORMAT_R16G16_UINT: |
| case PIPE_FORMAT_R16G16_SINT: |
| case PIPE_FORMAT_R32_FLOAT: |
| case PIPE_FORMAT_R32_UINT: |
| case PIPE_FORMAT_R32_SINT: |
| case PIPE_FORMAT_R10G10B10A2_UINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW32; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW32; |
| break; |
| |
| /* Generic 16-bit */ |
| case PIPE_FORMAT_R8G8_UINT: |
| case PIPE_FORMAT_R8G8_SINT: |
| case PIPE_FORMAT_R16_FLOAT: |
| case PIPE_FORMAT_R16_UINT: |
| case PIPE_FORMAT_R16_SINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW16; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW16; |
| break; |
| |
| /* Generic 64-bit */ |
| case PIPE_FORMAT_R32G32_FLOAT: |
| case PIPE_FORMAT_R32G32_SINT: |
| case PIPE_FORMAT_R32G32_UINT: |
| case PIPE_FORMAT_R16G16B16A16_FLOAT: |
| case PIPE_FORMAT_R16G16B16A16_SINT: |
| case PIPE_FORMAT_R16G16B16A16_UINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW64; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW64; |
| break; |
| |
| case PIPE_FORMAT_R16G16B16_FLOAT: |
| case PIPE_FORMAT_R16G16B16_SINT: |
| case PIPE_FORMAT_R16G16B16_UINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW64; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW48; |
| break; |
| |
| /* Generic 128-bit */ |
| case PIPE_FORMAT_R32G32B32A32_FLOAT: |
| case PIPE_FORMAT_R32G32B32A32_SINT: |
| case PIPE_FORMAT_R32G32B32A32_UINT: |
| rt->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_RAW128; |
| rt->writeback_format = MALI_MFBD_COLOR_FORMAT_RAW128; |
| break; |
| |
| default: |
| unreachable("Invalid format rendering"); |
| } |
| } |
| |
| static void |
| panfrost_mfbd_rt_set_buf(struct pipe_surface *surf, |
| struct MALI_RENDER_TARGET *rt) |
| { |
| struct panfrost_device *dev = pan_device(surf->context->screen); |
| unsigned version = dev->gpu_id >> 12; |
| struct panfrost_resource *rsrc = pan_resource(surf->texture); |
| unsigned level = surf->u.tex.level; |
| unsigned first_layer = surf->u.tex.first_layer; |
| assert(surf->u.tex.last_layer == first_layer); |
| int stride = rsrc->slices[level].stride; |
| |
| /* Only set layer_stride for layered MSAA rendering */ |
| |
| unsigned nr_samples = surf->texture->nr_samples; |
| unsigned layer_stride = (nr_samples > 1) ? rsrc->slices[level].size0 : 0; |
| mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0); |
| |
| if (layer_stride) |
| rt->writeback_msaa = MALI_MSAA_LAYERED; |
| else if (surf->nr_samples) |
| rt->writeback_msaa = MALI_MSAA_AVERAGE; |
| else |
| rt->writeback_msaa = MALI_MSAA_SINGLE; |
| |
| panfrost_mfbd_rt_init_format(surf, rt); |
| |
| if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) { |
| if (version >= 7) |
| rt->writeback_block_format_v7 = MALI_BLOCK_FORMAT_V7_LINEAR; |
| else |
| rt->writeback_block_format = MALI_BLOCK_FORMAT_LINEAR; |
| |
| rt->writeback_base = base; |
| rt->writeback_row_stride = stride; |
| rt->writeback_surface_stride = layer_stride; |
| } else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) { |
| if (version >= 7) |
| rt->writeback_block_format_v7 = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED; |
| else |
| rt->writeback_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED; |
| |
| rt->writeback_base = base; |
| rt->writeback_row_stride = stride * 16; |
| rt->writeback_surface_stride = layer_stride; |
| } else if (drm_is_afbc(rsrc->modifier)) { |
| if (version >= 7) |
| rt->writeback_block_format = MALI_BLOCK_FORMAT_V7_AFBC; |
| else |
| rt->writeback_block_format = MALI_BLOCK_FORMAT_AFBC; |
| |
| unsigned header_size = rsrc->slices[level].header_size; |
| |
| rt->afbc_header = base; |
| rt->afbc_chunk_size = 9; |
| rt->afbc_sparse = true; |
| rt->afbc_body = base + header_size; |
| rt->writeback_surface_stride = layer_stride; |
| |
| if (rsrc->modifier & AFBC_FORMAT_MOD_YTR) |
| rt->afbc_yuv_transform_enable = true; |
| |
| /* TODO: The blob sets this to something nonzero, but it's not |
| * clear what/how to calculate/if it matters */ |
| rt->afbc_body_size = 0; |
| } else { |
| unreachable("Invalid mod"); |
| } |
| } |
| |
| static void |
| panfrost_mfbd_emit_rt(struct panfrost_batch *batch, |
| void *rtp, struct pipe_surface *surf, |
| unsigned rt_offset, unsigned rt_idx) |
| { |
| struct panfrost_device *dev = pan_device(batch->ctx->base.screen); |
| unsigned version = dev->gpu_id >> 12; |
| |
| pan_pack(rtp, RENDER_TARGET, rt) { |
| rt.clean_pixel_write_enable = true; |
| if (surf) { |
| rt.write_enable = true; |
| rt.dithering_enable = true; |
| rt.internal_buffer_offset = rt_offset; |
| panfrost_mfbd_rt_set_buf(surf, &rt); |
| } else { |
| rt.internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8; |
| rt.internal_buffer_offset = rt_offset; |
| if (version >= 7) { |
| rt.writeback_block_format_v7 = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED; |
| rt.dithering_enable = true; |
| } |
| } |
| |
| if (batch->clear & (PIPE_CLEAR_COLOR0 << rt_idx)) { |
| rt.clear_color_0 = batch->clear_color[rt_idx][0]; |
| rt.clear_color_1 = batch->clear_color[rt_idx][1]; |
| rt.clear_color_2 = batch->clear_color[rt_idx][2]; |
| rt.clear_color_3 = batch->clear_color[rt_idx][3]; |
| } |
| } |
| } |
| |
| static enum mali_z_internal_format |
| get_z_internal_format(struct panfrost_batch *batch) |
| { |
| struct pipe_surface *zs_surf = batch->key.zsbuf; |
| |
| /* Default to 24 bit depth if there's no surface. */ |
| if (!zs_surf || !((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) |
| return MALI_Z_INTERNAL_FORMAT_D24; |
| |
| return panfrost_get_z_internal_format(zs_surf->format); |
| } |
| |
| static void |
| panfrost_mfbd_zs_crc_ext_set_bufs(struct panfrost_batch *batch, |
| struct MALI_ZS_CRC_EXTENSION *ext) |
| { |
| struct panfrost_device *dev = pan_device(batch->ctx->base.screen); |
| unsigned version = dev->gpu_id >> 12; |
| |
| /* Checksumming only works with a single render target */ |
| if (batch->key.nr_cbufs == 1) { |
| struct pipe_surface *c_surf = batch->key.cbufs[0]; |
| struct panfrost_resource *rsrc = pan_resource(c_surf->texture); |
| |
| if (rsrc->checksummed) { |
| unsigned level = c_surf->u.tex.level; |
| struct panfrost_slice *slice = &rsrc->slices[level]; |
| |
| ext->crc_row_stride = slice->checksum_stride; |
| if (slice->checksum_bo) |
| ext->crc_base = slice->checksum_bo->gpu; |
| else |
| ext->crc_base = rsrc->bo->gpu + slice->checksum_offset; |
| |
| if ((batch->clear & PIPE_CLEAR_COLOR0) && version >= 7) { |
| ext->crc_clear_color = batch->clear_color[0][0] | |
| 0xc000000000000000 | |
| ((uint64_t)batch->clear_color[0][0] & 0xffff) << 32; |
| } |
| } |
| } |
| |
| struct pipe_surface *zs_surf = batch->key.zsbuf; |
| |
| if (!((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) |
| zs_surf = NULL; |
| |
| if (!zs_surf) |
| return; |
| |
| struct panfrost_resource *rsrc = pan_resource(zs_surf->texture); |
| unsigned nr_samples = MAX2(zs_surf->texture->nr_samples, 1); |
| unsigned level = zs_surf->u.tex.level; |
| unsigned first_layer = zs_surf->u.tex.first_layer; |
| assert(zs_surf->u.tex.last_layer == first_layer); |
| |
| mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0); |
| |
| ext->zs_msaa = nr_samples > 1 ? MALI_MSAA_LAYERED : MALI_MSAA_SINGLE; |
| |
| if (drm_is_afbc(rsrc->modifier)) { |
| /* The only Z/S format we can compress is Z24S8 or variants |
| * thereof (handled by the gallium frontend) */ |
| assert(panfrost_is_z24s8_variant(zs_surf->format)); |
| |
| unsigned header_size = rsrc->slices[level].header_size; |
| |
| ext->zs_write_format = MALI_ZS_FORMAT_D24S8; |
| if (version >= 7) |
| ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_AFBC; |
| else |
| ext->zs_block_format = MALI_BLOCK_FORMAT_AFBC; |
| |
| ext->zs_afbc_header = base; |
| ext->zs_afbc_body = base + header_size; |
| ext->zs_afbc_body_size = 0x1000; |
| ext->zs_afbc_chunk_size = 9; |
| ext->zs_afbc_sparse = true; |
| } else { |
| assert(rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED || |
| rsrc->modifier == DRM_FORMAT_MOD_LINEAR); |
| /* TODO: Z32F(S8) support, which is always linear */ |
| |
| int stride = rsrc->slices[level].stride; |
| |
| unsigned layer_stride = (nr_samples > 1) ? rsrc->slices[level].size0 : 0; |
| |
| ext->zs_writeback_base = base; |
| ext->zs_writeback_row_stride = stride; |
| ext->zs_writeback_surface_stride = layer_stride; |
| |
| if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) { |
| if (version >= 7) |
| ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_LINEAR; |
| else |
| ext->zs_block_format = MALI_BLOCK_FORMAT_LINEAR; |
| } else { |
| ext->zs_writeback_row_stride *= 16; |
| if (version >= 7) |
| ext->zs_block_format_v7 = MALI_BLOCK_FORMAT_V7_TILED_U_INTERLEAVED; |
| else |
| ext->zs_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED; |
| } |
| |
| switch (zs_surf->format) { |
| case PIPE_FORMAT_Z24_UNORM_S8_UINT: |
| ext->zs_write_format = MALI_ZS_FORMAT_D24S8; |
| break; |
| case PIPE_FORMAT_Z24X8_UNORM: |
| ext->zs_write_format = MALI_ZS_FORMAT_D24X8; |
| break; |
| case PIPE_FORMAT_Z32_FLOAT: |
| ext->zs_write_format = MALI_ZS_FORMAT_D32; |
| break; |
| case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: |
| /* Midgard/Bifrost support interleaved depth/stencil |
| * buffers, but we always treat them as multu-planar. |
| */ |
| ext->zs_write_format = MALI_ZS_FORMAT_D32; |
| ext->s_write_format = MALI_S_FORMAT_S8; |
| |
| struct panfrost_resource *stencil = rsrc->separate_stencil; |
| struct panfrost_slice stencil_slice = stencil->slices[level]; |
| unsigned stencil_layer_stride = (nr_samples > 1) ? stencil_slice.size0 : 0; |
| |
| ext->s_writeback_base = panfrost_get_texture_address(stencil, level, first_layer, 0); |
| ext->s_writeback_row_stride = stencil_slice.stride; |
| if (rsrc->modifier != DRM_FORMAT_MOD_LINEAR) |
| ext->s_writeback_row_stride *= 16; |
| ext->s_writeback_surface_stride = stencil_layer_stride; |
| break; |
| default: |
| unreachable("Unsupported depth/stencil format."); |
| } |
| } |
| } |
| |
| static void |
| panfrost_mfbd_emit_zs_crc_ext(struct panfrost_batch *batch, void *extp) |
| { |
| pan_pack(extp, ZS_CRC_EXTENSION, ext) { |
| ext.zs_clean_pixel_write_enable = true; |
| panfrost_mfbd_zs_crc_ext_set_bufs(batch, &ext); |
| } |
| } |
| |
| /* Determines the # of bytes per pixel we need to reserve for a given format in |
| * the tilebuffer (compared to 128-bit budget, etc). Usually the same as the |
| * bytes per pixel of the format itself, but there are some special cases I |
| * don't understand. */ |
| |
| static unsigned |
| pan_bytes_per_pixel_tib(enum pipe_format format) |
| { |
| const struct util_format_description *desc = |
| util_format_description(format); |
| |
| if (util_format_is_unorm8(desc) || format == PIPE_FORMAT_B5G6R5_UNORM) |
| return 4; |
| |
| return desc->block.bits / 8; |
| } |
| |
| /* Calculates the internal color buffer size and tile size based on the number |
| * of RT, the format and the number of pixels. If things do not fit in 4KB, we |
| * shrink the tile size to make it fit. |
| */ |
| |
| static unsigned |
| pan_internal_cbuf_size(struct panfrost_batch *batch, unsigned *tile_size) |
| { |
| unsigned total_size = 0; |
| |
| *tile_size = 16 * 16; |
| for (int cb = 0; cb < batch->key.nr_cbufs; ++cb) { |
| struct pipe_surface *surf = batch->key.cbufs[cb]; |
| assert(surf); |
| |
| unsigned nr_samples = MAX3(surf->nr_samples, surf->texture->nr_samples, 1); |
| total_size += pan_bytes_per_pixel_tib(surf->format) * |
| nr_samples * (*tile_size); |
| } |
| |
| /* We have a 4KB budget, let's reduce the tile size until it fits. */ |
| while (total_size > 4096) { |
| total_size >>= 1; |
| *tile_size >>= 1; |
| } |
| |
| /* Align on 1k. */ |
| total_size = ALIGN_POT(total_size, 1024); |
| |
| /* Minimum tile size is 4x4. */ |
| assert(*tile_size > 4 * 4); |
| return total_size; |
| } |
| |
| static void |
| panfrost_mfbd_emit_local_storage(struct panfrost_batch *batch, void *fb) |
| { |
| struct panfrost_device *dev = pan_device(batch->ctx->base.screen); |
| |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, LOCAL_STORAGE, ls) { |
| if (batch->stack_size) { |
| unsigned shift = |
| panfrost_get_stack_shift(batch->stack_size); |
| struct panfrost_bo *bo = |
| panfrost_batch_get_scratchpad(batch, |
| batch->stack_size, |
| dev->thread_tls_alloc, |
| dev->core_count); |
| ls.tls_size = shift; |
| ls.tls_base_pointer = bo->gpu; |
| } |
| |
| ls.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM; |
| } |
| } |
| |
| static void |
| panfrost_mfbd_emit_midgard_tiler(struct panfrost_batch *batch, void *fb, |
| unsigned vertex_count) |
| { |
| void *t = pan_section_ptr(fb, MULTI_TARGET_FRAMEBUFFER, TILER); |
| |
| panfrost_emit_midg_tiler(batch, t, vertex_count); |
| |
| /* All weights set to 0, nothing to do here */ |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w); |
| } |
| |
| static void |
| panfrost_mfbd_emit_bifrost_parameters(struct panfrost_batch *batch, void *fb) |
| { |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_PARAMETERS, params) { |
| params.sample_locations = panfrost_emit_sample_locations(batch); |
| } |
| } |
| |
| static void |
| panfrost_mfbd_emit_bifrost_tiler(struct panfrost_batch *batch, void *fb, |
| unsigned vertex_count) |
| { |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_TILER_POINTER, tiler) { |
| tiler.address = panfrost_batch_get_bifrost_tiler(batch, vertex_count); |
| } |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, BIFROST_PADDING, padding); |
| } |
| |
| void |
| panfrost_attach_mfbd(struct panfrost_batch *batch, unsigned vertex_count) |
| { |
| struct panfrost_device *dev = pan_device(batch->ctx->base.screen); |
| void *fb = batch->framebuffer.cpu; |
| |
| if (dev->quirks & IS_BIFROST) |
| panfrost_mfbd_emit_bifrost_parameters(batch, fb); |
| else |
| panfrost_mfbd_emit_local_storage(batch, fb); |
| |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, PARAMETERS, params) { |
| params.width = batch->key.width; |
| params.height = batch->key.height; |
| params.bound_max_x = batch->key.width - 1; |
| params.bound_max_y = batch->key.height - 1; |
| params.color_buffer_allocation = |
| pan_internal_cbuf_size(batch, ¶ms.effective_tile_size); |
| params.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT; |
| params.render_target_count = MAX2(batch->key.nr_cbufs, 1); |
| } |
| |
| if (dev->quirks & IS_BIFROST) |
| panfrost_mfbd_emit_bifrost_tiler(batch, fb, vertex_count); |
| else |
| panfrost_mfbd_emit_midgard_tiler(batch, fb, vertex_count); |
| } |
| |
| /* Creates an MFBD for the FRAGMENT section of the bound framebuffer */ |
| |
| mali_ptr |
| panfrost_mfbd_fragment(struct panfrost_batch *batch, bool has_draws) |
| { |
| struct panfrost_device *dev = pan_device(batch->ctx->base.screen); |
| unsigned vertex_count = has_draws; |
| struct panfrost_transfer t = |
| panfrost_pool_alloc_aligned(&batch->pool, |
| panfrost_mfbd_size(batch), 64); |
| void *fb = t.cpu, *zs_crc_ext, *rts; |
| |
| if (panfrost_mfbd_has_zs_crc_ext(batch)) { |
| zs_crc_ext = fb + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH; |
| rts = zs_crc_ext + MALI_ZS_CRC_EXTENSION_LENGTH; |
| } else { |
| zs_crc_ext = NULL; |
| rts = fb + MALI_MULTI_TARGET_FRAMEBUFFER_LENGTH; |
| } |
| |
| /* When scanning out, the depth buffer is immediately invalidated, so |
| * we don't need to waste bandwidth writing it out. This can improve |
| * performance substantially (Z24X8_UNORM 1080p @ 60fps is 475 MB/s of |
| * memory bandwidth!). |
| * |
| * The exception is ReadPixels, but this is not supported on GLES so we |
| * can safely ignore it. */ |
| |
| if (panfrost_batch_is_scanout(batch)) |
| batch->requirements &= ~PAN_REQ_DEPTH_WRITE; |
| |
| if (zs_crc_ext) { |
| if (batch->key.zsbuf && |
| MAX2(batch->key.zsbuf->nr_samples, batch->key.zsbuf->nr_samples) > 1) |
| batch->requirements |= PAN_REQ_MSAA; |
| |
| panfrost_mfbd_emit_zs_crc_ext(batch, zs_crc_ext); |
| } |
| |
| /* We always upload at least one dummy GL_NONE render target */ |
| |
| unsigned rt_descriptors = MAX2(batch->key.nr_cbufs, 1); |
| |
| /* Upload either the render target or a dummy GL_NONE target */ |
| |
| unsigned rt_offset = 0, tib_size; |
| unsigned internal_cbuf_size = pan_internal_cbuf_size(batch, &tib_size); |
| |
| for (int cb = 0; cb < rt_descriptors; ++cb) { |
| struct pipe_surface *surf = batch->key.cbufs[cb]; |
| void *rt = rts + (cb * MALI_RENDER_TARGET_LENGTH); |
| |
| if (!((batch->clear | batch->draws) & (PIPE_CLEAR_COLOR0 << cb))) |
| surf = NULL; |
| |
| panfrost_mfbd_emit_rt(batch, rt, surf, rt_offset, cb); |
| |
| if (surf) { |
| if (MAX2(surf->nr_samples, surf->texture->nr_samples) > 1) |
| batch->requirements |= PAN_REQ_MSAA; |
| |
| rt_offset += pan_bytes_per_pixel_tib(surf->format) * tib_size; |
| } |
| } |
| |
| if (dev->quirks & IS_BIFROST) |
| panfrost_mfbd_emit_bifrost_parameters(batch, fb); |
| else |
| panfrost_mfbd_emit_local_storage(batch, fb); |
| |
| pan_section_pack(fb, MULTI_TARGET_FRAMEBUFFER, PARAMETERS, params) { |
| params.width = batch->key.width; |
| params.height = batch->key.height; |
| params.bound_max_x = batch->key.width - 1; |
| params.bound_max_y = batch->key.height - 1; |
| params.effective_tile_size = tib_size; |
| params.tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT; |
| params.render_target_count = rt_descriptors; |
| params.z_internal_format = get_z_internal_format(batch); |
| |
| if (batch->clear & PIPE_CLEAR_DEPTH) |
| params.z_clear = batch->clear_depth; |
| if (batch->clear & PIPE_CLEAR_STENCIL) |
| params.s_clear = batch->clear_stencil & 0xff; |
| |
| params.color_buffer_allocation = internal_cbuf_size; |
| |
| if (batch->requirements & PAN_REQ_MSAA) { |
| /* MSAA 4x */ |
| params.sample_count = 4; |
| params.sample_pattern = MALI_SAMPLE_PATTERN_ROTATED_4X_GRID; |
| } |
| |
| if (batch->key.zsbuf && |
| ((batch->clear | batch->draws) & PIPE_CLEAR_DEPTHSTENCIL)) { |
| params.z_write_enable = true; |
| if (batch->key.zsbuf->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) |
| params.s_write_enable = true; |
| } |
| |
| params.has_zs_crc_extension = !!zs_crc_ext; |
| } |
| |
| if (dev->quirks & IS_BIFROST) |
| panfrost_mfbd_emit_bifrost_tiler(batch, fb, vertex_count); |
| else |
| panfrost_mfbd_emit_midgard_tiler(batch, fb, vertex_count); |
| |
| /* Return pointer suitable for the fragment section */ |
| unsigned tag = |
| MALI_FBD_TAG_IS_MFBD | |
| (zs_crc_ext ? MALI_FBD_TAG_HAS_ZS_RT : 0) | |
| (MALI_POSITIVE(rt_descriptors) << 2); |
| |
| return t.gpu | tag; |
| } |