panfrost: Extend blending to MRT

Our hardware supports independent (per-RT) blending, but we need to
route those settings through from Gallium.

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
This commit is contained in:
Alyssa Rosenzweig 2019-08-12 16:14:03 -07:00
parent dff4986b1a
commit 375d4c2c74
3 changed files with 62 additions and 48 deletions

View file

@ -99,6 +99,10 @@ struct panfrost_blend_final {
/* Set for a shader, clear for an equation */
bool is_shader;
/* Set if the destination needs to be loaded from the tilebuffer,
* basically (for an equation) or if a shader is present */
bool no_blending;
union {
struct panfrost_blend_shader_final shader;
struct panfrost_blend_equation_final equation;

View file

@ -108,18 +108,23 @@ panfrost_create_blend_state(struct pipe_context *pipe,
assert(!blend->alpha_to_coverage);
assert(!blend->alpha_to_one);
for (unsigned c = 0; c < 4; ++c) {
for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
struct panfrost_blend_rt *rt = &so->rt[c];
/* There are two paths. First, we would like to try a
* fixed-function if we can */
/* Without indep blending, the first RT settings replicate */
unsigned g =
blend->independent_blend_enable ? c : 0;
rt->has_fixed_function =
panfrost_make_fixed_blend_mode(
&blend->rt[c],
&blend->rt[g],
&rt->equation,
&rt->constant_mask,
blend->rt[c].colormask);
blend->rt[g].colormask);
/* Regardless if that works, we also need to initialize
* the blend shaders */
@ -249,6 +254,12 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
/* There's an equation and suitable constant, so we're good to go */
final.is_shader = false;
final.equation.equation = &rt->equation;
final.no_blending =
(rt->equation.rgb_mode == 0x122) &&
(rt->equation.alpha_mode == 0x122) &&
(rt->equation.color_mask == 0xf);
return final;
}
}
@ -256,6 +267,7 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
/* Otherwise, we need to grab a shader */
struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, rti);
final.is_shader = true;
final.no_blending = false;
final.shader.work_count = shader->work_count;
final.shader.first_tag = shader->first_tag;

View file

@ -968,13 +968,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
#undef COPY
/* Get blending setup */
struct panfrost_blend_final blend =
panfrost_get_blend_for_context(ctx, 0);
unsigned rt_count = MAX2(ctx->pipe_framebuffer.nr_cbufs, 1);
/* If there is a blend shader, work registers are shared */
struct panfrost_blend_final blend[PIPE_MAX_COLOR_BUFS];
if (blend.is_shader)
ctx->fragment_shader_core.midgard1.work_count = /*MAX2(ctx->fragment_shader_core.midgard1.work_count, ctx->blend->blend_work_count)*/16;
for (unsigned c = 0; c < rt_count; ++c)
blend[c] = panfrost_get_blend_for_context(ctx, c);
/* If there is a blend shader, work registers are shared. XXX: opt */
for (unsigned c = 0; c < rt_count; ++c) {
if (blend[c].is_shader)
ctx->fragment_shader_core.midgard1.work_count = 16;
}
/* Set late due to depending on render state */
unsigned flags = ctx->fragment_shader_core.midgard1.flags;
@ -1014,22 +1020,14 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
ctx->fragment_shader_core.midgard1.flags |= 0x400;
}
/* Check if we're using the default blend descriptor (fast path) */
bool no_blending =
!blend.is_shader &&
(blend.equation.equation->rgb_mode == 0x122) &&
(blend.equation.equation->alpha_mode == 0x122) &&
(blend.equation.equation->color_mask == 0xf);
/* Even on MFBD, the shader descriptor gets blend shaders. It's
* *also* copied to the blend_meta appended (by convention),
* but this is the field actually read by the hardware. (Or
* maybe both are read...?) */
if (blend.is_shader) {
if (blend[0].is_shader) {
ctx->fragment_shader_core.blend.shader =
blend.shader.bo->gpu | blend.shader.first_tag;
blend[0].shader.bo->gpu | blend[0].shader.first_tag;
} else {
ctx->fragment_shader_core.blend.shader = 0;
}
@ -1040,19 +1038,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
* additionally need to signal CAN_DISCARD for nontrivial blend
* modes (so we're able to read back the destination buffer) */
if (!blend.is_shader) {
if (!blend[0].is_shader) {
ctx->fragment_shader_core.blend.equation =
*blend.equation.equation;
*blend[0].equation.equation;
ctx->fragment_shader_core.blend.constant =
blend.equation.constant;
blend[0].equation.constant;
}
if (!no_blending) {
if (!blend[0].no_blending) {
ctx->fragment_shader_core.unknown2_3 |= MALI_CAN_DISCARD;
}
}
size_t size = sizeof(struct mali_shader_meta) + sizeof(struct midgard_blend_rt);
size_t size = sizeof(struct mali_shader_meta) + (sizeof(struct midgard_blend_rt) * rt_count);
struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, size);
memcpy(transfer.cpu, &ctx->fragment_shader_core, sizeof(struct mali_shader_meta));
@ -1061,27 +1059,27 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
if (!screen->require_sfbd) {
/* Additional blend descriptor tacked on for jobs using MFBD */
struct midgard_blend_rt rts[4];
for (unsigned i = 0; i < rt_count; ++i) {
unsigned blend_count = 0x200;
if (blend.is_shader) {
if (blend[i].is_shader) {
/* For a blend shader, the bottom nibble corresponds to
* the number of work registers used, which signals the
* -existence- of a blend shader */
assert(blend.shader.work_count >= 2);
blend_count |= MIN2(blend.shader.work_count, 3);
assert(blend[i].shader.work_count >= 2);
blend_count |= MIN2(blend[i].shader.work_count, 3);
} else {
/* Otherwise, the bottom bit simply specifies if
* blending (anything other than REPLACE) is enabled */
if (!no_blending)
if (!blend[i].no_blending)
blend_count |= 0x1;
}
struct midgard_blend_rt rts[4];
for (unsigned i = 0; i < 1; ++i) {
bool is_srgb =
(ctx->pipe_framebuffer.nr_cbufs > i) &&
(ctx->pipe_framebuffer.cbufs[i]) &&
@ -1101,17 +1099,17 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
* native Midgard ops for helping here, but
* they're not well-understood yet. */
assert(!(is_srgb && blend.is_shader));
assert(!(is_srgb && blend[i].is_shader));
if (blend.is_shader) {
rts[i].blend.shader = blend.shader.bo->gpu | blend.shader.first_tag;
if (blend[i].is_shader) {
rts[i].blend.shader = blend[i].shader.bo->gpu | blend[i].shader.first_tag;
} else {
rts[i].blend.equation = *blend.equation.equation;
rts[i].blend.constant = blend.equation.constant;
rts[i].blend.equation = *blend[i].equation.equation;
rts[i].blend.constant = blend[i].equation.constant;
}
}
memcpy(transfer.cpu + sizeof(struct mali_shader_meta), rts, sizeof(rts[0]) * 1);
memcpy(transfer.cpu + sizeof(struct mali_shader_meta), rts, sizeof(rts[0]) * rt_count);
}
}