From 244995e4af1923aa955df8a1adb94b0e16035517 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 24 Jan 2025 11:23:36 +0100 Subject: [PATCH] panvk: Support color attachment remapping We take the color attachment remapping into account when emitting blend descriptors, and we make sure we re-emit those when this color attachment map is dirty. We also need to take the remapping into account when checking the render targets written by the fragment shader, hence the addition of a color_attachment_written_mask() helper. Signed-off-by: Boris Brezillon Reviewed-by: Lars-Ivar Hesselberg Simonsen Part-of: --- src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c | 9 ++-- src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c | 7 +-- src/panfrost/vulkan/panvk_blend.h | 4 ++ src/panfrost/vulkan/panvk_cmd_draw.h | 22 +++++++++ src/panfrost/vulkan/panvk_vX_blend.c | 52 ++++++++++++++++----- 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c index a720f17c4aa..a6930b598b9 100644 --- a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c +++ b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c @@ -441,15 +441,13 @@ prepare_blend(struct panvk_cmd_buffer *cmdbuf) dyn_gfx_state_dirty(cmdbuf, CB_BLEND_EQUATIONS) || dyn_gfx_state_dirty(cmdbuf, CB_WRITE_MASKS) || dyn_gfx_state_dirty(cmdbuf, CB_BLEND_CONSTANTS) || + dyn_gfx_state_dirty(cmdbuf, COLOR_ATTACHMENT_MAP) || fs_user_dirty(cmdbuf) || gfx_state_dirty(cmdbuf, RENDER_STATE); if (!dirty) return VK_SUCCESS; - const struct vk_dynamic_graphics_state *dyns = - &cmdbuf->vk.dynamic_graphics_state; - const struct vk_color_blend_state *cb = &dyns->cb; - unsigned bd_count = MAX2(cb->attachment_count, 1); + uint32_t bd_count = MAX2(cmdbuf->state.gfx.render.fb.info.rt_count, 1); struct cs_builder *b = panvk_get_cs_builder(cmdbuf, PANVK_SUBQUEUE_VERTEX_TILER); struct panfrost_ptr ptr = @@ -1519,7 +1517,8 @@ prepare_dcd(struct panvk_cmd_buffer *cmdbuf) struct mali_dcd_flags_0_packed dcd0; pan_pack(&dcd0, DCD_FLAGS_0, cfg) { if (fs) { - uint8_t rt_written = fs->info.outputs_written >> FRAG_RESULT_DATA0; + uint8_t rt_written = color_attachment_written_mask( + fs, &cmdbuf->vk.dynamic_graphics_state.cal); uint8_t rt_mask = cmdbuf->state.gfx.render.bound_attachments & MESA_VK_RP_ATTACHMENT_ANY_COLOR_BITS; diff --git a/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c b/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c index 2d4eae50fe3..652fc725876 100644 --- a/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c +++ b/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c @@ -196,6 +196,7 @@ panvk_draw_prepare_fs_rsd(struct panvk_cmd_buffer *cmdbuf, dyn_gfx_state_dirty(cmdbuf, CB_BLEND_EQUATIONS) || dyn_gfx_state_dirty(cmdbuf, CB_WRITE_MASKS) || dyn_gfx_state_dirty(cmdbuf, CB_BLEND_CONSTANTS) || + dyn_gfx_state_dirty(cmdbuf, COLOR_ATTACHMENT_MAP) || dyn_gfx_state_dirty(cmdbuf, DS_DEPTH_TEST_ENABLE) || dyn_gfx_state_dirty(cmdbuf, DS_DEPTH_WRITE_ENABLE) || dyn_gfx_state_dirty(cmdbuf, DS_DEPTH_COMPARE_OP) || @@ -220,12 +221,11 @@ panvk_draw_prepare_fs_rsd(struct panvk_cmd_buffer *cmdbuf, const struct vk_dynamic_graphics_state *dyns = &cmdbuf->vk.dynamic_graphics_state; const struct vk_rasterization_state *rs = &dyns->rs; - const struct vk_color_blend_state *cb = &dyns->cb; const struct vk_depth_stencil_state *ds = &dyns->ds; const struct vk_input_assembly_state *ia = &dyns->ia; const struct panvk_shader *fs = get_fs(cmdbuf); const struct pan_shader_info *fs_info = fs ? &fs->info : NULL; - unsigned bd_count = MAX2(cb->attachment_count, 1); + uint32_t bd_count = MAX2(cmdbuf->state.gfx.render.fb.info.rt_count, 1); bool test_s = has_stencil_att(cmdbuf) && ds->stencil.test_enable; bool test_z = has_depth_att(cmdbuf) && ds->depth.test_enable; bool writes_z = writes_depth(cmdbuf); @@ -282,7 +282,8 @@ panvk_draw_prepare_fs_rsd(struct panvk_cmd_buffer *cmdbuf, 8)); } - uint8_t rt_written = fs_info->outputs_written >> FRAG_RESULT_DATA0; + uint8_t rt_written = color_attachment_written_mask( + fs, &cmdbuf->vk.dynamic_graphics_state.cal); uint8_t rt_mask = cmdbuf->state.gfx.render.bound_attachments & MESA_VK_RP_ATTACHMENT_ANY_COLOR_BITS; cfg.properties.allow_forward_pixel_to_kill = diff --git a/src/panfrost/vulkan/panvk_blend.h b/src/panfrost/vulkan/panvk_blend.h index 245b4072f03..d7cadaad3a5 100644 --- a/src/panfrost/vulkan/panvk_blend.h +++ b/src/panfrost/vulkan/panvk_blend.h @@ -8,7 +8,9 @@ #include +#include "util/bitscan.h" #include "util/hash_table.h" +#include "util/macros.h" #include "util/simple_mtx.h" #include "pan_blend.h" @@ -16,6 +18,8 @@ #include "panvk_macros.h" #include "panvk_mempool.h" +#include "vk_graphics_state.h" + struct panvk_cmd_buffer; #ifdef PAN_ARCH diff --git a/src/panfrost/vulkan/panvk_cmd_draw.h b/src/panfrost/vulkan/panvk_cmd_draw.h index 39011a16c2d..47adfc1ba18 100644 --- a/src/panfrost/vulkan/panvk_cmd_draw.h +++ b/src/panfrost/vulkan/panvk_cmd_draw.h @@ -354,4 +354,26 @@ void panvk_per_arch(cmd_prepare_draw_sysvals)(struct panvk_cmd_buffer *cmdbuf, const struct panvk_draw_info *info); +static inline uint32_t +color_attachment_written_mask( + const struct panvk_shader *fs, + const struct vk_color_attachment_location_state *cal) +{ + uint32_t written_by_shader = + (fs->info.outputs_written >> FRAG_RESULT_DATA0) & BITFIELD_MASK(8); + uint32_t catt_written_mask = 0; + + for (uint32_t i = 0; i < MAX_RTS; i++) { + if (cal->color_map[i] == MESA_VK_ATTACHMENT_UNUSED) + continue; + + uint32_t shader_rt = cal->color_map[i]; + + if (written_by_shader & BITFIELD_BIT(shader_rt)) + catt_written_mask |= BITFIELD_BIT(i); + } + + return catt_written_mask; +} + #endif diff --git a/src/panfrost/vulkan/panvk_vX_blend.c b/src/panfrost/vulkan/panvk_vX_blend.c index 557700247fc..0b58450d7ec 100644 --- a/src/panfrost/vulkan/panvk_vX_blend.c +++ b/src/panfrost/vulkan/panvk_vX_blend.c @@ -124,14 +124,15 @@ out: static void emit_blend_desc(const struct pan_shader_info *fs_info, uint64_t fs_code, - const struct pan_blend_state *state, unsigned rt_idx, - uint64_t blend_shader, uint16_t constant, + const struct pan_blend_state *state, unsigned blend_idx, + unsigned rt_idx, uint64_t blend_shader, uint16_t constant, struct mali_blend_packed *bd) { - const struct pan_blend_rt_state *rt = &state->rts[rt_idx]; + const struct pan_blend_rt_state *rt = + rt_idx != MESA_VK_ATTACHMENT_UNUSED ? &state->rts[rt_idx] : NULL; pan_pack(bd, BLEND, cfg) { - if (!state->rt_count || !rt->equation.color_mask) { + if (!state->rt_count || !rt || !rt->equation.color_mask) { cfg.enable = false; cfg.internal.mode = MALI_BLEND_MODE_OFF; continue; @@ -154,7 +155,7 @@ emit_blend_desc(const struct pan_shader_info *fs_info, uint64_t fs_code, cfg.internal.shader.pc = (uint32_t)blend_shader; #if PAN_ARCH <= 7 - uint32_t ret_offset = fs_info->bifrost.blend[rt_idx].return_offset; + uint32_t ret_offset = fs_info->bifrost.blend[blend_idx].return_offset; /* If ret_offset is zero, we assume the BLEND is a terminal * instruction and set return_value to zero, to let the @@ -195,13 +196,13 @@ emit_blend_desc(const struct pan_shader_info *fs_info, uint64_t fs_code, #if PAN_ARCH <= 7 if (fs_info->fs.untyped_color_outputs) { - nir_alu_type type = fs_info->bifrost.blend[rt_idx].type; + nir_alu_type type = fs_info->bifrost.blend[blend_idx].type; cfg.internal.fixed_function.conversion.register_format = GENX(pan_fixup_blend_type)(type, rt->format); } else { cfg.internal.fixed_function.conversion.register_format = - fs_info->bifrost.blend[rt_idx].format; + fs_info->bifrost.blend[blend_idx].format; } if (!opaque) { @@ -302,6 +303,7 @@ panvk_per_arch(blend_emit_descs)(struct panvk_cmd_buffer *cmdbuf, const struct vk_dynamic_graphics_state *dyns = &cmdbuf->vk.dynamic_graphics_state; const struct vk_color_blend_state *cb = &dyns->cb; + const struct vk_color_attachment_location_state *cal = &dyns->cal; const struct panvk_shader *fs = cmdbuf->state.gfx.fs.shader; const struct pan_shader_info *fs_info = fs ? &fs->info : NULL; uint64_t fs_code = panvk_shader_get_dev_addr(fs); @@ -325,11 +327,33 @@ panvk_per_arch(blend_emit_descs)(struct panvk_cmd_buffer *cmdbuf, uint64_t blend_shaders[8] = {}; /* All bits set to one encodes unused fixed-function blend constant. */ unsigned ff_blend_constant = ~0; + uint8_t remap_catts[MAX_RTS] = { + MESA_VK_ATTACHMENT_UNUSED, MESA_VK_ATTACHMENT_UNUSED, + MESA_VK_ATTACHMENT_UNUSED, MESA_VK_ATTACHMENT_UNUSED, + MESA_VK_ATTACHMENT_UNUSED, MESA_VK_ATTACHMENT_UNUSED, + MESA_VK_ATTACHMENT_UNUSED, MESA_VK_ATTACHMENT_UNUSED, + }; + uint32_t blend_count = MAX2(cmdbuf->state.gfx.render.fb.info.rt_count, 1); + + static_assert(ARRAY_SIZE(remap_catts) <= ARRAY_SIZE(cal->color_map), + "vk_color_attachment_location_state::color_map is too small"); + + for (uint32_t i = 0; i < ARRAY_SIZE(remap_catts); i++) { + if (cal->color_map[i] != MESA_VK_ATTACHMENT_UNUSED) { + assert(cal->color_map[i] < MAX_RTS); + remap_catts[cal->color_map[i]] = i; + } + } memset(blend_info, 0, sizeof(*blend_info)); for (uint8_t i = 0; i < cb->attachment_count; i++) { struct pan_blend_rt_state *rt = &bs.rts[i]; + if (cal->color_map[i] == MESA_VK_ATTACHMENT_UNUSED) { + rt->equation.color_mask = 0; + continue; + } + if (!(cb->color_write_enables & BITFIELD_BIT(i))) { rt->equation.color_mask = 0; continue; @@ -387,8 +411,8 @@ panvk_per_arch(blend_emit_descs)(struct panvk_cmd_buffer *cmdbuf, nir_alu_type src0_type = fs_info->bifrost.blend[i].type; nir_alu_type src1_type = fs_info->bifrost.blend_src1_type; - VkResult result = get_blend_shader(dev, &bs, src0_type, src1_type, i, - &blend_shaders[i]); + VkResult result = get_blend_shader(dev, &bs, src0_type, src1_type, + i, &blend_shaders[i]); if (result != VK_SUCCESS) return result; @@ -403,9 +427,13 @@ panvk_per_arch(blend_emit_descs)(struct panvk_cmd_buffer *cmdbuf, ff_blend_constant = 0; /* Now that we've collected all the information, we can emit. */ - for (uint8_t i = 0; i < MAX2(cb->attachment_count, 1); i++) { - emit_blend_desc(fs_info, fs_code, &bs, i, blend_shaders[i], - ff_blend_constant, &bds[i]); + for (uint8_t i = 0; i < blend_count; i++) { + uint32_t catt_idx = remap_catts[i]; + uint64_t blend_shader = + catt_idx != MESA_VK_ATTACHMENT_UNUSED ? blend_shaders[catt_idx] : 0; + + emit_blend_desc(fs_info, fs_code, &bs, i, catt_idx, + blend_shader, ff_blend_constant, &bds[i]); } if (blend_info->shader_loads_blend_const)