}
}
-void *
-fd6_blend_state_create(struct pipe_context *pctx,
- const struct pipe_blend_state *cso)
+struct fd6_blend_variant *
+__fd6_setup_blend_variant(struct fd6_blend_stateobj *blend, unsigned sample_mask)
{
- struct fd_context *ctx = fd_context(pctx);
- struct fd6_blend_stateobj *so;
+ const struct pipe_blend_state *cso = &blend->base;
+ struct fd6_blend_variant *so;
enum a3xx_rop_code rop = ROP_COPY;
bool reads_dest = false;
- unsigned i, mrt_blend = 0;
+ unsigned mrt_blend = 0;
if (cso->logicop_enable) {
rop = cso->logicop_func; /* maps 1:1 */
reads_dest = util_logicop_reads_dest(cso->logicop_func);
}
- so = CALLOC_STRUCT(fd6_blend_stateobj);
+ so = rzalloc_size(blend, sizeof(*so));
if (!so)
return NULL;
- so->base = *cso;
- struct fd_ringbuffer *ring = fd_ringbuffer_new_object(ctx->pipe,
- ((A6XX_MAX_RENDER_TARGETS * 4) + 4) * 4);
+ struct fd_ringbuffer *ring = fd_ringbuffer_new_object(blend->ctx->pipe,
+ ((A6XX_MAX_RENDER_TARGETS * 4) + 6) * 4);
so->stateobj = ring;
- so->lrz_write = true; /* unless blend enabled for any MRT */
-
- for (i = 0; i < A6XX_MAX_RENDER_TARGETS; i++) {
+ for (unsigned i = 0; i < A6XX_MAX_RENDER_TARGETS; i++) {
const struct pipe_rt_blend_state *rt;
if (cso->independent_blend_enable)
if (rt->blend_enable) {
mrt_blend |= (1 << i);
- so->lrz_write = false;
}
if (reads_dest) {
mrt_blend |= (1 << i);
- so->lrz_write = false;
}
}
.dither_mode_mrt7 = cso->dither ? DITHER_ALWAYS : DITHER_DISABLE,
));
- so->rb_blend_cntl = A6XX_RB_BLEND_CNTL_ENABLE_BLEND(mrt_blend) |
- COND(cso->alpha_to_coverage, A6XX_RB_BLEND_CNTL_ALPHA_TO_COVERAGE) |
- COND(cso->independent_blend_enable, A6XX_RB_BLEND_CNTL_INDEPENDENT_BLEND);
-
OUT_REG(ring, A6XX_SP_BLEND_CNTL(
.unk8 = true,
.alpha_to_coverage = cso->alpha_to_coverage,
.enabled = !!mrt_blend,
));
+ OUT_REG(ring, A6XX_RB_BLEND_CNTL(
+ .enable_blend = mrt_blend,
+ .alpha_to_coverage = cso->alpha_to_coverage,
+ .independent_blend = cso->independent_blend_enable,
+ .sample_mask = sample_mask
+ ));
+
+ so->sample_mask = sample_mask;
+
+ util_dynarray_append(&blend->variants, struct fd6_blend_variant *, so);
+
+ return so;
+}
+
+void *
+fd6_blend_state_create(struct pipe_context *pctx,
+ const struct pipe_blend_state *cso)
+{
+ struct fd6_blend_stateobj *so;
+ bool reads_dest = false;
+
+ if (cso->logicop_enable) {
+ reads_dest = util_logicop_reads_dest(cso->logicop_func);
+ }
+
+ so = rzalloc_size(NULL, sizeof(*so));
+ if (!so)
+ return NULL;
+
+ so->base = *cso;
+ so->ctx = fd_context(pctx);
+ so->lrz_write = true; /* unless blend enabled for any MRT */
+
+ unsigned nr = cso->independent_blend_enable ? A6XX_MAX_RENDER_TARGETS : 1;
+ for (unsigned i = 0; i < nr; i++) {
+ const struct pipe_rt_blend_state *rt = &cso->rt[i];
+
+ if (rt->blend_enable) {
+ so->lrz_write = false;
+ }
+ }
+
+ if (reads_dest) {
+ so->lrz_write = false;
+ }
+
+ util_dynarray_init(&so->variants, so);
+
return so;
}
{
struct fd6_blend_stateobj *so = hwcso;
- fd_ringbuffer_del(so->stateobj);
+ util_dynarray_foreach(&so->variants, struct fd6_blend_variant *, vp) {
+ struct fd6_blend_variant *v = *vp;
+ fd_ringbuffer_del(v->stateobj);
+ }
- FREE(hwcso);
+ ralloc_free(so);
}
#include "freedreno_context.h"
#include "freedreno_util.h"
+/**
+ * Since the sample-mask is part of the hw blend state, we need to have state
+ * variants per sample-mask value. But we don't expect the sample-mask state
+ * to change frequently.
+ */
+struct fd6_blend_variant {
+ unsigned sample_mask;
+ struct fd_ringbuffer *stateobj;
+};
+
struct fd6_blend_stateobj {
struct pipe_blend_state base;
- uint32_t rb_blend_cntl;
-
+ struct fd_context *ctx;
bool lrz_write;
- struct fd_ringbuffer *stateobj;
+ struct util_dynarray variants;
};
static inline struct fd6_blend_stateobj *
return (struct fd6_blend_stateobj *)blend;
}
+struct fd6_blend_variant * __fd6_setup_blend_variant(
+ struct fd6_blend_stateobj *blend, unsigned sample_mask);
+
+static inline struct fd6_blend_variant *
+fd6_blend_variant(struct pipe_blend_state *cso,
+ unsigned nr_samples, unsigned sample_mask)
+{
+ struct fd6_blend_stateobj *blend = fd6_blend_stateobj(cso);
+ unsigned mask = BITFIELD_MASK(nr_samples);
+
+ util_dynarray_foreach(&blend->variants, struct fd6_blend_variant *, vp) {
+ struct fd6_blend_variant *v = *vp;
+
+ /* mask out sample-mask bits that we don't care about to avoid
+ * creating unnecessary variants
+ */
+ if ((mask & v->sample_mask) == (mask & sample_mask)) {
+ return v;
+ }
+ }
+
+ return __fd6_setup_blend_variant(blend, sample_mask);
+}
+
void * fd6_blend_state_create(struct pipe_context *pctx,
const struct pipe_blend_state *cso);
void fd6_blend_state_delete(struct pipe_context *, void *hwcso);
if (info->num_outputs)
fd6_emit_streamout(ring, emit, info);
- if (dirty & FD_DIRTY_BLEND) {
- struct fd6_blend_stateobj *blend = fd6_blend_stateobj(ctx->blend);
- fd6_emit_add_group(emit, blend->stateobj, FD6_GROUP_BLEND, ENABLE_DRAW);
- }
-
if (dirty & (FD_DIRTY_BLEND | FD_DIRTY_SAMPLE_MASK)) {
- struct fd6_blend_stateobj *blend = fd6_blend_stateobj(ctx->blend);
-
- OUT_PKT4(ring, REG_A6XX_RB_BLEND_CNTL, 1);
- OUT_RING(ring, blend->rb_blend_cntl |
- A6XX_RB_BLEND_CNTL_SAMPLE_MASK(ctx->sample_mask));
+ struct fd6_blend_variant *blend = fd6_blend_variant(ctx->blend,
+ pfb->samples, ctx->sample_mask);
+ fd6_emit_add_group(emit, blend->stateobj, FD6_GROUP_BLEND, ENABLE_DRAW);
}
if (dirty & FD_DIRTY_BLEND_COLOR) {