v3d: 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-13 11:06:49 +00:00 committed by Marge Bot
parent 42154029fc
commit a72be0f720
8 changed files with 84 additions and 7 deletions

View file

@ -99,7 +99,7 @@ GL 3.2, GLSL 1.50 --- all DONE: freedreno, nv50, nvc0, r600, radeonsi, llvmpipe,
GL 3.3, GLSL 3.30 --- all DONE: freedreno, nv50, nvc0, r600, radeonsi, llvmpipe, softpipe, virgl, zink, d3d12, iris, crocus/gen6+, asahi
GL_ARB_blend_func_extended DONE (freedreno/a3xx, freedreno/a6xx, panfrost, lima)
GL_ARB_blend_func_extended DONE (freedreno/a3xx, freedreno/a6xx, v3d, panfrost, lima)
GL_ARB_explicit_attrib_location DONE (all drivers that support GLSL)
GL_ARB_occlusion_query2 DONE (v3d, panfrost)
GL_ARB_sampler_objects DONE (all drivers)

View file

@ -4,3 +4,4 @@ pushDescriptor on panvk
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

View file

@ -712,6 +712,8 @@ struct v3d_depth_stencil_alpha_state {
struct v3d_blend_state {
struct pipe_blend_state base;
bool use_software;
/* Per-RT mask of whether blending is enabled. */
uint8_t blend_enables;
};

View file

@ -367,6 +367,16 @@ v3d_uncompiled_shader_create(struct pipe_context *pctx,
if (s->info.stage == MESA_SHADER_KERNEL)
s->info.stage = MESA_SHADER_COMPUTE;
if (s->info.stage == MESA_SHADER_FRAGMENT &&
s->info.outputs_written & BITFIELD_BIT(FRAG_RESULT_COLOR)) {
/* We only support one attachment when doing dual source blending. */
if (s->info.fs.color_is_dual_source)
NIR_PASS(_, s, nir_lower_fragcolor, 1);
else if (V3D_DBG(SOFT_BLEND))
NIR_PASS(_, s, nir_lower_fragcolor,
V3D_MAX_DRAW_BUFFERS);
}
if (s->info.stage != MESA_SHADER_VERTEX &&
s->info.stage != MESA_SHADER_GEOMETRY) {
NIR_PASS(_, s, nir_lower_io,
@ -680,6 +690,8 @@ v3d_update_compiled_fs(struct v3d_context *v3d, uint8_t prim_mode)
!v3d->zsa->base.depth_writemask) &&
!(v3d->active_queries && v3d->current_oq);
key->software_blend = v3d->blend->use_software;
for (int i = 0; i < v3d->framebuffer.nr_cbufs; i++) {
struct pipe_surface *cbuf = v3d->framebuffer.cbufs[i];
if (!cbuf)
@ -696,7 +708,8 @@ v3d_update_compiled_fs(struct v3d_context *v3d, uint8_t prim_mode)
* swizzle.
*/
if (key->logicop_func != PIPE_LOGICOP_COPY ||
s->info.fs.uses_fbfetch_output) {
s->info.fs.uses_fbfetch_output ||
key->software_blend) {
key->color_fmt[i].format = cbuf->format;
memcpy(key->color_fmt[i].swizzle,
@ -705,6 +718,26 @@ v3d_update_compiled_fs(struct v3d_context *v3d, uint8_t prim_mode)
sizeof(key->color_fmt[i].swizzle));
}
if (key->software_blend) {
struct pipe_rt_blend_state *blend = &v3d->blend->base.rt[i];
if (blend->blend_enable) {
key->blend[i].rgb_func = blend->rgb_func;
key->blend[i].rgb_src_factor = blend->rgb_src_factor;
key->blend[i].rgb_dst_factor = blend->rgb_dst_factor;
key->blend[i].alpha_func = blend->alpha_func;
key->blend[i].alpha_src_factor = blend->alpha_src_factor;
key->blend[i].alpha_dst_factor = blend->alpha_dst_factor;
} else {
key->blend[i].rgb_func = PIPE_BLEND_ADD;
key->blend[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
key->blend[i].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
key->blend[i].alpha_func = PIPE_BLEND_ADD;
key->blend[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
key->blend[i].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
}
}
const struct util_format_description *desc =
util_format_description(cbuf->format);

View file

@ -338,6 +338,7 @@ v3d_init_screen_caps(struct v3d_screen *screen)
caps->max_render_targets = V3D_MAX_RENDER_TARGETS(screen->devinfo.ver);
caps->fbfetch = caps->max_render_targets;
caps->fbfetch_coherent = true;
caps->max_dual_source_render_targets = 1;
caps->vendor_id = 0x14E4;

View file

@ -393,6 +393,19 @@ v3d_write_uniforms(struct v3d_context *v3d, struct v3d_job *job,
cl_aligned_u32(&uniforms, job->num_layers);
break;
case QUNIFORM_BLEND_CONSTANT_R:
cl_aligned_f(&uniforms, v3d->blend_color.f.color[0]);
break;
case QUNIFORM_BLEND_CONSTANT_G:
cl_aligned_f(&uniforms, v3d->blend_color.f.color[1]);
break;
case QUNIFORM_BLEND_CONSTANT_B:
cl_aligned_f(&uniforms, v3d->blend_color.f.color[2]);
break;
case QUNIFORM_BLEND_CONSTANT_A:
cl_aligned_f(&uniforms, v3d->blend_color.f.color[3]);
break;
default:
unreachable("Unknown QUNIFORM");
@ -486,6 +499,13 @@ v3d_set_shader_uniform_dirty_flags(struct v3d_compiled_shader *shader)
dirty |= V3D_DIRTY_FRAMEBUFFER;
break;
case QUNIFORM_BLEND_CONSTANT_R:
case QUNIFORM_BLEND_CONSTANT_G:
case QUNIFORM_BLEND_CONSTANT_B:
case QUNIFORM_BLEND_CONSTANT_A:
dirty |= V3D_DIRTY_BLEND_COLOR;
break;
default:
assert(quniform_contents_is_texture_p0(shader->prog_data.base->uniforms.contents[i]));
dirty |= V3D_DIRTY_FRAGTEX | V3D_DIRTY_VERTTEX |

View file

@ -324,7 +324,7 @@ v3dX(emit_state)(struct pipe_context *pctx)
config.direct3d_provoking_vertex =
v3d->rasterizer->base.flatshade_first;
config.blend_enable = v3d->blend->blend_enables;
config.blend_enable = v3d->blend->blend_enables && !v3d->blend->use_software;
/* Note: EZ state may update based on the compiled FS,
* along with ZSA
@ -480,7 +480,7 @@ v3dX(emit_state)(struct pipe_context *pctx)
if (v3d->dirty & V3D_DIRTY_BLEND) {
struct v3d_blend_state *blend = v3d->blend;
if (blend->blend_enables) {
if (blend->blend_enables && !blend->use_software) {
cl_emit(&job->bcl, BLEND_ENABLES, enables) {
enables.mask = blend->blend_enables;
}
@ -516,6 +516,10 @@ v3dX(emit_state)(struct pipe_context *pctx)
(1 << max_rts) - 1,
v3d->blend_dst_alpha_one);
}
} else {
cl_emit(&job->bcl, BLEND_ENABLES, enables) {
enables.mask = 0;
}
}
}
@ -535,9 +539,6 @@ v3dX(emit_state)(struct pipe_context *pctx)
}
}
/* GFXH-1431: On V3D 3.x, writing BLEND_CONFIG resets the constant
* color.
*/
if (v3d->dirty & V3D_DIRTY_BLEND_COLOR) {
cl_emit(&job->bcl, BLEND_CONSTANT_COLOR, color) {
color.red_f16 = (v3d->swap_color_rb ?

View file

@ -24,6 +24,7 @@
#include "pipe/p_state.h"
#include "util/format/u_format.h"
#include "util/u_dual_blend.h"
#include "util/u_framebuffer.h"
#include "util/u_inlines.h"
#include "util/u_math.h"
@ -123,6 +124,22 @@ v3d_create_rasterizer_state(struct pipe_context *pctx,
return so;
}
/* If the pipe_blend_state contains dual source factors then we need to fall
* back to software blend.
*/
static bool
v3d_needs_software_blend(const struct pipe_blend_state *blend)
{
if (V3D_DBG(SOFT_BLEND))
return true;
/* We only support 1 attachment with dual source blend. */
if (util_blend_state_is_dual(blend, 0))
return true;
return false;
}
/* Blend state is baked into shaders. */
static void *
v3d_create_blend_state(struct pipe_context *pctx,
@ -136,6 +153,8 @@ v3d_create_blend_state(struct pipe_context *pctx,
so->base = *cso;
so->use_software = v3d_needs_software_blend(cso);
uint32_t max_rts = V3D_MAX_RENDER_TARGETS(V3D_VERSION);
if (cso->independent_blend_enable) {
for (int i = 0; i < max_rts; i++) {