From 8e0377dcf37c70713e23627d785b2921e1558608 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tapani=20P=C3=A4lli?= Date: Thu, 29 Sep 2022 17:15:06 +0300 Subject: [PATCH] anv: dynamic color blend equation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This affects following packets: BLEND_STATE_ENTRY 3DSTATE_PS_BLEND v2: move vk_to_intel_blend and vk_to_intel_blend_op, remove ps_blend merge (Lionel) Signed-off-by: Tapani Pälli Reviewed-by: Lionel Landwerlin Part-of: --- src/intel/vulkan/anv_private.h | 19 +++++- src/intel/vulkan/genX_pipeline.c | 111 ------------------------------- src/intel/vulkan/gfx8_cmd_buffer.c | 130 ++++++++++++++++++++++++++++++++----- 3 files changed, 132 insertions(+), 128 deletions(-) diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 40e51a2..90ee8f1 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -2980,7 +2980,6 @@ struct anv_graphics_pipeline { uint32_t sf[4]; uint32_t raster[5]; uint32_t wm[2]; - uint32_t ps_blend[2]; uint32_t blend_state[1 + MAX_RTS * 2]; uint32_t streamout_state[5]; } gfx8; @@ -3878,6 +3877,24 @@ anv_line_rasterization_mode(VkLineRasterizationModeEXT line_mode, unreachable("Invalid provoking vertex mode"); \ } \ +static inline bool +anv_is_dual_src_blend_factor(VkBlendFactor factor) +{ + return factor == VK_BLEND_FACTOR_SRC1_COLOR || + factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR || + factor == VK_BLEND_FACTOR_SRC1_ALPHA || + factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; +} + +static inline bool +anv_is_dual_src_blend_equation(const struct vk_color_blend_attachment_state *cb) +{ + return anv_is_dual_src_blend_factor(cb->src_color_blend_factor) && + anv_is_dual_src_blend_factor(cb->dst_color_blend_factor) && + anv_is_dual_src_blend_factor(cb->src_alpha_blend_factor) && + anv_is_dual_src_blend_factor(cb->dst_alpha_blend_factor); +} + VkFormatFeatureFlags2 anv_get_image_format_features2(const struct intel_device_info *devinfo, VkFormat vk_format, diff --git a/src/intel/vulkan/genX_pipeline.c b/src/intel/vulkan/genX_pipeline.c index d0820fe..952d35f 100644 --- a/src/intel/vulkan/genX_pipeline.c +++ b/src/intel/vulkan/genX_pipeline.c @@ -772,36 +772,6 @@ const uint32_t genX(vk_to_intel_logic_op)[] = { [VK_LOGIC_OP_SET] = LOGICOP_SET, }; -static const uint32_t vk_to_intel_blend[] = { - [VK_BLEND_FACTOR_ZERO] = BLENDFACTOR_ZERO, - [VK_BLEND_FACTOR_ONE] = BLENDFACTOR_ONE, - [VK_BLEND_FACTOR_SRC_COLOR] = BLENDFACTOR_SRC_COLOR, - [VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR] = BLENDFACTOR_INV_SRC_COLOR, - [VK_BLEND_FACTOR_DST_COLOR] = BLENDFACTOR_DST_COLOR, - [VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR] = BLENDFACTOR_INV_DST_COLOR, - [VK_BLEND_FACTOR_SRC_ALPHA] = BLENDFACTOR_SRC_ALPHA, - [VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA] = BLENDFACTOR_INV_SRC_ALPHA, - [VK_BLEND_FACTOR_DST_ALPHA] = BLENDFACTOR_DST_ALPHA, - [VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA] = BLENDFACTOR_INV_DST_ALPHA, - [VK_BLEND_FACTOR_CONSTANT_COLOR] = BLENDFACTOR_CONST_COLOR, - [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR]= BLENDFACTOR_INV_CONST_COLOR, - [VK_BLEND_FACTOR_CONSTANT_ALPHA] = BLENDFACTOR_CONST_ALPHA, - [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA]= BLENDFACTOR_INV_CONST_ALPHA, - [VK_BLEND_FACTOR_SRC_ALPHA_SATURATE] = BLENDFACTOR_SRC_ALPHA_SATURATE, - [VK_BLEND_FACTOR_SRC1_COLOR] = BLENDFACTOR_SRC1_COLOR, - [VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR] = BLENDFACTOR_INV_SRC1_COLOR, - [VK_BLEND_FACTOR_SRC1_ALPHA] = BLENDFACTOR_SRC1_ALPHA, - [VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA] = BLENDFACTOR_INV_SRC1_ALPHA, -}; - -static const uint32_t vk_to_intel_blend_op[] = { - [VK_BLEND_OP_ADD] = BLENDFUNCTION_ADD, - [VK_BLEND_OP_SUBTRACT] = BLENDFUNCTION_SUBTRACT, - [VK_BLEND_OP_REVERSE_SUBTRACT] = BLENDFUNCTION_REVERSE_SUBTRACT, - [VK_BLEND_OP_MIN] = BLENDFUNCTION_MIN, - [VK_BLEND_OP_MAX] = BLENDFUNCTION_MAX, -}; - const uint32_t genX(vk_to_intel_compare_op)[] = { [VK_COMPARE_OP_NEVER] = PREFILTEROP_NEVER, [VK_COMPARE_OP_LESS] = PREFILTEROP_LESS, @@ -837,15 +807,6 @@ const uint32_t genX(vk_to_intel_primitive_type)[] = { [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY] = _3DPRIM_TRISTRIP_ADJ, }; -static bool -is_dual_src_blend_factor(VkBlendFactor factor) -{ - return factor == VK_BLEND_FACTOR_SRC1_COLOR || - factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR || - factor == VK_BLEND_FACTOR_SRC1_ALPHA || - factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; -} - static inline uint32_t * write_disabled_blend(uint32_t *state) { @@ -864,9 +825,6 @@ emit_cb_state(struct anv_graphics_pipeline *pipeline, const struct vk_color_blend_state *cb, const struct vk_multisample_state *ms) { - struct anv_device *device = pipeline->base.device; - const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline); - struct GENX(BLEND_STATE) blend_state = { .AlphaToCoverageEnable = ms && ms->alpha_to_coverage_enable, }; @@ -882,7 +840,6 @@ emit_cb_state(struct anv_graphics_pipeline *pipeline, uint32_t *state_pos = blend_state_start; state_pos += GENX(BLEND_STATE_length); - struct GENX(BLEND_STATE_ENTRY) bs0 = { 0 }; for (unsigned i = 0; i < surface_count; i++) { struct anv_pipeline_binding *binding = &map->surface_to_descriptor[i]; @@ -898,9 +855,6 @@ emit_cb_state(struct anv_graphics_pipeline *pipeline, continue; } - const struct vk_color_blend_attachment_state *a = - &cb->attachments[binding->index]; - struct GENX(BLEND_STATE_ENTRY) entry = { /* Vulkan specification 1.2.168, VkLogicOp: * @@ -922,77 +876,12 @@ emit_cb_state(struct anv_graphics_pipeline *pipeline, .ColorClampRange = COLORCLAMP_RTFORMAT, .PreBlendColorClampEnable = true, .PostBlendColorClampEnable = true, - .SourceBlendFactor = vk_to_intel_blend[a->src_color_blend_factor], - .DestinationBlendFactor = vk_to_intel_blend[a->dst_color_blend_factor], - .ColorBlendFunction = vk_to_intel_blend_op[a->color_blend_op], - .SourceAlphaBlendFactor = vk_to_intel_blend[a->src_alpha_blend_factor], - .DestinationAlphaBlendFactor = vk_to_intel_blend[a->dst_alpha_blend_factor], - .AlphaBlendFunction = vk_to_intel_blend_op[a->alpha_blend_op], }; - if (a->src_color_blend_factor != a->src_alpha_blend_factor || - a->dst_color_blend_factor != a->dst_alpha_blend_factor || - a->color_blend_op != a->alpha_blend_op) { - blend_state.IndependentAlphaBlendEnable = true; - } - - /* The Dual Source Blending documentation says: - * - * "If SRC1 is included in a src/dst blend factor and - * a DualSource RT Write message is not used, results - * are UNDEFINED. (This reflects the same restriction in DX APIs, - * where undefined results are produced if “o1” is not written - * by a PS – there are no default values defined)." - * - * There is no way to gracefully fix this undefined situation - * so we just disable the blending to prevent possible issues. - */ - if (!wm_prog_data->dual_src_blend && - (is_dual_src_blend_factor(a->src_color_blend_factor) || - is_dual_src_blend_factor(a->dst_color_blend_factor) || - is_dual_src_blend_factor(a->src_alpha_blend_factor) || - is_dual_src_blend_factor(a->dst_alpha_blend_factor))) { - vk_logw(VK_LOG_OBJS(&device->vk.base), - "Enabled dual-src blend factors without writing both targets " - "in the shader. Disabling blending to avoid GPU hangs."); - entry.ColorBufferBlendEnable = false; - } - - /* Our hardware applies the blend factor prior to the blend function - * regardless of what function is used. Technically, this means the - * hardware can do MORE than GL or Vulkan specify. However, it also - * means that, for MIN and MAX, we have to stomp the blend factor to - * ONE to make it a no-op. - */ - if (a->color_blend_op == VK_BLEND_OP_MIN || - a->color_blend_op == VK_BLEND_OP_MAX) { - entry.SourceBlendFactor = BLENDFACTOR_ONE; - entry.DestinationBlendFactor = BLENDFACTOR_ONE; - } - if (a->alpha_blend_op == VK_BLEND_OP_MIN || - a->alpha_blend_op == VK_BLEND_OP_MAX) { - entry.SourceAlphaBlendFactor = BLENDFACTOR_ONE; - entry.DestinationAlphaBlendFactor = BLENDFACTOR_ONE; - } GENX(BLEND_STATE_ENTRY_pack)(NULL, state_pos, &entry); state_pos += GENX(BLEND_STATE_ENTRY_length); - if (i == 0) - bs0 = entry; } - struct GENX(3DSTATE_PS_BLEND) blend = { - GENX(3DSTATE_PS_BLEND_header), - }; - blend.AlphaToCoverageEnable = blend_state.AlphaToCoverageEnable; - blend.SourceAlphaBlendFactor = bs0.SourceAlphaBlendFactor; - blend.DestinationAlphaBlendFactor = bs0.DestinationAlphaBlendFactor; - blend.SourceBlendFactor = bs0.SourceBlendFactor; - blend.DestinationBlendFactor = bs0.DestinationBlendFactor; - blend.AlphaTestEnable = false; - blend.IndependentAlphaBlendEnable = blend_state.IndependentAlphaBlendEnable; - - GENX(3DSTATE_PS_BLEND_pack)(NULL, pipeline->gfx8.ps_blend, &blend); - GENX(BLEND_STATE_pack)(NULL, blend_state_start, &blend_state); } diff --git a/src/intel/vulkan/gfx8_cmd_buffer.c b/src/intel/vulkan/gfx8_cmd_buffer.c index f64eefc..d80280a 100644 --- a/src/intel/vulkan/gfx8_cmd_buffer.c +++ b/src/intel/vulkan/gfx8_cmd_buffer.c @@ -254,6 +254,36 @@ genX(cmd_emit_te)(struct anv_cmd_buffer *cmd_buffer) } } +const uint32_t genX(vk_to_intel_blend)[] = { + [VK_BLEND_FACTOR_ZERO] = BLENDFACTOR_ZERO, + [VK_BLEND_FACTOR_ONE] = BLENDFACTOR_ONE, + [VK_BLEND_FACTOR_SRC_COLOR] = BLENDFACTOR_SRC_COLOR, + [VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR] = BLENDFACTOR_INV_SRC_COLOR, + [VK_BLEND_FACTOR_DST_COLOR] = BLENDFACTOR_DST_COLOR, + [VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR] = BLENDFACTOR_INV_DST_COLOR, + [VK_BLEND_FACTOR_SRC_ALPHA] = BLENDFACTOR_SRC_ALPHA, + [VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA] = BLENDFACTOR_INV_SRC_ALPHA, + [VK_BLEND_FACTOR_DST_ALPHA] = BLENDFACTOR_DST_ALPHA, + [VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA] = BLENDFACTOR_INV_DST_ALPHA, + [VK_BLEND_FACTOR_CONSTANT_COLOR] = BLENDFACTOR_CONST_COLOR, + [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR]= BLENDFACTOR_INV_CONST_COLOR, + [VK_BLEND_FACTOR_CONSTANT_ALPHA] = BLENDFACTOR_CONST_ALPHA, + [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA]= BLENDFACTOR_INV_CONST_ALPHA, + [VK_BLEND_FACTOR_SRC_ALPHA_SATURATE] = BLENDFACTOR_SRC_ALPHA_SATURATE, + [VK_BLEND_FACTOR_SRC1_COLOR] = BLENDFACTOR_SRC1_COLOR, + [VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR] = BLENDFACTOR_INV_SRC1_COLOR, + [VK_BLEND_FACTOR_SRC1_ALPHA] = BLENDFACTOR_SRC1_ALPHA, + [VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA] = BLENDFACTOR_INV_SRC1_ALPHA, +}; + +static const uint32_t genX(vk_to_intel_blend_op)[] = { + [VK_BLEND_OP_ADD] = BLENDFUNCTION_ADD, + [VK_BLEND_OP_SUBTRACT] = BLENDFUNCTION_SUBTRACT, + [VK_BLEND_OP_REVERSE_SUBTRACT] = BLENDFUNCTION_REVERSE_SUBTRACT, + [VK_BLEND_OP_MIN] = BLENDFUNCTION_MIN, + [VK_BLEND_OP_MAX] = BLENDFUNCTION_MAX, +}; + void genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer) { @@ -533,27 +563,15 @@ genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer) BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_COLOR_WRITE_ENABLES) || BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_LOGIC_OP_ENABLE) || BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_MS_ALPHA_TO_ONE_ENABLE) || - BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_COLOR_WRITE_ENABLES)) { + BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_COLOR_WRITE_ENABLES) || + BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS)) { const uint8_t color_writes = dyn->cb.color_write_enables; const struct anv_cmd_graphics_state *state = &cmd_buffer->state.gfx; + const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline); bool has_writeable_rt = anv_pipeline_has_stage(pipeline, MESA_SHADER_FRAGMENT) && (color_writes & ((1u << state->color_att_count) - 1)) != 0; - /* 3DSTATE_PS_BLEND to be consistent with the rest of the - * BLEND_STATE_ENTRY. - */ - uint32_t ps_blend_dwords[GENX(3DSTATE_PS_BLEND_length)]; - struct GENX(3DSTATE_PS_BLEND) ps_blend = { - GENX(3DSTATE_PS_BLEND_header), - .HasWriteableRT = has_writeable_rt, - .ColorBufferBlendEnable = - !dyn->cb.logic_op_enable && dyn->cb.attachments[0].blend_enable, - }; - GENX(3DSTATE_PS_BLEND_pack)(NULL, ps_blend_dwords, &ps_blend); - anv_batch_emit_merge(&cmd_buffer->batch, ps_blend_dwords, - pipeline->gfx8.ps_blend); - uint32_t blend_dws[GENX(BLEND_STATE_length) + MAX_RTS * GENX(BLEND_STATE_ENTRY_length)]; uint32_t *dws = blend_dws; @@ -562,11 +580,12 @@ genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer) struct GENX(BLEND_STATE) blend_state = { .AlphaToOneEnable = dyn->ms.alpha_to_one_enable, }; - GENX(BLEND_STATE_pack)(NULL, dws, &blend_state); /* Jump to blend entries. */ dws += GENX(BLEND_STATE_length); + struct GENX(BLEND_STATE_ENTRY) bs0 = { 0 }; + for (uint32_t i = 0; i < MAX_RTS; i++) { /* Disable anything above the current number of color attachments. */ bool write_disabled = i >= cmd_buffer->state.gfx.color_att_count || @@ -589,10 +608,89 @@ genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer) .ColorBufferBlendEnable = !dyn->cb.logic_op_enable && dyn->cb.attachments[i].blend_enable, }; + + /* Setup blend equation. */ + entry.SourceBlendFactor = + genX(vk_to_intel_blend)[dyn->cb.attachments[i].src_color_blend_factor]; + entry.DestinationBlendFactor = + genX(vk_to_intel_blend)[dyn->cb.attachments[i].dst_color_blend_factor]; + entry.ColorBlendFunction = + genX(vk_to_intel_blend_op)[dyn->cb.attachments[i].color_blend_op]; + entry.SourceAlphaBlendFactor = + genX(vk_to_intel_blend)[dyn->cb.attachments[i].src_alpha_blend_factor]; + entry.DestinationAlphaBlendFactor = + genX(vk_to_intel_blend)[dyn->cb.attachments[i].dst_alpha_blend_factor]; + entry.AlphaBlendFunction = + genX(vk_to_intel_blend_op)[dyn->cb.attachments[i].alpha_blend_op]; + + if (dyn->cb.attachments[i].src_color_blend_factor != + dyn->cb.attachments[i].src_alpha_blend_factor || + dyn->cb.attachments[i].dst_color_blend_factor != + dyn->cb.attachments[i].dst_alpha_blend_factor || + dyn->cb.attachments[i].color_blend_op != + dyn->cb.attachments[i].alpha_blend_op) { + blend_state.IndependentAlphaBlendEnable = true; + } + + /* The Dual Source Blending documentation says: + * + * "If SRC1 is included in a src/dst blend factor and + * a DualSource RT Write message is not used, results + * are UNDEFINED. (This reflects the same restriction in DX APIs, + * where undefined results are produced if “o1” is not written + * by a PS – there are no default values defined)." + * + * There is no way to gracefully fix this undefined situation + * so we just disable the blending to prevent possible issues. + */ + if (wm_prog_data && !wm_prog_data->dual_src_blend && + anv_is_dual_src_blend_equation(&dyn->cb.attachments[i])) { + entry.ColorBufferBlendEnable = false; + } + + /* Our hardware applies the blend factor prior to the blend function + * regardless of what function is used. Technically, this means the + * hardware can do MORE than GL or Vulkan specify. However, it also + * means that, for MIN and MAX, we have to stomp the blend factor to + * ONE to make it a no-op. + */ + if (dyn->cb.attachments[i].color_blend_op == VK_BLEND_OP_MIN || + dyn->cb.attachments[i].color_blend_op == VK_BLEND_OP_MAX) { + entry.SourceBlendFactor = BLENDFACTOR_ONE; + entry.DestinationBlendFactor = BLENDFACTOR_ONE; + } + if (dyn->cb.attachments[i].alpha_blend_op == VK_BLEND_OP_MIN || + dyn->cb.attachments[i].alpha_blend_op == VK_BLEND_OP_MAX) { + entry.SourceAlphaBlendFactor = BLENDFACTOR_ONE; + entry.DestinationAlphaBlendFactor = BLENDFACTOR_ONE; + } + GENX(BLEND_STATE_ENTRY_pack)(NULL, dws, &entry); + + if (i == 0) + bs0 = entry; + dws += GENX(BLEND_STATE_ENTRY_length); } + /* Generate blend state after entries. */ + GENX(BLEND_STATE_pack)(NULL, blend_dws, &blend_state); + + /* 3DSTATE_PS_BLEND to be consistent with the rest of the + * BLEND_STATE_ENTRY. + */ + anv_batch_emit(&cmd_buffer->batch, GENX(3DSTATE_PS_BLEND), blend) { + blend.HasWriteableRT = has_writeable_rt, + blend.ColorBufferBlendEnable = bs0.ColorBufferBlendEnable; + blend.SourceAlphaBlendFactor = bs0.SourceAlphaBlendFactor; + blend.DestinationAlphaBlendFactor = bs0.DestinationAlphaBlendFactor; + blend.SourceBlendFactor = bs0.SourceBlendFactor; + blend.DestinationBlendFactor = bs0.DestinationBlendFactor; + blend.AlphaTestEnable = false; + blend.IndependentAlphaBlendEnable = blend_state.IndependentAlphaBlendEnable; + blend.AlphaToCoverageEnable = dyn->ms.alpha_to_coverage_enable; + } + uint32_t num_dwords = GENX(BLEND_STATE_length) + GENX(BLEND_STATE_ENTRY_length) * MAX_RTS; -- 2.7.4