summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>2019-07-05 15:40:08 -0700
committerAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>2019-07-10 06:12:08 -0700
commit46396af1ec4b69ca4a38b501fa2cf37386947840 (patch)
tree6b2b5d7e421da52f0fcea08e7974f7947783d834
parentc9af7701d1be791752fafcbe19169851bcdf1336 (diff)
panfrost: Refactor blend infrastructure
We would like to permit keying blend shaders against the framebuffer format, which requires some new blending abstractions. Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
-rw-r--r--src/gallium/drivers/panfrost/meson.build1
-rw-r--r--src/gallium/drivers/panfrost/pan_blend.h109
-rw-r--r--src/gallium/drivers/panfrost/pan_blend_cso.c268
-rw-r--r--src/gallium/drivers/panfrost/pan_blend_shaders.c34
-rw-r--r--src/gallium/drivers/panfrost/pan_blend_shaders.h8
-rw-r--r--src/gallium/drivers/panfrost/pan_blending.c75
-rw-r--r--src/gallium/drivers/panfrost/pan_blending.h13
-rw-r--r--src/gallium/drivers/panfrost/pan_context.c133
-rw-r--r--src/gallium/drivers/panfrost/pan_context.h16
9 files changed, 455 insertions, 202 deletions
diff --git a/src/gallium/drivers/panfrost/meson.build b/src/gallium/drivers/panfrost/meson.build
index cc49903aaac..6b907f155ae 100644
--- a/src/gallium/drivers/panfrost/meson.build
+++ b/src/gallium/drivers/panfrost/meson.build
@@ -56,6 +56,7 @@ files_panfrost = files(
'pan_format.c',
'pan_blending.c',
'pan_blend_shaders.c',
+ 'pan_blend_cso.c',
'pan_pretty_print.c',
'pan_fragment.c',
'pan_invocation.c',
diff --git a/src/gallium/drivers/panfrost/pan_blend.h b/src/gallium/drivers/panfrost/pan_blend.h
new file mode 100644
index 00000000000..486ed4dc034
--- /dev/null
+++ b/src/gallium/drivers/panfrost/pan_blend.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 Collabora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors (Collabora):
+ * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
+ *
+ */
+
+#ifndef __PAN_BLEND_H
+#define __PAN_BLEND_H
+
+#include "util/hash_table.h"
+
+/* An internal blend shader descriptor, from the compiler */
+
+struct panfrost_blend_shader {
+ /* The compiled shader in GPU memory */
+ struct panfrost_transfer shader;
+
+ /* Byte count of the shader */
+ unsigned size;
+
+ /* Number of 128-bit work registers required by the shader */
+ unsigned work_count;
+
+ /* Offset into the shader to patch constants. Zero to disable patching
+ * (it is illogical to have constants at offset 0). */
+ unsigned patch_index;
+
+ /* First instruction tag (for tagging the pointer) */
+ unsigned first_tag;
+};
+
+/* A blend shader descriptor ready for actual use */
+
+struct panfrost_blend_shader_final {
+ /* The upload, possibly to transient memory */
+ mali_ptr gpu;
+
+ /* Same meaning as panfrost_blend_shader */
+ unsigned work_count;
+};
+
+struct panfrost_blend_equation_final {
+ struct mali_blend_equation *equation;
+ float constant;
+};
+
+struct panfrost_blend_rt {
+ /* If has_fixed_function is set, equation is the
+ * fixed-function configuration for this blend state */
+
+ bool has_fixed_function;
+ struct mali_blend_equation equation;
+
+ /* Mask of blend color components read */
+ unsigned constant_mask;
+
+ /* Regardless of fixed-function blending, this is a map of pipe_format
+ * to panfrost_blend_shader */
+
+ struct hash_table_u64 *shaders;
+};
+
+struct panfrost_blend_state {
+ struct pipe_blend_state base;
+
+ struct panfrost_blend_rt rt[PIPE_MAX_COLOR_BUFS];
+};
+
+/* Container for a final blend state, specialized to constants and a
+ * framebuffer formats. */
+
+struct panfrost_blend_final {
+ /* Set for a shader, clear for an equation */
+ bool is_shader;
+
+ union {
+ struct panfrost_blend_shader_final shader;
+ struct panfrost_blend_equation_final equation;
+ };
+};
+
+void
+panfrost_blend_context_init(struct pipe_context *pipe);
+
+struct panfrost_blend_final
+panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rt);
+
+#endif
diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c
new file mode 100644
index 00000000000..a1b8111190f
--- /dev/null
+++ b/src/gallium/drivers/panfrost/pan_blend_cso.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2019 Collabora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors (Collabora):
+ * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
+ *
+ */
+
+#include <stdio.h>
+#include "util/u_memory.h"
+#include "pan_blend_shaders.h"
+#include "pan_blending.h"
+
+/* A given Gallium blend state can be encoded to the hardware in numerous,
+ * dramatically divergent ways due to the interactions of blending with
+ * framebuffer formats. Conceptually, there are two modes:
+ *
+ * - Fixed-function blending (for suitable framebuffer formats, suitable blend
+ * state, and suitable blend constant)
+ *
+ * - Blend shaders (for everything else)
+ *
+ * A given Gallium blend configuration will compile to exactly one
+ * fixed-function blend state, if it compiles to any, although the constant
+ * will vary across runs as that is tracked outside of the Gallium CSO.
+ *
+ * However, that same blend configuration will compile to many different blend
+ * shaders, depending on the framebuffer formats active. The rationale is that
+ * blend shaders override not just fixed-function blending but also
+ * fixed-function format conversion. As such, each blend shader must be
+ * hardcoded to a particular framebuffer format to correctly pack/unpack it. As
+ * a concrete example, to the hardware there is no difference (!) between RG16F
+ * and RG16UI -- both are simply 4-byte-per-pixel chunks. Thus both formats
+ * require a blend shader (even with blending is totally disabled!), required
+ * to do conversion as necessary (if necessary).
+ *
+ * All of this state is encapsulated in the panfrost_blend_state struct
+ * (our subclass of pipe_blend_state).
+ */
+
+/* Given an initialized CSO and a particular framebuffer format, grab a
+ * blend shader, generating and compiling it if it doesn't exist
+ * (lazy-loading in a way). This routine, when the cache hits, should
+ * befast, suitable for calling every draw to avoid wacky dirty
+ * tracking paths. If the cache hits, boom, done. */
+
+static struct panfrost_blend_shader *
+panfrost_get_blend_shader(
+ struct panfrost_context *ctx,
+ struct panfrost_blend_state *blend,
+ enum pipe_format fmt,
+ unsigned rt)
+{
+ /* Prevent NULL collision issues.. */
+ assert(fmt != 0);
+
+ /* Check the cache */
+ struct hash_table_u64 *shaders = blend->rt[rt].shaders;
+
+ struct panfrost_blend_shader *shader =
+ _mesa_hash_table_u64_search(shaders, fmt);
+
+ if (shader)
+ return shader;
+
+ /* Cache miss. Build one instead, cache it, and go */
+
+ struct panfrost_blend_shader generated =
+ panfrost_compile_blend_shader(ctx, &blend->base, fmt);
+
+ shader = mem_dup(&generated, sizeof(generated));
+ _mesa_hash_table_u64_insert(shaders, fmt, shader);
+ return shader;
+}
+
+/* Create a blend CSO. Essentially, try to compile a fixed-function
+ * expression and initialize blend shaders */
+
+static void *
+panfrost_create_blend_state(struct pipe_context *pipe,
+ const struct pipe_blend_state *blend)
+{
+ struct panfrost_context *ctx = pan_context(pipe);
+ struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state);
+ so->base = *blend;
+
+ /* TODO: The following features are not yet implemented */
+ assert(!blend->logicop_enable);
+ assert(!blend->alpha_to_coverage);
+ assert(!blend->alpha_to_one);
+
+ for (unsigned c = 0; c < 4; ++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 */
+
+ rt->has_fixed_function =
+ panfrost_make_fixed_blend_mode(
+ &blend->rt[c],
+ &rt->equation,
+ &rt->constant_mask,
+ blend->rt[c].colormask);
+
+ /* Regardless if that works, we also need to initialize
+ * the blend shaders */
+
+ rt->shaders = _mesa_hash_table_u64_create(NULL);
+ }
+
+ return so;
+}
+
+static void
+panfrost_bind_blend_state(struct pipe_context *pipe,
+ void *cso)
+{
+ struct panfrost_context *ctx = pan_context(pipe);
+ struct pipe_blend_state *blend = (struct pipe_blend_state *) cso;
+ struct panfrost_blend_state *pblend = (struct panfrost_blend_state *) cso;
+ ctx->blend = pblend;
+
+ if (!blend)
+ return;
+
+ SET_BIT(ctx->fragment_shader_core.unknown2_4, MALI_NO_DITHER, !blend->dither);
+
+ /* Shader itself is not dirty, but the shader core is */
+ ctx->dirty |= PAN_DIRTY_FS;
+}
+
+static void
+panfrost_delete_blend_state(struct pipe_context *pipe,
+ void *blend)
+{
+ /* TODO: leaks internally? */
+
+ ralloc_free(blend);
+}
+
+static void
+panfrost_set_blend_color(struct pipe_context *pipe,
+ const struct pipe_blend_color *blend_color)
+{
+ struct panfrost_context *ctx = pan_context(pipe);
+
+ if (blend_color)
+ ctx->blend_color = *blend_color;
+}
+
+/* Given a vec4 of constants, reduce it to just a single constant according to
+ * the mask (if we can) */
+
+static bool
+panfrost_blend_constant(float *out, float *in, unsigned mask)
+{
+ /* If there is no components used, it automatically works. Do set a
+ * dummy constant just to avoid reading uninitialized memory. */
+
+ if (!mask) {
+ *out = 0.0;
+ return true;
+ }
+
+ /* Find some starter mask */
+ unsigned first = ffs(mask) - 1;
+ float cons = in[first];
+ mask ^= (1 << first);
+
+ /* Ensure the rest are equal */
+ while (mask) {
+ unsigned i = u_bit_scan(&mask);
+
+ if (in[i] != cons) {
+ *out = 0.0;
+ return false;
+ }
+ }
+
+ /* Otherwise, we're good to go */
+ *out = cons;
+ return true;
+}
+
+/* Create a final blend given the context */
+
+struct panfrost_blend_final
+panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
+{
+ /* Grab the format */
+ struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
+ assert(fb->nr_cbufs > rti);
+ enum pipe_format fmt = fb->cbufs[rti]->format;
+
+ /* Grab the blend state */
+ struct panfrost_blend_state *blend = ctx->blend;
+ assert(blend);
+
+ struct panfrost_blend_rt *rt = &blend->rt[rti];
+
+ struct panfrost_blend_final final;
+
+ /* First, we'll try a fixed function path */
+ if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) {
+ if (panfrost_blend_constant(
+ &final.equation.constant,
+ ctx->blend_color.color,
+ rt->constant_mask))
+ {
+ /* There's an equation and suitable constant, so we're good to go */
+ final.is_shader = false;
+ final.equation.equation = &rt->equation;
+ return final;
+ }
+ }
+
+ /* 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.shader.work_count = shader->work_count;
+
+ if (shader->patch_index) {
+ /* We have to specialize the blend shader to use constants, so
+ * patch in the current constants and upload to transient
+ * memory */
+
+ float *patch = (float *) (shader->shader.cpu + shader->patch_index);
+ memcpy(patch, ctx->blend_color.color, sizeof(float) * 4);
+
+ final.shader.gpu = panfrost_upload_transient(
+ ctx, shader->shader.cpu, shader->size);
+ } else {
+ /* No need to specialize further, use the preuploaded */
+ final.shader.gpu = shader->shader.gpu;
+ }
+
+ final.shader.gpu |= shader->first_tag;
+ return final;
+}
+
+void
+panfrost_blend_context_init(struct pipe_context *pipe)
+{
+ pipe->create_blend_state = panfrost_create_blend_state;
+ pipe->bind_blend_state = panfrost_bind_blend_state;
+ pipe->delete_blend_state = panfrost_delete_blend_state;
+
+ pipe->set_blend_color = panfrost_set_blend_color;
+}
diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.c b/src/gallium/drivers/panfrost/pan_blend_shaders.c
index 2b6206545b3..993b612ee50 100644
--- a/src/gallium/drivers/panfrost/pan_blend_shaders.c
+++ b/src/gallium/drivers/panfrost/pan_blend_shaders.c
@@ -29,6 +29,7 @@
#include "compiler/nir/nir_builder.h"
#include "midgard/nir_lower_blend.h"
#include "gallium/auxiliary/util/u_blend.h"
+#include "util/u_memory.h"
/*
* Implements the command stream portion of programmatic blend shaders.
@@ -124,13 +125,14 @@ nir_make_options(const struct pipe_blend_state *blend, unsigned nr_cbufs)
return options;
}
-void
-panfrost_make_blend_shader(
+struct panfrost_blend_shader
+panfrost_compile_blend_shader(
struct panfrost_context *ctx,
- struct panfrost_blend_state *cso,
- const struct pipe_blend_color *blend_color,
+ struct pipe_blend_state *cso,
enum pipe_format format)
{
+ struct panfrost_blend_shader res;
+
/* Build the shader */
nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
@@ -160,7 +162,7 @@ panfrost_make_blend_shader(
nir_store_var(b, c_out, s_src, 0xFF);
nir_lower_blend_options options =
- nir_make_options(&cso->base, 1);
+ nir_make_options(cso, 1);
NIR_PASS_V(shader, nir_lower_blend, options);
NIR_PASS_V(shader, nir_lower_framebuffer, format);
@@ -175,20 +177,16 @@ panfrost_make_blend_shader(
int size = program.compiled.size;
uint8_t *dst = program.compiled.data;
- /* Hot patch in constant color */
-
- if (program.blend_patch_offset >= 0) {
- float *hot_color = (float *) (dst + program.blend_patch_offset);
-
- for (int c = 0; c < 4; ++c)
- hot_color[c] = blend_color->color[c];
- }
+ res.shader.cpu = mem_dup(dst, size);
+ res.shader.gpu = panfrost_upload(&ctx->shaders, dst, size, true);
- cso->blend_shader = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag;
+ /* At least two work registers are needed due to an encoding quirk */
+ res.work_count = MAX2(program.work_register_count, 2);
- /* We need to switch to shader mode */
- cso->has_blend_shader = true;
+ /* Allow us to patch later */
+ res.patch_index = program.blend_patch_offset;
+ res.first_tag = program.first_tag;
+ res.size = size;
- /* At least two work registers are needed due to an encoding quirk */
- cso->blend_work_count = MAX2(program.work_register_count, 2);
+ return res;
}
diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.h b/src/gallium/drivers/panfrost/pan_blend_shaders.h
index 23acd39581a..1d2f090c4cc 100644
--- a/src/gallium/drivers/panfrost/pan_blend_shaders.h
+++ b/src/gallium/drivers/panfrost/pan_blend_shaders.h
@@ -29,12 +29,12 @@
#include "pipe/p_defines.h"
#include <panfrost-job.h>
#include "pan_context.h"
+#include "pan_blend.h"
-void
-panfrost_make_blend_shader(
+struct panfrost_blend_shader
+panfrost_compile_blend_shader(
struct panfrost_context *ctx,
- struct panfrost_blend_state *cso,
- const struct pipe_blend_color *blend_color,
+ struct pipe_blend_state *cso,
enum pipe_format format);
#endif
diff --git a/src/gallium/drivers/panfrost/pan_blending.c b/src/gallium/drivers/panfrost/pan_blending.c
index 6bdc8395d18..72eeb59280c 100644
--- a/src/gallium/drivers/panfrost/pan_blending.c
+++ b/src/gallium/drivers/panfrost/pan_blending.c
@@ -101,8 +101,8 @@
/* Not all formats can be blended by fixed-function hardware */
-static bool
-panfrost_can_blend(enum pipe_format format)
+bool
+panfrost_can_fixed_blend(enum pipe_format format)
{
/* Fixed-function can handle sRGB */
format = util_format_linear(format);
@@ -318,53 +318,24 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_
return true;
}
-/* We can upload a single constant for all of the factors. So, scan the factors
- * for constants used, and scan the constants for the constants used. If there
- * is a single unique constant, output that. If there are multiple,
- * fixed-function operation breaks down. */
+/* We can upload a single constant for all of the factors. So, scan
+ * the factors for constants used to create a mask to check later. */
-static bool
-panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, void *out)
+static unsigned
+panfrost_constant_mask(unsigned *factors, unsigned num_factors)
{
- /* Color components used */
- bool cc[4] = { false };
+ unsigned mask = 0;
for (unsigned i = 0; i < num_factors; ++i) {
unsigned factor = uncomplement_factor(factors[i]);
if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
- cc[0] = cc[1] = cc[2] = true;
+ mask |= 0b0111; /* RGB */
else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
- cc[3] = true;
- }
-
- /* Find the actual constant associated with the components used*/
-
- float constant = 0.0;
- bool has_constant = false;
-
- for (unsigned i = 0; i < 4; ++i) {
- /* If the component is unused, nothing to do */
- if (!cc[i]) continue;
-
- float value = blend_color->color[i];
-
- /* Either there's a second constant, in which case we fail, or
- * there's no constant / a first constant, in which case we use
- * that constant */
-
- if (has_constant && constant != value) {
- return false;
- } else {
- has_constant = true;
- constant = value;
- }
+ mask |= 0b1000; /* A */
}
- /* We have the constant -- success! */
-
- memcpy(out, &constant, sizeof(float));
- return true;
+ return mask;
}
/* Create the descriptor for a fixed blend mode given the corresponding Gallium
@@ -376,19 +347,13 @@ panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pip
bool
panfrost_make_fixed_blend_mode(
const struct pipe_rt_blend_state *blend,
- struct panfrost_blend_state *so,
- unsigned colormask,
- const struct pipe_blend_color *blend_color,
- enum pipe_format format)
+ struct mali_blend_equation *out,
+ unsigned *constant_mask,
+ unsigned colormask)
{
- struct mali_blend_equation *out = &so->equation;
-
- /* Check if the format supports fixed-function blending at all */
+ /* Gallium and Mali represent colour masks identically. XXX: Static
+ * assert for future proof */
- if (!panfrost_can_blend(format))
- return false;
-
- /* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */
out->color_mask = colormask;
/* If no blending is enabled, default back on `replace` mode */
@@ -399,16 +364,18 @@ panfrost_make_fixed_blend_mode(
return true;
}
- /* We have room only for a single float32 constant between the four
- * components. If we need more, spill to the programmable pipeline. */
+ /* At draw-time, we'll need to analyze the blend constant, so
+ * precompute a mask for it -- even if we don't end up able to use
+ * fixed-function blending */
unsigned factors[] = {
blend->rgb_src_factor, blend->rgb_dst_factor,
blend->alpha_src_factor, blend->alpha_dst_factor,
};
- if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &so->constant))
- return false;
+ *constant_mask = panfrost_constant_mask(factors, ARRAY_SIZE(factors));
+
+ /* Try to compile the actual fixed-function blend */
unsigned rgb_mode = 0;
unsigned alpha_mode = 0;
diff --git a/src/gallium/drivers/panfrost/pan_blending.h b/src/gallium/drivers/panfrost/pan_blending.h
index 4be0c4d4385..163237eed5e 100644
--- a/src/gallium/drivers/panfrost/pan_blending.h
+++ b/src/gallium/drivers/panfrost/pan_blending.h
@@ -31,11 +31,14 @@
struct panfrost_blend_state;
-bool panfrost_make_fixed_blend_mode(
+bool
+panfrost_make_fixed_blend_mode(
const struct pipe_rt_blend_state *blend,
- struct panfrost_blend_state *so,
- unsigned colormask,
- const struct pipe_blend_color *blend_color,
- enum pipe_format format);
+ struct mali_blend_equation *out,
+ unsigned *constant_mask,
+ unsigned colormask);
+
+bool
+panfrost_can_fixed_blend(enum pipe_format format);
#endif
diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
index c26a6dbaabb..69d877277be 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -1071,9 +1071,14 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
COPY(midgard1.unknown2);
#undef COPY
+
+ /* Get blending setup */
+ struct panfrost_blend_final blend =
+ panfrost_get_blend_for_context(ctx, 0);
+
/* If there is a blend shader, work registers are shared */
- if (ctx->blend->has_blend_shader)
+ 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;
/* Set late due to depending on render state */
@@ -1112,18 +1117,19 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
/* Check if we're using the default blend descriptor (fast path) */
bool no_blending =
- !ctx->blend->has_blend_shader &&
- (ctx->blend->equation.rgb_mode == 0x122) &&
- (ctx->blend->equation.alpha_mode == 0x122) &&
- (ctx->blend->equation.color_mask == 0xf);
+ !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 (ctx->blend->has_blend_shader) {
- ctx->fragment_shader_core.blend.shader = ctx->blend->blend_shader;
+ if (blend.is_shader) {
+ ctx->fragment_shader_core.blend.shader =
+ blend.shader.gpu;
} else {
ctx->fragment_shader_core.blend.shader = 0;
}
@@ -1134,9 +1140,11 @@ 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 (!ctx->blend->has_blend_shader) {
- ctx->fragment_shader_core.blend.equation = ctx->blend->equation;
- ctx->fragment_shader_core.blend.constant = ctx->blend->constant;
+ if (!blend.is_shader) {
+ ctx->fragment_shader_core.blend.equation =
+ *blend.equation.equation;
+ ctx->fragment_shader_core.blend.constant =
+ blend.equation.constant;
}
if (!no_blending) {
@@ -1155,13 +1163,13 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
unsigned blend_count = 0x200;
- if (ctx->blend->has_blend_shader) {
+ 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(ctx->blend->blend_work_count >= 2);
- blend_count |= MIN2(ctx->blend->blend_work_count, 3);
+ 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 */
@@ -1191,13 +1199,13 @@ 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 && ctx->blend->has_blend_shader));
+ assert(!(is_srgb && blend.is_shader));
- if (ctx->blend->has_blend_shader) {
- rts[i].blend.shader = ctx->blend->blend_shader;
+ if (blend.is_shader) {
+ rts[i].blend.shader = blend.shader.gpu;
} else {
- rts[i].blend.equation = ctx->blend->equation;
- rts[i].blend.constant = ctx->blend->constant;
+ rts[i].blend.equation = *blend.equation.equation;
+ rts[i].blend.constant = blend.equation.constant;
}
}
@@ -2364,88 +2372,6 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx,
}
static void *
-panfrost_create_blend_state(struct pipe_context *pipe,
- const struct pipe_blend_state *blend)
-{
- struct panfrost_context *ctx = pan_context(pipe);
- struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state);
- so->base = *blend;
-
- /* TODO: The following features are not yet implemented */
- assert(!blend->logicop_enable);
- assert(!blend->alpha_to_coverage);
- assert(!blend->alpha_to_one);
-
- /* Compile the blend state, first as fixed-function if we can */
-
- /* TODO: Key by format */
- enum pipe_format format = ctx->pipe_framebuffer.nr_cbufs ?
- ctx->pipe_framebuffer.cbufs[0]->format :
- PIPE_FORMAT_R8G8B8A8_UNORM;
-
- if (panfrost_make_fixed_blend_mode(&blend->rt[0], so, blend->rt[0].colormask, &ctx->blend_color, format))
- return so;
-
- /* If we can't, compile a blend shader instead */
-
- panfrost_make_blend_shader(ctx, so, &ctx->blend_color, format);
-
- return so;
-}
-
-static void
-panfrost_bind_blend_state(struct pipe_context *pipe,
- void *cso)
-{
- struct panfrost_context *ctx = pan_context(pipe);
- struct pipe_blend_state *blend = (struct pipe_blend_state *) cso;
- struct panfrost_blend_state *pblend = (struct panfrost_blend_state *) cso;
- ctx->blend = pblend;
-
- if (!blend)
- return;
-
- SET_BIT(ctx->fragment_shader_core.unknown2_4, MALI_NO_DITHER, !blend->dither);
-
- /* TODO: Attach color */
-
- /* Shader itself is not dirty, but the shader core is */
- ctx->dirty |= PAN_DIRTY_FS;
-}
-
-static void
-panfrost_delete_blend_state(struct pipe_context *pipe,
- void *blend)
-{
- struct panfrost_blend_state *so = (struct panfrost_blend_state *) blend;
-
- if (so->has_blend_shader) {
- DBG("Deleting blend state leak blend shaders bytecode\n");
- }
-
- ralloc_free(blend);
-}
-
-static void
-panfrost_set_blend_color(struct pipe_context *pipe,
- const struct pipe_blend_color *blend_color)
-{
- struct panfrost_context *ctx = pan_context(pipe);
-
- /* If blend_color is we're unbinding, so ctx->blend_color is now undefined -> nothing to do */
-
- if (blend_color) {
- ctx->blend_color = *blend_color;
-
- /* The blend mode depends on the blend constant color, due to the
- * fixed/programmable split. So, we're forced to regenerate the blend
- * equation */
-
- /* TODO: Attach color */
- }
-}
-
-static void *
panfrost_create_depth_stencil_state(struct pipe_context *pipe,
const struct pipe_depth_stencil_alpha_state *depth_stencil)
{
@@ -2795,12 +2721,6 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
gallium->delete_sampler_state = panfrost_generic_cso_delete;
gallium->bind_sampler_states = panfrost_bind_sampler_states;
- gallium->create_blend_state = panfrost_create_blend_state;
- gallium->bind_blend_state = panfrost_bind_blend_state;
- gallium->delete_blend_state = panfrost_delete_blend_state;
-
- gallium->set_blend_color = panfrost_set_blend_color;
-
gallium->create_depth_stencil_alpha_state = panfrost_create_depth_stencil_state;
gallium->bind_depth_stencil_alpha_state = panfrost_bind_depth_stencil_state;
gallium->delete_depth_stencil_alpha_state = panfrost_delete_depth_stencil_state;
@@ -2824,6 +2744,7 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
gallium->set_stream_output_targets = panfrost_set_stream_output_targets;
panfrost_resource_context_init(gallium);
+ panfrost_blend_context_init(gallium);
panfrost_drm_init_context(ctx);
diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h
index a913c8581ef..9b977ed59ec 100644
--- a/src/gallium/drivers/panfrost/pan_context.h
+++ b/src/gallium/drivers/panfrost/pan_context.h
@@ -31,6 +31,7 @@
#include <assert.h>
#include "pan_resource.h"
#include "pan_job.h"
+#include "pan_blend.h"
#include "pipe/p_compiler.h"
#include "pipe/p_config.h"
@@ -228,21 +229,6 @@ struct panfrost_rasterizer {
unsigned tiler_gl_enables;
};
-struct panfrost_blend_state {
- struct pipe_blend_state base;
-
- /* Whether a blend shader is in use */
- bool has_blend_shader;
-
- /* Compiled fixed function command */
- struct mali_blend_equation equation;
- float constant;
-
- /* Compiled blend shader */
- mali_ptr blend_shader;
- int blend_work_count;
-};
-
/* Variants bundle together to form the backing CSO, bundling multiple
* shaders with varying emulated features baked in (alpha test
* parameters, etc) */