#include <stdio.h>
#include "util/u_memory.h"
+#include "gallium/auxiliary/util/u_blend.h"
#include "pan_blend_shaders.h"
#include "pan_blending.h"
+#include "pan_bo.h"
+#include "panfrost-quirks.h"
/* A given Gallium blend state can be encoded to the hardware in numerous,
* dramatically divergent ways due to the interactions of blending with
* befast, suitable for calling every draw to avoid wacky dirty
* tracking paths. If the cache hits, boom, done. */
-static struct panfrost_blend_shader *
+struct panfrost_blend_shader *
panfrost_get_blend_shader(
- struct panfrost_context *ctx,
- struct panfrost_blend_state *blend,
- enum pipe_format fmt,
- unsigned rt)
+ 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 */
+ /* Check the cache. Key by the RT and format */
struct hash_table_u64 *shaders = blend->rt[rt].shaders;
+ unsigned key = (fmt << 3) | rt;
struct panfrost_blend_shader *shader =
- _mesa_hash_table_u64_search(shaders, fmt);
+ _mesa_hash_table_u64_search(shaders, key);
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);
+ panfrost_compile_blend_shader(ctx, &blend->base, fmt, rt);
shader = mem_dup(&generated, sizeof(generated));
- _mesa_hash_table_u64_insert(shaders, fmt, shader);
+ _mesa_hash_table_u64_insert(shaders, key, shader);
return shader;
}
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) {
+ for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
+ unsigned g = blend->independent_blend_enable ? c : 0;
+ struct pipe_rt_blend_state pipe = blend->rt[g];
+
struct panfrost_blend_rt *rt = &so->rt[c];
+ rt->shaders = _mesa_hash_table_u64_create(so);
- /* There are two paths. First, we would like to try a
- * fixed-function if we can */
+ /* Logic ops are always shader */
+ if (blend->logicop_enable) {
+ rt->load_dest = true;
+ continue;
+ }
rt->has_fixed_function =
- panfrost_make_fixed_blend_mode(
- &blend->rt[c],
+ panfrost_make_fixed_blend_mode(
+ pipe,
&rt->equation,
- &rt->constant_mask,
- blend->rt[c].colormask);
+ &rt->constant_mask);
+
+ if (rt->has_fixed_function)
+ rt->opaque = (rt->equation.opaque[0] == 0xf0122122);
- /* Regardless if that works, we also need to initialize
- * the blend shaders */
+ rt->load_dest = util_blend_uses_dest(pipe)
+ || pipe.colormask != 0xF;
- rt->shaders = _mesa_hash_table_u64_create(NULL);
+ rt->no_colour = pipe.colormask == 0x0;
}
return so;
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);
+ ctx->blend = (struct panfrost_blend_state *) cso;
+}
- /* 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
panfrost_delete_blend_state(struct pipe_context *pipe,
- void *blend)
+ void *cso)
{
- /* TODO: leaks internally? */
+ struct panfrost_blend_state *blend = (struct panfrost_blend_state *) cso;
+ for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
+ struct panfrost_blend_rt *rt = &blend->rt[c];
+ _mesa_hash_table_u64_clear(rt->shaders, panfrost_delete_blend_shader);
+ }
ralloc_free(blend);
}
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 there is no components used, it automatically works */
- if (!mask) {
- *out = 0.0;
+ if (!mask)
return true;
- }
/* Find some starter mask */
unsigned first = ffs(mask) - 1;
while (mask) {
unsigned i = u_bit_scan(&mask);
- if (in[i] != cons) {
- *out = 0.0;
+ if (in[i] != cons)
return false;
- }
}
/* Otherwise, we're good to go */
struct panfrost_blend_final
panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
{
- /* Grab the format */
+ struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
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 */
+ /* First, we'll try fixed function, matching equationn and constant */
if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) {
+ float constant = 0.0;
+
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;
+ &constant,
+ ctx->blend_color.color,
+ rt->constant_mask)) {
+ struct panfrost_blend_final final = {
+ .equation = {
+ .equation = rt->equation,
+ .constant = constant
+ },
+ .load_dest = rt->load_dest,
+ .opaque = rt->opaque,
+ .no_colour = rt->no_colour
+ };
+
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;
+
+ struct panfrost_bo *bo = panfrost_batch_create_bo(batch, shader->size,
+ PAN_BO_EXECUTE,
+ PAN_BO_ACCESS_PRIVATE |
+ PAN_BO_ACCESS_READ |
+ PAN_BO_ACCESS_FRAGMENT);
+
+ memcpy(bo->cpu, shader->buffer, shader->size);
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);
+ * patch in the current constants */
- 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;
+ float *patch = (float *) (bo->cpu + shader->patch_index);
+ memcpy(patch, ctx->blend_color.color, sizeof(float) * 4);
}
- final.shader.gpu |= shader->first_tag;
+ struct panfrost_blend_final final = {
+ .is_shader = true,
+ .shader = {
+ .work_count = shader->work_count,
+ .first_tag = shader->first_tag,
+ .gpu = bo->gpu,
+ },
+ .load_dest = rt->load_dest,
+ };
+
return final;
}