summaryrefslogtreecommitdiff
path: root/lib/mesa/src/gallium/drivers/panfrost
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2020-01-22 02:13:10 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2020-01-22 02:13:10 +0000
commit2ebab484cac65c01dd19e8c1b62eb58c83074390 (patch)
treed5decbcdfb7743214078cb8e0b0372a59c2ca6d6 /lib/mesa/src/gallium/drivers/panfrost
parentc5f75a531a75824f9087ebabbb1d9ff34a17d110 (diff)
Import Mesa 19.2.8
Diffstat (limited to 'lib/mesa/src/gallium/drivers/panfrost')
-rw-r--r--lib/mesa/src/gallium/drivers/panfrost/pan_blend_cso.c253
1 files changed, 171 insertions, 82 deletions
diff --git a/lib/mesa/src/gallium/drivers/panfrost/pan_blend_cso.c b/lib/mesa/src/gallium/drivers/panfrost/pan_blend_cso.c
index 157c23491..43121335f 100644
--- a/lib/mesa/src/gallium/drivers/panfrost/pan_blend_cso.c
+++ b/lib/mesa/src/gallium/drivers/panfrost/pan_blend_cso.c
@@ -27,11 +27,8 @@
#include <stdio.h>
#include "util/u_memory.h"
-#include "gallium/auxiliary/util/u_blend.h"
-#include "pan_context.h"
-#include "pan_blend_cso.h"
-#include "pan_bo.h"
-#include "panfrost-quirks.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
@@ -60,6 +57,41 @@
* (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 */
@@ -71,34 +103,33 @@ panfrost_create_blend_state(struct pipe_context *pipe,
struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state);
so->base = *blend;
- so->pan.dither = blend->dither;
- so->pan.logicop_enable = blend->logicop_enable;
- so->pan.logicop_func = blend->logicop_func;
- so->pan.rt_count = blend->max_rt + 1;
-
/* 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 < so->pan.rt_count; ++c) {
- unsigned g = blend->independent_blend_enable ? c : 0;
- const struct pipe_rt_blend_state *pipe = &blend->rt[g];
- struct pan_blend_equation *equation = &so->pan.rts[c].equation;
-
- equation->color_mask = pipe->colormask;
- equation->blend_enable = pipe->blend_enable;
- if (!equation->blend_enable)
- continue;
-
- equation->rgb_func = util_blend_func_to_shader(pipe->rgb_func);
- equation->rgb_src_factor = util_blend_factor_to_shader(pipe->rgb_src_factor);
- equation->rgb_invert_src_factor = util_blend_factor_is_inverted(pipe->rgb_src_factor);
- equation->rgb_dst_factor = util_blend_factor_to_shader(pipe->rgb_dst_factor);
- equation->rgb_invert_dst_factor = util_blend_factor_is_inverted(pipe->rgb_dst_factor);
- equation->alpha_func = util_blend_func_to_shader(pipe->alpha_func);
- equation->alpha_src_factor = util_blend_factor_to_shader(pipe->alpha_src_factor);
- equation->alpha_invert_src_factor = util_blend_factor_is_inverted(pipe->alpha_src_factor);
- equation->alpha_dst_factor = util_blend_factor_to_shader(pipe->alpha_dst_factor);
- equation->alpha_invert_dst_factor = util_blend_factor_is_inverted(pipe->alpha_dst_factor);
+ 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[g],
+ &rt->equation,
+ &rt->constant_mask,
+ blend->rt[g].colormask);
+
+ /* Regardless if that works, we also need to initialize
+ * the blend shaders */
+
+ rt->shaders = _mesa_hash_table_u64_create(so);
}
return so;
@@ -109,7 +140,28 @@ panfrost_bind_blend_state(struct pipe_context *pipe,
void *cso)
{
struct panfrost_context *ctx = pan_context(pipe);
- ctx->blend = (struct panfrost_blend_state *) cso;
+ struct panfrost_screen *screen = pan_screen(ctx->base.screen);
+ 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;
+
+ if (screen->require_sfbd) {
+ 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_shader(struct hash_entry *entry)
+{
+ struct panfrost_blend_shader *shader = (struct panfrost_blend_shader *)entry->data;
+ free(shader->buffer);
+ free(shader);
}
static void
@@ -117,6 +169,11 @@ panfrost_delete_blend_state(struct pipe_context *pipe,
void *cso)
{
struct panfrost_blend_state *blend = (struct panfrost_blend_state *) cso;
+
+ for (unsigned c = 0; c < 4; ++c) {
+ struct panfrost_blend_rt *rt = &blend->rt[c];
+ _mesa_hash_table_u64_clear(rt->shaders, panfrost_delete_blend_shader);
+ }
ralloc_free(blend);
}
@@ -130,73 +187,105 @@ panfrost_set_blend_color(struct pipe_context *pipe,
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, struct panfrost_bo **bo, unsigned *shader_offset)
+panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
{
- struct panfrost_device *dev = pan_device(ctx->base.screen);
- struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
+ struct panfrost_screen *screen = pan_screen(ctx->base.screen);
+ struct panfrost_job *job = panfrost_get_job_for_fbo(ctx);
+
+ /* Grab the format, falling back gracefully if called invalidly (which
+ * has to happen for no-color-attachment FBOs, for instance) */
struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
- enum pipe_format fmt = fb->cbufs[rti]->format;
- unsigned nr_samples = fb->cbufs[rti]->nr_samples ? :
- fb->cbufs[rti]->texture->nr_samples;
+ enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
+
+ if ((fb->nr_cbufs > rti) && fb->cbufs[rti])
+ fmt = fb->cbufs[rti]->format;
/* Grab the blend state */
struct panfrost_blend_state *blend = ctx->blend;
- struct pan_blend_state pan_blend = blend->pan;
-
- pan_blend.rts[rti].format = fmt;
- pan_blend.rts[rti].nr_samples = nr_samples;
- memcpy(pan_blend.constants, ctx->blend_color.color,
- sizeof(pan_blend.constants));
-
- /* First, we'll try fixed function, matching equation and constant */
- if (pan_blend_can_fixed_function(dev, &pan_blend, rti)) {
- struct panfrost_blend_final final = {
- .load_dest = pan_blend_reads_dest(pan_blend.rts[rti].equation),
- .equation.constant = pan_blend_get_constant(dev, &pan_blend, rti),
- .opaque = pan_blend_is_opaque(pan_blend.rts[rti].equation),
- .no_colour = pan_blend.rts[rti].equation.color_mask == 0,
- };
-
- pan_blend_to_fixed_function_equation(dev, &pan_blend, rti,
- &final.equation.equation);
- return final;
- }
+ assert(blend);
+ struct panfrost_blend_rt *rt = &blend->rt[rti];
- /* Otherwise, we need to grab a shader */
- /* Upload the shader, sharing a BO */
- if (!(*bo)) {
- *bo = panfrost_batch_create_bo(batch, 4096,
- PAN_BO_EXECUTE,
- PAN_BO_ACCESS_PRIVATE |
- PAN_BO_ACCESS_READ |
- PAN_BO_ACCESS_FRAGMENT);
+ 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;
+
+ final.no_blending =
+ (rt->equation.rgb_mode == 0x122) &&
+ (rt->equation.alpha_mode == 0x122) &&
+ (rt->equation.color_mask == 0xf);
+
+ return final;
+ }
}
- pthread_mutex_lock(&dev->blend_shaders.lock);
- struct pan_blend_shader_variant *shader =
- pan_blend_get_shader_locked(dev, &pan_blend, 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;
- /* Size check */
- assert((*shader_offset + shader->binary.size) < 4096);
+ /* Upload the shader */
+ final.shader.bo = panfrost_drm_create_bo(screen, shader->size, PAN_ALLOCATE_EXECUTE);
+ memcpy(final.shader.bo->cpu, shader->buffer, shader->size);
- memcpy((*bo)->ptr.cpu + *shader_offset, shader->binary.data, shader->binary.size);
+ /* Pass BO ownership to job */
+ panfrost_job_add_bo(job, final.shader.bo);
+ panfrost_bo_unreference(ctx->base.screen, final.shader.bo);
- struct panfrost_blend_final final = {
- .is_shader = true,
- .shader = {
- .first_tag = shader->first_tag,
- .gpu = (*bo)->ptr.gpu + *shader_offset,
- },
- .load_dest = pan_blend.logicop_enable ||
- pan_blend_reads_dest(pan_blend.rts[rti].equation),
- };
+ if (shader->patch_index) {
+ /* We have to specialize the blend shader to use constants, so
+ * patch in the current constants */
- *shader_offset += shader->binary.size;
- pthread_mutex_unlock(&dev->blend_shaders.lock);
+ float *patch = (float *) (final.shader.bo->cpu + shader->patch_index);
+ memcpy(patch, ctx->blend_color.color, sizeof(float) * 4);
+ }
return final;
}