mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 17:40:11 +01:00
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:
parent
dff4986b1a
commit
375d4c2c74
3 changed files with 62 additions and 48 deletions
|
|
@ -99,6 +99,10 @@ struct panfrost_blend_final {
|
||||||
/* Set for a shader, clear for an equation */
|
/* Set for a shader, clear for an equation */
|
||||||
bool is_shader;
|
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 {
|
union {
|
||||||
struct panfrost_blend_shader_final shader;
|
struct panfrost_blend_shader_final shader;
|
||||||
struct panfrost_blend_equation_final equation;
|
struct panfrost_blend_equation_final equation;
|
||||||
|
|
|
||||||
|
|
@ -108,18 +108,23 @@ panfrost_create_blend_state(struct pipe_context *pipe,
|
||||||
assert(!blend->alpha_to_coverage);
|
assert(!blend->alpha_to_coverage);
|
||||||
assert(!blend->alpha_to_one);
|
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];
|
struct panfrost_blend_rt *rt = &so->rt[c];
|
||||||
|
|
||||||
/* There are two paths. First, we would like to try a
|
/* There are two paths. First, we would like to try a
|
||||||
* fixed-function if we can */
|
* 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 =
|
rt->has_fixed_function =
|
||||||
panfrost_make_fixed_blend_mode(
|
panfrost_make_fixed_blend_mode(
|
||||||
&blend->rt[c],
|
&blend->rt[g],
|
||||||
&rt->equation,
|
&rt->equation,
|
||||||
&rt->constant_mask,
|
&rt->constant_mask,
|
||||||
blend->rt[c].colormask);
|
blend->rt[g].colormask);
|
||||||
|
|
||||||
/* Regardless if that works, we also need to initialize
|
/* Regardless if that works, we also need to initialize
|
||||||
* the blend shaders */
|
* 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 */
|
/* There's an equation and suitable constant, so we're good to go */
|
||||||
final.is_shader = false;
|
final.is_shader = false;
|
||||||
final.equation.equation = &rt->equation;
|
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;
|
return final;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -256,6 +267,7 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
|
||||||
/* Otherwise, we need to grab a shader */
|
/* Otherwise, we need to grab a shader */
|
||||||
struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, rti);
|
struct panfrost_blend_shader *shader = panfrost_get_blend_shader(ctx, blend, fmt, rti);
|
||||||
final.is_shader = true;
|
final.is_shader = true;
|
||||||
|
final.no_blending = false;
|
||||||
final.shader.work_count = shader->work_count;
|
final.shader.work_count = shader->work_count;
|
||||||
final.shader.first_tag = shader->first_tag;
|
final.shader.first_tag = shader->first_tag;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -968,13 +968,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
|
||||||
#undef COPY
|
#undef COPY
|
||||||
|
|
||||||
/* Get blending setup */
|
/* Get blending setup */
|
||||||
struct panfrost_blend_final blend =
|
unsigned rt_count = MAX2(ctx->pipe_framebuffer.nr_cbufs, 1);
|
||||||
panfrost_get_blend_for_context(ctx, 0);
|
|
||||||
|
|
||||||
/* If there is a blend shader, work registers are shared */
|
struct panfrost_blend_final blend[PIPE_MAX_COLOR_BUFS];
|
||||||
|
|
||||||
if (blend.is_shader)
|
for (unsigned c = 0; c < rt_count; ++c)
|
||||||
ctx->fragment_shader_core.midgard1.work_count = /*MAX2(ctx->fragment_shader_core.midgard1.work_count, ctx->blend->blend_work_count)*/16;
|
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 */
|
/* Set late due to depending on render state */
|
||||||
unsigned flags = ctx->fragment_shader_core.midgard1.flags;
|
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;
|
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
|
/* Even on MFBD, the shader descriptor gets blend shaders. It's
|
||||||
* *also* copied to the blend_meta appended (by convention),
|
* *also* copied to the blend_meta appended (by convention),
|
||||||
* but this is the field actually read by the hardware. (Or
|
* but this is the field actually read by the hardware. (Or
|
||||||
* maybe both are read...?) */
|
* maybe both are read...?) */
|
||||||
|
|
||||||
if (blend.is_shader) {
|
if (blend[0].is_shader) {
|
||||||
ctx->fragment_shader_core.blend.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 {
|
} else {
|
||||||
ctx->fragment_shader_core.blend.shader = 0;
|
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
|
* additionally need to signal CAN_DISCARD for nontrivial blend
|
||||||
* modes (so we're able to read back the destination buffer) */
|
* 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 =
|
ctx->fragment_shader_core.blend.equation =
|
||||||
*blend.equation.equation;
|
*blend[0].equation.equation;
|
||||||
ctx->fragment_shader_core.blend.constant =
|
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;
|
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);
|
struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, size);
|
||||||
memcpy(transfer.cpu, &ctx->fragment_shader_core, sizeof(struct mali_shader_meta));
|
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) {
|
if (!screen->require_sfbd) {
|
||||||
/* Additional blend descriptor tacked on for jobs using MFBD */
|
/* Additional blend descriptor tacked on for jobs using MFBD */
|
||||||
|
|
||||||
unsigned blend_count = 0x200;
|
|
||||||
|
|
||||||
if (blend.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);
|
|
||||||
} else {
|
|
||||||
/* Otherwise, the bottom bit simply specifies if
|
|
||||||
* blending (anything other than REPLACE) is enabled */
|
|
||||||
|
|
||||||
|
|
||||||
if (!no_blending)
|
|
||||||
blend_count |= 0x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct midgard_blend_rt rts[4];
|
struct midgard_blend_rt rts[4];
|
||||||
|
|
||||||
for (unsigned i = 0; i < 1; ++i) {
|
for (unsigned i = 0; i < rt_count; ++i) {
|
||||||
|
unsigned blend_count = 0x200;
|
||||||
|
|
||||||
|
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[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 (!blend[i].no_blending)
|
||||||
|
blend_count |= 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_srgb =
|
bool is_srgb =
|
||||||
(ctx->pipe_framebuffer.nr_cbufs > i) &&
|
(ctx->pipe_framebuffer.nr_cbufs > i) &&
|
||||||
(ctx->pipe_framebuffer.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
|
* native Midgard ops for helping here, but
|
||||||
* they're not well-understood yet. */
|
* they're not well-understood yet. */
|
||||||
|
|
||||||
assert(!(is_srgb && blend.is_shader));
|
assert(!(is_srgb && blend[i].is_shader));
|
||||||
|
|
||||||
if (blend.is_shader) {
|
if (blend[i].is_shader) {
|
||||||
rts[i].blend.shader = blend.shader.bo->gpu | blend.shader.first_tag;
|
rts[i].blend.shader = blend[i].shader.bo->gpu | blend[i].shader.first_tag;
|
||||||
} else {
|
} else {
|
||||||
rts[i].blend.equation = *blend.equation.equation;
|
rts[i].blend.equation = *blend[i].equation.equation;
|
||||||
rts[i].blend.constant = blend.equation.constant;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue