diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 3f406aacd22..6771eadd8f1 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -3822,6 +3822,12 @@ struct anv_cmd_graphics_state { struct anv_attachment stencil_att; struct anv_state null_surface_state; + /* Bitfield of color attachments disabled by a pipeline (pointing a null + * surface state in the last emitted binding table for the fragment + * stage) + */ + uint8_t disabled_color_atts; + anv_cmd_dirty_mask_t dirty; uint32_t vb_dirty; diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c index be4595431c8..d4f12a7d4cb 100644 --- a/src/intel/vulkan/genX_cmd_buffer.c +++ b/src/intel/vulkan/genX_cmd_buffer.c @@ -5176,15 +5176,24 @@ void genX(CmdBeginRendering)( }; const uint32_t color_att_count = pRenderingInfo->colorAttachmentCount; + result = anv_cmd_buffer_init_attachments(cmd_buffer, color_att_count); if (result != VK_SUCCESS) return; genX(flush_pipeline_select_3d)(cmd_buffer); + UNUSED bool render_target_change = false; for (uint32_t i = 0; i < gfx->color_att_count; i++) { - if (pRenderingInfo->pColorAttachments[i].imageView == VK_NULL_HANDLE) + if (pRenderingInfo->pColorAttachments[i].imageView == VK_NULL_HANDLE) { + render_target_change |= gfx->color_att[i].iview != NULL; + + gfx->color_att[i].vk_format = VK_FORMAT_UNDEFINED; + gfx->color_att[i].iview = NULL; + gfx->color_att[i].layout = VK_IMAGE_LAYOUT_UNDEFINED; + gfx->color_att[i].aux_usage = ISL_AUX_USAGE_NONE; continue; + } const VkRenderingAttachmentInfo *att = &pRenderingInfo->pColorAttachments[i]; @@ -5211,6 +5220,13 @@ void genX(CmdBeginRendering)( att->imageLayout, cmd_buffer->queue_family->queueFlags); + render_target_change |= gfx->color_att[i].iview != iview; + + gfx->color_att[i].vk_format = iview->vk.format; + gfx->color_att[i].iview = iview; + gfx->color_att[i].layout = att->imageLayout; + gfx->color_att[i].aux_usage = aux_usage; + union isl_color_value fast_clear_color = { .u32 = { 0, } }; if (att->loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR && @@ -5325,11 +5341,6 @@ void genX(CmdBeginRendering)( assert(att->imageLayout == initial_layout); } - gfx->color_att[i].vk_format = iview->vk.format; - gfx->color_att[i].iview = iview; - gfx->color_att[i].layout = att->imageLayout; - gfx->color_att[i].aux_usage = aux_usage; - struct isl_view isl_view = iview->planes[0].isl; if (pRenderingInfo->viewMask) { assert(isl_view.array_len >= util_last_bit(pRenderingInfo->viewMask)); @@ -5606,14 +5617,7 @@ void genX(CmdBeginRendering)( gfx->dirty |= ANV_CMD_DIRTY_PIPELINE; #if GFX_VER >= 11 - bool has_color_att = false; - for (uint32_t i = 0; i < gfx->color_att_count; i++) { - if (pRenderingInfo->pColorAttachments[i].imageView != VK_NULL_HANDLE) { - has_color_att = true; - break; - } - } - if (has_color_att) { + if (render_target_change) { /* The PIPE_CONTROL command description says: * * "Whenever a Binding Table Index (BTI) used by a Render Target Message diff --git a/src/intel/vulkan/genX_cmd_draw.c b/src/intel/vulkan/genX_cmd_draw.c index 5f9c7a68621..686f307d8ae 100644 --- a/src/intel/vulkan/genX_cmd_draw.c +++ b/src/intel/vulkan/genX_cmd_draw.c @@ -687,6 +687,60 @@ genX(emit_ds)(struct anv_cmd_buffer *cmd_buffer) #endif } +ALWAYS_INLINE static void +cmd_buffer_maybe_flush_rt_writes(struct anv_cmd_buffer *cmd_buffer, + struct anv_graphics_pipeline *pipeline) +{ +#if GFX_VER >= 11 + if (!anv_pipeline_has_stage(pipeline, MESA_SHADER_FRAGMENT)) + return; + + const struct anv_shader_bin *shader = + pipeline->base.shaders[MESA_SHADER_FRAGMENT]; + const struct anv_pipeline_bind_map *bind_map = &shader->bind_map; + + unsigned s; + uint8_t disabled_mask = 0; + for (s = 0; s < bind_map->surface_count; s++) { + const struct anv_pipeline_binding *binding = + &bind_map->surface_to_descriptor[s]; + + if (binding->set != ANV_DESCRIPTOR_SET_COLOR_ATTACHMENTS) + break; + + if (binding->index >= cmd_buffer->state.gfx.color_att_count) + disabled_mask |= BITFIELD_BIT(s); + } + + const uint8_t diff_mask = (1u << s) - 1; + + if ((cmd_buffer->state.gfx.disabled_color_atts & diff_mask) != disabled_mask) { + cmd_buffer->state.gfx.disabled_color_atts = disabled_mask | + (cmd_buffer->state.gfx.disabled_color_atts & ~diff_mask); + + /* The PIPE_CONTROL command description says: + * + * "Whenever a Binding Table Index (BTI) used by a Render Target Message + * points to a different RENDER_SURFACE_STATE, SW must issue a Render + * Target Cache Flush by enabling this bit. When render target flush + * is set due to new association of BTI, PS Scoreboard Stall bit must + * be set in this packet." + * + * Within a renderpass, the render target entries in the binding tables + * remain the same as what was setup at CmdBeginRendering() with one + * exception where have to setup a null render target because a fragment + * writes only depth/stencil yet the renderpass has been setup with at + * least one color attachment. This is because our render target messages + * in the shader always send the color. + */ + anv_add_pending_pipe_bits(cmd_buffer, + ANV_PIPE_RENDER_TARGET_CACHE_FLUSH_BIT | + ANV_PIPE_STALL_AT_SCOREBOARD_BIT, + "change RT due to shader outputs"); + } +#endif +} + ALWAYS_INLINE static void genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer) { @@ -708,16 +762,18 @@ genX(cmd_buffer_flush_gfx_state)(struct anv_cmd_buffer *cmd_buffer) genX(flush_pipeline_select_3d)(cmd_buffer); - /* Wa_14015814527 - * - * Apply task URB workaround when switching from task to primitive. - */ if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_PIPELINE) { + /* Wa_14015814527 + * + * Apply task URB workaround when switching from task to primitive. + */ if (anv_pipeline_is_primitive(pipeline)) { genX(apply_task_urb_workaround)(cmd_buffer); } else if (anv_pipeline_has_stage(pipeline, MESA_SHADER_TASK)) { cmd_buffer->state.gfx.used_task_shader = true; } + + cmd_buffer_maybe_flush_rt_writes(cmd_buffer, pipeline); } /* Apply any pending pipeline flushes we may have. We want to apply them