anv: dynamic color blend equation

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 <tapani.palli@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18879>
This commit is contained in:
Tapani Pälli 2022-09-29 17:15:06 +03:00 committed by Marge Bot
parent fc3fd7c69e
commit 8e0377dcf3
3 changed files with 132 additions and 128 deletions

View file

@ -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,

View file

@ -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);
}

View file

@ -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;