diff --git a/src/freedreno/fdl/freedreno_lrz_layout.h b/src/freedreno/fdl/freedreno_lrz_layout.h index 650e375f765..24915b7ba14 100644 --- a/src/freedreno/fdl/freedreno_lrz_layout.h +++ b/src/freedreno/fdl/freedreno_lrz_layout.h @@ -33,12 +33,13 @@ ENDC; template static void fdl6_lrz_layout_init(struct fdl_lrz_layout *lrz_layout, - struct fdl_layout *layout, + struct fdl_layout *layout, uint32_t extra_width, + uint32_t extra_height, const struct fd_dev_info *dev_info, uint32_t lrz_offset, uint32_t array_layers) { - unsigned width = layout->width0; - unsigned height = layout->height0; + unsigned width = layout->width0 + extra_width; + unsigned height = layout->height0 + extra_height; /* LRZ buffer is super-sampled */ switch (layout->nr_samples) { diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index 28fa02ae5be..26fecd0de86 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -650,6 +650,7 @@ struct tu_bin_size_params { bool force_lrz_write_dis; enum a6xx_buffers_location buffers_location; enum a6xx_lrz_feedback_mask lrz_feedback_zmode_mask; + bool force_lrz_dis; }; template @@ -674,7 +675,8 @@ tu6_emit_bin_size(struct tu_cs *cs, .render_mode = p.render_mode, .force_lrz_write_dis = p.force_lrz_write_dis, .lrz_feedback_zmode_mask = - p.lrz_feedback_zmode_mask, )); + p.lrz_feedback_zmode_mask, + .force_lrz_dis = p.force_lrz_dis)); } tu_cs_emit_regs(cs, RB_CNTL(CHIP, @@ -1270,6 +1272,17 @@ tu6_emit_tile_select(struct tu_cmd_buffer *cmd, views <= MAX_HW_SCALED_VIEWS && !cmd->state.rp.shared_viewport && bin_is_scaled; + /* We cannot support LRZ if we cannot use HW bin scaling and the bin is + * scaled (i.e. less than full resolution) + */ + bool disable_lrz = bin_is_scaled && !bin_scale_en; + + /* We cannot support LRZ for the first row and column because the offset + * required wouldn't be aligned to HW requirements. + */ + if (fdm_offsets && (tile->pos.x == 0 || tile->pos.y == 0)) + disable_lrz = true; + tu6_emit_bin_size( cs, tiling->tile0.width, tiling->tile0.height, { @@ -1277,10 +1290,11 @@ tu6_emit_tile_select(struct tu_cmd_buffer *cmd, .force_lrz_write_dis = !phys_dev->info->a6xx.has_lrz_feedback, .buffers_location = BUFFERS_IN_GMEM, .lrz_feedback_zmode_mask = - phys_dev->info->a6xx.has_lrz_feedback + phys_dev->info->a6xx.has_lrz_feedback && !bin_is_scaled ? (hw_binning ? LRZ_FEEDBACK_EARLY_Z_OR_EARLY_Z_LATE_Z : LRZ_FEEDBACK_EARLY_Z_LATE_Z) : LRZ_FEEDBACK_NONE, + .force_lrz_dis = CHIP >= A7XX && disable_lrz, }); tu_cs_emit_regs(cs, diff --git a/src/freedreno/vulkan/tu_image.cc b/src/freedreno/vulkan/tu_image.cc index 44548feb993..9b98dde0f6b 100644 --- a/src/freedreno/vulkan/tu_image.cc +++ b/src/freedreno/vulkan/tu_image.cc @@ -587,7 +587,24 @@ tu_image_update_layout(struct tu_device *device, struct tu_image *image, const struct util_format_description *desc = util_format_description(image->layout[0].format); if (util_format_has_depth(desc) && device->use_lrz) { + /* If FDM offset is enabled, then the LRZ image will be shifted over. We + * have to overallocate it, but we have no idea how large the tiles it's + * used with will be. Try to calculate the worst-case width and height. + */ + uint32_t extra_width = 0, extra_height = 0; + if (image->vk.create_flags & + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT) { + uint32_t gmem_pixels = + device->physical_device->gmem_size / + (desc->block.bits / 8); + extra_width = gmem_pixels / + device->physical_device->info->tile_align_h; + extra_height = gmem_pixels / + device->physical_device->info->tile_align_w; + } + fdl6_lrz_layout_init(&image->lrz_layout, &image->layout[0], + extra_width, extra_height, device->physical_device->info, image->total_size, image->vk.array_layers); diff --git a/src/freedreno/vulkan/tu_lrz.cc b/src/freedreno/vulkan/tu_lrz.cc index e4d8c1211ab..b466945a2de 100644 --- a/src/freedreno/vulkan/tu_lrz.cc +++ b/src/freedreno/vulkan/tu_lrz.cc @@ -210,6 +210,14 @@ tu_lrz_init_state(struct tu_cmd_buffer *cmd, if (!has_gpu_tracking && !clears_depth) return; + /* Reusing previous state doesn't work with FDM offset because the LRZ + * image is offsetted. + */ + if ((view->image->vk.create_flags & + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT) && + !clears_depth) + return; + /* We need to always have an LRZ view just to disable it if there is a * depth attachment, there are any secondaries, and GPU tracking is * enabled, in order not to rely on loadOp state which doesn't exist with diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc index 88a1682d9cc..2e1aee87d72 100644 --- a/src/freedreno/vulkan/tu_shader.cc +++ b/src/freedreno/vulkan/tu_shader.cc @@ -2840,9 +2840,10 @@ tu_shader_create(struct tu_device *dev, /* FDM isn't compatible with LRZ, because the LRZ image uses the original * resolution and we would need to use the low resolution. * - * TODO: Use a patchpoint to only disable LRZ for scaled bins. + * TODO: Use a patchpoint to only disable LRZ for scaled bins. On a7xx + * we use GRAS_SC_BIN_CNTL::FORCE_LRZ_DIS instead. */ - if (key->fragment_density_map) + if (key->fragment_density_map && dev->physical_device->info->chip < 7) shader->fs.lrz.status = TU_LRZ_FORCE_DISABLE_LRZ; if (!fs->fs.early_fragment_tests && (fs->no_earlyz || fs->writes_stencilref)) { diff --git a/src/gallium/drivers/freedreno/a6xx/fd6_resource.cc b/src/gallium/drivers/freedreno/a6xx/fd6_resource.cc index 815008dbaed..bf1ca27d288 100644 --- a/src/gallium/drivers/freedreno/a6xx/fd6_resource.cc +++ b/src/gallium/drivers/freedreno/a6xx/fd6_resource.cc @@ -243,8 +243,8 @@ setup_lrz(struct fd_resource *rsc) { struct fd_screen *screen = fd_screen(rsc->b.b.screen); uint32_t nr_layers = 1; - fdl6_lrz_layout_init(&rsc->lrz_layout, &rsc->layout, screen->info, 0, - nr_layers); + fdl6_lrz_layout_init(&rsc->lrz_layout, &rsc->layout, 0, 0, + screen->info, 0, nr_layers); rsc->lrz = fd_bo_new(screen->dev, rsc->lrz_layout.lrz_total_size, FD_BO_NOMAP, "lrz");