diff --git a/src/freedreno/vulkan/tu_cmd_buffer.c b/src/freedreno/vulkan/tu_cmd_buffer.c index a56c0296e19..5196191fd41 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.c +++ b/src/freedreno/vulkan/tu_cmd_buffer.c @@ -1772,13 +1772,11 @@ tu_BeginCommandBuffer(VkCommandBuffer commandBuffer, } if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) { - TU_FROM_HANDLE(tu_framebuffer, fb, pBeginInfo->pInheritanceInfo->framebuffer); - cmd_buffer->state.pass = tu_render_pass_from_handle(pBeginInfo->pInheritanceInfo->renderPass); cmd_buffer->state.subpass = &cmd_buffer->state.pass->subpasses[pBeginInfo->pInheritanceInfo->subpass]; - tu_lrz_begin_secondary_cmdbuf(cmd_buffer, fb); + tu_lrz_begin_secondary_cmdbuf(cmd_buffer); } else { /* When executing in the middle of another command buffer, the CCU * state is unknown. diff --git a/src/freedreno/vulkan/tu_lrz.c b/src/freedreno/vulkan/tu_lrz.c index 9f372064bac..d820823f0d8 100644 --- a/src/freedreno/vulkan/tu_lrz.c +++ b/src/freedreno/vulkan/tu_lrz.c @@ -202,8 +202,11 @@ tu_lrz_init_state(struct tu_cmd_buffer *cmd, const struct tu_render_pass_attachment *att, const struct tu_image_view *view) { - if (!view->image->lrz_height) + if (!view->image->lrz_height) { + assert((cmd->device->instance->debug_flags & TU_DEBUG_NOLRZ) || + !vk_format_has_depth(att->format)); return; + } bool clears_depth = att->clear_mask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT); @@ -213,10 +216,17 @@ tu_lrz_init_state(struct tu_cmd_buffer *cmd, if (!has_gpu_tracking && !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 + * dynamic rendering in secondaries. Otherwise the secondary will have LRZ + * enabled and there will be a NULL/garbage LRZ buffer. + */ + cmd->state.lrz.image_view = view; + if (!clears_depth && !att->load) return; - cmd->state.lrz.image_view = view; cmd->state.lrz.valid = true; cmd->state.lrz.prev_direction = TU_LRZ_UNKNOWN; /* Be optimistic and unconditionally enable fast-clear in @@ -228,6 +238,43 @@ tu_lrz_init_state(struct tu_cmd_buffer *cmd, cmd->state.lrz.reuse_previous_state = !clears_depth; } +/* Note: if we enable LRZ here, then tu_lrz_init_state() must at least set + * lrz.image_view, so that an LRZ buffer is present (even if LRZ is + * dynamically disabled). + */ + +static void +tu_lrz_init_secondary(struct tu_cmd_buffer *cmd, + const struct tu_render_pass_attachment *att) +{ + bool has_gpu_tracking = + cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking; + + if (!has_gpu_tracking) + return; + + if (cmd->device->instance->debug_flags & TU_DEBUG_NOLRZ) + return; + + if (!vk_format_has_depth(att->format)) + return; + + cmd->state.lrz.valid = true; + cmd->state.lrz.prev_direction = TU_LRZ_UNKNOWN; + cmd->state.lrz.gpu_dir_tracking = has_gpu_tracking; + + /* We may not have the depth attachment when executing in a secondary + * inside a render pass. This means we have to be even more optimistic than + * the normal case and enable fast clear even if the depth image doesn't + * support it. + */ + cmd->state.lrz.fast_clear = true; + + /* These are not used inside secondaries */ + cmd->state.lrz.image_view = NULL; + cmd->state.lrz.reuse_previous_state = false; +} + void tu_lrz_begin_renderpass(struct tu_cmd_buffer *cmd, const VkRenderPassBeginInfo *pRenderPassBegin) @@ -257,7 +304,7 @@ tu_lrz_begin_renderpass(struct tu_cmd_buffer *cmd, } /* Track LRZ valid state */ - cmd->state.lrz.valid = false; + memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz)); uint32_t a = cmd->state.subpass->depth_stencil_attachment.attachment; if (a != VK_ATTACHMENT_UNUSED) { const struct tu_render_pass_attachment *att = &cmd->state.pass->attachments[a]; @@ -273,28 +320,29 @@ tu_lrz_begin_renderpass(struct tu_cmd_buffer *cmd, } if (!cmd->state.lrz.valid) { - memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz)); tu6_emit_lrz_buffer(&cmd->cs, NULL); } } void -tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer *cmd, - struct tu_framebuffer *fb) +tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer *cmd) { + memset(&cmd->state.lrz, 0, sizeof(cmd->state.lrz)); uint32_t a = cmd->state.subpass->depth_stencil_attachment.attachment; - if (a != VK_ATTACHMENT_UNUSED && - cmd->device->physical_device->info->a6xx.has_lrz_dir_tracking) { + if (a != VK_ATTACHMENT_UNUSED) { const struct tu_render_pass_attachment *att = &cmd->state.pass->attachments[a]; - struct tu_image_view *view = fb->attachments[a].attachment; - - tu_lrz_init_state(cmd, att, view); + tu_lrz_init_secondary(cmd, att); } } void tu_lrz_tiling_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs) { + /* TODO: If lrz was never valid for the entire renderpass, we could exit + * early here. Sometimes we know this ahead of time and null out + * image_view, but with LOAD_OP_DONT_CARE this only happens if there were + * no secondaries. + */ if (!cmd->state.lrz.image_view) return; diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 439c12dc8d2..d605268095b 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -1591,8 +1591,7 @@ tu_lrz_begin_renderpass(struct tu_cmd_buffer *cmd, const VkRenderPassBeginInfo *pRenderPassBegin); void -tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer *cmd, - struct tu_framebuffer *fb); +tu_lrz_begin_secondary_cmdbuf(struct tu_cmd_buffer *cmd); void tu_lrz_tiling_begin(struct tu_cmd_buffer *cmd, struct tu_cs *cs);