v3dv: Implement dual source blending

Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33942>
This commit is contained in:
Ella Stanforth 2025-03-11 12:44:11 +00:00 committed by Marge Bot
parent a72be0f720
commit 08c323951b
10 changed files with 136 additions and 14 deletions

View file

@ -5,3 +5,4 @@ VK_EXT_vertex_input_dynamic_state on panvk
VK_EXT_vertex_attribute_divisor on panvk
supportsNonZeroFirstInstance on panvk
GL_ARB_blend_func_extended on v3d
dualSrcBlend on v3dv

View file

@ -586,3 +586,11 @@ ubsan-KHR-GL31.transform_feedback3.multiple_streams,Fail
# This seems to be working with upstream
program@execute@vector-conversion,Fail
# B10G11R11 Formats have accuracy issues.
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail

View file

@ -454,3 +454,11 @@ KHR-GL31.transform_feedback3.skip_multiple_buffers,Fail
# This seems to be working with upstream
program@execute@vector-conversion,Fail
# B10G11R11 Formats have accuracy issues.
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_variable.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_dc_ca_rsub_alpha_dc_s1a_rsub-color_cc_da_min_alpha_ca_1ms1a_max-color_1msc_1mdc_max_alpha_cc_sa_rsub-color_da_o_sub_alpha_z_dc_rsub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_da_ca_max_alpha_da_1mdc_rsub-color_sa_1msc_sub_alpha_sc_1mca_sub-color_1ms1c_s1c_add_alpha_s1c_dc_rsub-color_da_1mda_add_alpha_s1c_1msa_sub,Fail
dEQP-VK.pipeline.monolithic.blend.dual_source.format.b10g11r11_ufloat_pack32.output_array.states.color_1ms1a_sa_max_alpha_sas_sas_min-color_1ms1c_1msa_sub_alpha_1msc_o_add-color_sa_sa_rsub_alpha_cc_cc_add-color_da_da_add_alpha_s1c_da_add,Fail

View file

