panfrost: Flip point coords in hardware

On Bifrost, this is very easy: there's an RSD bit to Y-flip gl_PointCoord. It
should map perfectly to the Gallium bit. With this change, we no longer use
lower_pntc_ytransform on Bifrost, saving a bit of ALU when reading point
coordinates.

On Valhall, this is quite hard: the bit is in the framebuffer descriptor now!
That means it can't be changed in a batch. This is expected to be ok: on GLES
and VK, the origin is controlled only by the framebuffer orientation. It's a
bigger problem on big GL, where GL_POINT_SPRITE_COORD_ORIGIN can be set freely.
To cope, a tri-state data structure is used for the state tracking. This has a
failure case on Valhall: every draw toggling the coord origin. However, the
intention of the ORIGIN state bit is smoothing over coordinate system
differences; it should never /actually/ change once set. Until we see an app
doing something so stupid, I don't think we should worry about.

We need all the Valhall tri-state infrastructure for handling provoking vertices
on big GL anyway.

Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16173>
This commit is contained in:
Alyssa Rosenzweig 2022-05-02 09:19:41 -04:00
parent 5bab8e6cbe
commit 3641dfe436
6 changed files with 85 additions and 9 deletions

View File

@ -573,6 +573,13 @@ panfrost_prepare_fs_state(struct panfrost_context *ctx,
cfg.multisample_misc.evaluate_per_sample = true;
cfg.preload.fragment.sample_mask_id = true;
}
/* Flip gl_PointCoord (and point sprites) depending on API
* setting on framebuffer orientation. We do not use
* lower_wpos_pntc on Bifrost.
*/
cfg.properties.point_sprite_coord_origin_max_y =
(rast->sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT);
#endif
cfg.stencil_mask_misc.alpha_to_coverage = alpha_to_coverage;
@ -3780,6 +3787,21 @@ panfrost_indirect_draw(struct panfrost_batch *batch,
}
#endif
static bool
panfrost_compatible_batch_state(struct panfrost_batch *batch)
{
/* Only applies on Valhall */
if (PAN_ARCH < 9)
return true;
struct panfrost_context *ctx = batch->ctx;
struct pipe_rasterizer_state *rast = &ctx->rasterizer->base;
bool coord = (rast->sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT);
return pan_tristate_set(&batch->sprite_coord_origin, coord);
}
static void
panfrost_draw_vbo(struct pipe_context *pipe,
const struct pipe_draw_info *info,
@ -3810,6 +3832,9 @@ panfrost_draw_vbo(struct pipe_context *pipe,
if (unlikely(batch->scoreboard.job_index > 10000))
batch = panfrost_get_fresh_batch_for_fbo(ctx, "Too many draws");
if (unlikely(!panfrost_compatible_batch_state(batch)))
batch = panfrost_get_fresh_batch_for_fbo(ctx, "State change");
/* panfrost_batch_skip_rasterization reads
* batch->scissor_culls_everything, which is set by
* panfrost_emit_viewport, so call that first.
@ -4371,14 +4396,7 @@ prepare_shader(struct panfrost_shader_state *state,
pan_pack(out, RENDERER_STATE, cfg) {
pan_shader_prepare_rsd(&state->info, state->bin.gpu, &cfg);
#if PAN_ARCH >= 6
/* Match the mesa/st convention. If this needs to be flipped,
* nir_lower_pntc_ytransform will do so.
*/
if (state->info.stage == MESA_SHADER_FRAGMENT)
cfg.properties.point_sprite_coord_origin_max_y = true;
#endif
}
}
#else
assert(upload);

View File

@ -435,6 +435,7 @@ panfrost_batch_to_fb_info(const struct panfrost_batch *batch,
fb->extent.maxy = batch->maxy - 1;
fb->nr_samples = util_framebuffer_get_num_samples(&batch->key);
fb->rt_count = batch->key.nr_cbufs;
fb->sprite_coord_origin = pan_tristate_get(batch->sprite_coord_origin);
static const unsigned char id_swz[] = {
PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W,

View File

@ -33,6 +33,52 @@
#include "pan_resource.h"
#include "pan_scoreboard.h"
/* Simple tri-state data structure. In the default "don't care" state, the value
* may be set to true or false. However, once the value is set, it must not be
* changed. Declared inside of a struct to prevent casting to bool, which is an
* error. The getter needs to be used instead.
*/
struct pan_tristate {
enum {
PAN_TRISTATE_DONTCARE,
PAN_TRISTATE_FALSE,
PAN_TRISTATE_TRUE,
} v;
};
/*
* Try to set a tristate value to a desired boolean value. Returns whether the
* operation is successful.
*/
static bool
pan_tristate_set(struct pan_tristate *state, bool value)
{
switch (state->v) {
case PAN_TRISTATE_DONTCARE:
state->v = value ? PAN_TRISTATE_TRUE : PAN_TRISTATE_FALSE;
return true;
case PAN_TRISTATE_FALSE:
return (value == false);
case PAN_TRISTATE_TRUE:
return (value == true);
default:
unreachable("Invalid tristate value");
}
}
/*
* Read the boolean value of a tristate. Return value undefined in the don't
* care state.
*/
static bool
pan_tristate_get(struct pan_tristate state)
{
return (state.v == PAN_TRISTATE_TRUE);
}
/* A panfrost_batch corresponds to a bound FBO we're rendering to,
* collecting over multiple draws. */
@ -141,6 +187,11 @@ struct panfrost_batch {
*/
mali_ptr images[PIPE_SHADER_TYPES];
/* On Valhall, these are properties of the batch. On Bifrost, they are
* per draw.
*/
struct pan_tristate sprite_coord_origin;
/* Referenced resources */
struct set *resources;
};

View File

@ -48,7 +48,6 @@ static const nir_shader_compiler_options bifrost_nir_options = {
.lower_fdph = true,
.lower_fsqrt = true,
.lower_wpos_pntc = true,
.lower_fsign = true,
.lower_bitfield_insert_to_shifts = true,

View File

@ -690,6 +690,10 @@ GENX(pan_emit_fbd)(const struct panfrost_device *dev,
*valid |= full;
}
#if PAN_ARCH >= 9
cfg.point_sprite_coord_origin_max_y = fb->sprite_coord_origin;
#endif
}
#if PAN_ARCH >= 6

View File

@ -117,6 +117,9 @@ struct pan_fb_info {
union {
struct pan_fb_bifrost_info bifrost;
};
/* Only used on Valhall */
bool sprite_coord_origin;
};
static inline unsigned