diff --git a/docs/features.txt b/docs/features.txt index ac3e3805390..28f8fe8d155 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -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) diff --git a/docs/relnotes/new_features.txt b/docs/relnotes/new_features.txt index a92d6e36e03..b14971e70d7 100644 --- a/docs/relnotes/new_features.txt +++ b/docs/relnotes/new_features.txt @@ -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 diff --git a/src/gallium/drivers/v3d/v3d_context.h b/src/gallium/drivers/v3d/v3d_context.h index cb8263f38cd..2f9172e1d57 100644 --- a/src/gallium/drivers/v3d/v3d_context.h +++ b/src/gallium/drivers/v3d/v3d_context.h @@ -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; }; diff --git a/src/gallium/drivers/v3d/v3d_program.c b/src/gallium/drivers/v3d/v3d_program.c index a0136fffff5..c2a02b745ae 100644 --- a/src/gallium/drivers/v3d/v3d_program.c +++ b/src/gallium/drivers/v3d/v3d_program.c @@ -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); diff --git a/src/gallium/drivers/v3d/v3d_screen.c b/src/gallium/drivers/v3d/v3d_screen.c index c760c3c8675..de0777750f0 100644 --- a/src/gallium/drivers/v3d/v3d_screen.c +++ b/src/gallium/drivers/v3d/v3d_screen.c @@ -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; diff --git a/src/gallium/drivers/v3d/v3d_uniforms.c b/src/gallium/drivers/v3d/v3d_uniforms.c index 329d888d49e..fe06237ba6a 100644 --- a/src/gallium/drivers/v3d/v3d_uniforms.c +++ b/src/gallium/drivers/v3d/v3d_uniforms.c @@ -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 | diff --git a/src/gallium/drivers/v3d/v3dx_emit.c b/src/gallium/drivers/v3d/v3dx_emit.c index e8f6d894745..d2d48422b62 100644 --- a/src/gallium/drivers/v3d/v3dx_emit.c +++ b/src/gallium/drivers/v3d/v3dx_emit.c @@ -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 ? diff --git a/src/gallium/drivers/v3d/v3dx_state.c b/src/gallium/drivers/v3d/v3dx_state.c index 92c5f6070b7..4215d746407 100644 --- a/src/gallium/drivers/v3d/v3dx_state.c +++ b/src/gallium/drivers/v3d/v3dx_state.c @@ -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++) {