@ -2400,7 +2400,9 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
V3DV_CMD_DIRTY_DESCRIPTOR_SETS |
V3DV_CMD_DIRTY_VIEW_INDEX |
V3DV_CMD_DIRTY_DRAW_ID)) ||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS);
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS) ||
(pipeline->blend.use_software &&
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS));
if (!dirty_uniform_state)
return false;
@ -2411,6 +2413,8 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
const bool has_new_descriptors = dirty & V3DV_CMD_DIRTY_DESCRIPTOR_SETS;
const bool has_new_view_index = dirty & V3DV_CMD_DIRTY_VIEW_INDEX;
const bool has_new_draw_id = dirty & V3DV_CMD_DIRTY_DRAW_ID;
const bool has_new_blend_constants = (pipeline->blend.use_software &&
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS));
/* VK_SHADER_STAGE_FRAGMENT_BIT */
const bool has_new_descriptors_fs =
@ -2424,7 +2428,8 @@ update_gfx_uniform_state(struct v3dv_cmd_buffer *cmd_buffer)
const bool needs_fs_update = has_new_pipeline ||
has_new_view_index ||
has_new_push_constants_fs ||
has_new_descriptors_fs;
has_new_descriptors_fs ||
has_new_blend_constants;
if (needs_fs_update) {
struct v3dv_shader_variant *fs_variant =

View file

@ -258,7 +258,7 @@ get_features(const struct v3dv_physical_device *physical_device,
.geometryShader = true,
.tessellationShader = false,
.sampleRateShading = true,
.dualSrcBlend = false,
.dualSrcBlend = true,
.logicOp = true,
.multiDrawIndirect = false,
.drawIndirectFirstInstance = true,
@ -967,7 +967,7 @@ get_device_properties(const struct v3dv_physical_device *device,
/* Fragment limits */
.maxFragmentInputComponents = max_varying_components,
.maxFragmentOutputAttachments = 4,
.maxFragmentDualSrcAttachments = 0,
.maxFragmentDualSrcAttachments = 1,
.maxFragmentCombinedOutputResources = max_rts +
MAX_STORAGE_BUFFERS +
MAX_STORAGE_IMAGES,

View file

@ -29,6 +29,7 @@
#include "qpu/qpu_disasm.h"
#include "compiler/nir/nir_builder.h"
#include "compiler/nir/nir_lower_blend.h"
#include "nir/nir_serialize.h"
#include "util/shader_stats.h"
@ -39,6 +40,7 @@
#include "vk_format.h"
#include "vk_nir_convert_ycbcr.h"
#include "vk_pipeline.h"
#include "vk_blend.h"
static VkResult
compute_vpm_config(struct v3dv_pipeline *pipeline);
@ -1121,7 +1123,9 @@ v3d_fs_key_set_color_attachment(struct v3d_fs_key *key,
/* If logic operations are enabled then we might emit color reads and we
* need to know the color buffer format and swizzle for that
*/
if (key->logicop_func != PIPE_LOGICOP_COPY) {
if (key->logicop_func != PIPE_LOGICOP_COPY ||
p_stage->nir->info.fs.uses_fbfetch_output ||
key->software_blend) {
/* Framebuffer formats should be single plane */
assert(vk_format_get_plane_count(fb_format) == 1);
key->color_fmt[index].format = fb_pipe_format;
@ -1130,6 +1134,27 @@ v3d_fs_key_set_color_attachment(struct v3d_fs_key *key,
sizeof(key->color_fmt[index].swizzle));
}
if (key->software_blend) {
struct vk_color_blend_attachment_state *att =
&p_stage->pipeline->dynamic_graphics_state.cb.attachments[index];
if (att->blend_enable) {
key->blend[index].rgb_func = vk_blend_op_to_pipe(att->color_blend_op);
key->blend[index].alpha_func = vk_blend_op_to_pipe(att->alpha_blend_op);
key->blend[index].rgb_dst_factor = vk_blend_factor_to_pipe(att->dst_color_blend_factor);
key->blend[index].alpha_dst_factor = vk_blend_factor_to_pipe(att->dst_alpha_blend_factor);
key->blend[index].rgb_src_factor = vk_blend_factor_to_pipe(att->src_color_blend_factor);
key->blend[index].alpha_src_factor = vk_blend_factor_to_pipe(att->src_alpha_blend_factor);
} else {
key->blend[index].rgb_func = PIPE_BLEND_ADD;
key->blend[index].alpha_func = PIPE_BLEND_ADD;
key->blend[index].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
key->blend[index].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
key->blend[index].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
key->blend[index].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
}
}
const struct util_format_description *desc =
vk_format_description(fb_format);
@ -1215,6 +1240,8 @@ pipeline_populate_v3d_fs_key(struct v3d_fs_key *key,
*/
key->swap_color_rb = 0;
key->software_blend = p_stage->pipeline->blend.use_software;
for (uint32_t i = 0; i < rendering_info->color_attachment_count; i++) {
if (rendering_info->color_attachment_formats[i] == VK_FORMAT_UNDEFINED)
continue;
@ -1989,6 +2016,8 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
key->sample_alpha_to_one = ms_info->alphaToOneEnable;
}
key->software_blend = pipeline->blend.use_software;
struct vk_render_pass_state *ri = &pipeline->rendering_info;
for (uint32_t i = 0; i < ri->color_attachment_count; i++) {
if (ri->color_attachment_formats[i] == VK_FORMAT_UNDEFINED)
@ -2002,7 +2031,8 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
/* If logic operations are enabled then we might emit color reads and we
* need to know the color buffer format and swizzle for that
*/
if (key->logicop_func != PIPE_LOGICOP_COPY) {
if (key->logicop_func != PIPE_LOGICOP_COPY ||
key->software_blend) {
/* Framebuffer formats should be single plane */
assert(vk_format_get_plane_count(fb_format) == 1);
key->color_fmt[i].format = fb_pipe_format;
@ -2011,6 +2041,27 @@ pipeline_populate_graphics_key(struct v3dv_pipeline *pipeline,
sizeof(key->color_fmt[i].swizzle));
}
if (key->software_blend) {
struct vk_color_blend_attachment_state *att =
&pipeline->dynamic_graphics_state.cb.attachments[i];
if (att->blend_enable) {
key->blend[i].rgb_func = vk_blend_op_to_pipe(att->color_blend_op);
key->blend[i].alpha_func = vk_blend_op_to_pipe(att->alpha_blend_op);
key->blend[i].rgb_dst_factor = vk_blend_factor_to_pipe(att->dst_color_blend_factor);
key->blend[i].alpha_dst_factor = vk_blend_factor_to_pipe(att->dst_alpha_blend_factor);
key->blend[i].rgb_src_factor = vk_blend_factor_to_pipe(att->src_color_blend_factor);
key->blend[i].alpha_src_factor = vk_blend_factor_to_pipe(att->src_alpha_blend_factor);
} else {
key->blend[i].rgb_func = PIPE_BLEND_ADD;
key->blend[i].alpha_func = PIPE_BLEND_ADD;
key->blend[i].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
key->blend[i].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
key->blend[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
key->blend[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
}
}
const struct util_format_description *desc =
vk_format_description(fb_format);

View file

@ -321,11 +321,20 @@ struct v3dv_pipeline_key {
bool msaa;
bool sample_alpha_to_coverage;
bool sample_alpha_to_one;
bool software_blend;
uint8_t cbufs;
struct {
enum pipe_format format;
uint8_t swizzle[4];
} color_fmt[V3D_MAX_DRAW_BUFFERS];
struct {
enum pipe_blend_func rgb_func;
enum pipe_blendfactor rgb_src_factor;
enum pipe_blendfactor rgb_dst_factor;
enum pipe_blend_func alpha_func;
enum pipe_blendfactor alpha_src_factor;
enum pipe_blendfactor alpha_dst_factor;
} blend[V3D_MAX_DRAW_BUFFERS];
uint8_t f32_color_rb;
uint32_t va_swap_rb_mask;
bool has_multiview;
@ -2318,7 +2327,12 @@ struct v3dv_pipeline {
/* Blend state */
struct {
/* Per-RT bit mask with blend enables */
/* In some cases, such as when dual source blend factors are in use, we
* fall back to software blend lowering.
*/
bool use_software;
/* Per-RT bit mask with blend enables. */
uint8_t enables;
/* Per-RT prepacked blend config packets */
uint8_t cfg[V3D_MAX_DRAW_BUFFERS][V3DV_BLEND_CFG_LENGTH];

View file

@ -670,6 +670,19 @@ v3dv_write_uniforms_wg_offsets(struct v3dv_cmd_buffer *cmd_buffer,
v3dv_get_aa_line_width(pipeline, job->cmd_buffer));
break;
case QUNIFORM_BLEND_CONSTANT_R:
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[0]);
break;
case QUNIFORM_BLEND_CONSTANT_G:
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[1]);
break;
case QUNIFORM_BLEND_CONSTANT_B:
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[2]);
break;
case QUNIFORM_BLEND_CONSTANT_A:
cl_aligned_f(&uniforms, job->cmd_buffer->vk.dynamic_graphics_state.cb.blend_constants[3]);
break;
default:
unreachable("unsupported quniform_contents uniform type\n");
}

View file

@ -1617,6 +1617,10 @@ v3dX(cmd_buffer_emit_blend)(struct v3dv_cmd_buffer *cmd_buffer)
struct v3dv_pipeline *pipeline = cmd_buffer->state.gfx.pipeline;
assert(pipeline);
/* When using software blend we don't want to enable any blend hardware */
if (pipeline->blend.use_software)
return;
const struct v3d_device_info *devinfo = &cmd_buffer->device->devinfo;
const uint32_t max_color_rts = V3D_MAX_RENDER_TARGETS(devinfo->ver);

View file

@ -27,7 +27,8 @@
#include "broadcom/compiler/v3d_compiler.h"
static uint8_t
blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants)
blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants,
bool *needs_dual_src)
{
switch (factor) {
case VK_BLEND_FACTOR_ZERO:
@ -52,11 +53,17 @@ blend_factor(VkBlendFactor factor, bool dst_alpha_one, bool *needs_constants)
case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
return dst_alpha_one ? V3D_BLEND_FACTOR_ZERO :
V3D_BLEND_FACTOR_INV_DST_ALPHA;
/* For dual source blending we need to fallback to software as the hardware
* has no support for it.
*/
case VK_BLEND_FACTOR_SRC1_COLOR:
case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
case VK_BLEND_FACTOR_SRC1_ALPHA:
case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
unreachable("Invalid blend factor: dual source blending not supported.");
assert(needs_dual_src);
*needs_dual_src = true;
return VK_BLEND_FACTOR_ZERO;
default:
unreachable("Unknown blend factor.");
}
@ -86,6 +93,8 @@ pack_blend(struct v3dv_pipeline *pipeline,
assert(ri->color_attachment_count == cb_info->attachmentCount);
pipeline->blend.needs_color_constants = false;
uint32_t color_write_masks = 0;
bool needs_dual_src = false;
for (uint32_t i = 0; i < ri->color_attachment_count; i++) {
const VkPipelineColorBlendAttachmentState *b_state =
&cb_info->pAttachments[i];
@ -116,21 +125,29 @@ pack_blend(struct v3dv_pipeline *pipeline,
config.color_blend_mode = b_state->colorBlendOp;
config.color_blend_dst_factor =
blend_factor(b_state->dstColorBlendFactor, dst_alpha_one,
&pipeline->blend.needs_color_constants);
&pipeline->blend.needs_color_constants,
&needs_dual_src);
config.color_blend_src_factor =
blend_factor(b_state->srcColorBlendFactor, dst_alpha_one,
&pipeline->blend.needs_color_constants);
&pipeline->blend.needs_color_constants,
&needs_dual_src);
config.alpha_blend_mode = b_state->alphaBlendOp;
config.alpha_blend_dst_factor =
blend_factor(b_state->dstAlphaBlendFactor, dst_alpha_one,
&pipeline->blend.needs_color_constants);
&pipeline->blend.needs_color_constants,
&needs_dual_src);
config.alpha_blend_src_factor =
blend_factor(b_state->srcAlphaBlendFactor, dst_alpha_one,
&pipeline->blend.needs_color_constants);
&pipeline->blend.needs_color_constants,
&needs_dual_src);
}
}
/* We may want to fallback to software in other cases in the future such
* as for formats not supported by the blend hardware.
*/
pipeline->blend.use_software = V3D_DBG(SOFT_BLEND) || needs_dual_src;
pipeline->blend.color_write_masks = color_write_masks;
}
@ -191,7 +208,8 @@ pack_cfg_bits(struct v3dv_pipeline *pipeline,
config.direct3d_provoking_vertex = true;
}
config.blend_enable = pipeline->blend.enables != 0;
config.blend_enable = pipeline->blend.enables != 0 &&
!pipeline->blend.use_software;
#if V3D_VERSION >= 71
/* From the Vulkan spec: