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>
This commit is contained in:
Alyssa Rosenzweig
2019-07-05 15:40:08 -07:00
parent c9af7701d1
commit 46396af1ec
9 changed files with 456 additions and 203 deletions

View File

@@ -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',

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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];
}
cso->blend_shader = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag;
/* We need to switch to shader mode */
cso->has_blend_shader = true;
res.shader.cpu = mem_dup(dst, size);
res.shader.gpu = panfrost_upload(&ctx->shaders, dst, size, true);
/* At least two work registers are needed due to an encoding quirk */
cso->blend_work_count = MAX2(program.work_register_count, 2);
res.work_count = MAX2(program.work_register_count, 2);
/* Allow us to patch later */
res.patch_index = program.blend_patch_offset;
res.first_tag = program.first_tag;
res.size = size;
return res;
}

View File

@@ -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

View File

@@ -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;
mask |= 0b1000; /* A */
}
/* 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;
}
}
/* 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;
/* Gallium and Mali represent colour masks identically. XXX: Static
* assert for future proof */
/* Check if the format supports fixed-function blending at all */
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;

View File

@@ -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

View File

@@ -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;
}
}
@@ -2363,88 +2371,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);

View File

@@ -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) */