panfrost: Implement opportunistic AFBC
Rather than hardcoding a BO layout at creation-time, we implement the ability to hint layouts at various points in a BO's lifetime, potentially reallocating and switching layouts if it's heuristically deemed useful to do so. In this patch, we add a simple hinting implementation, opportunistically compressing FBOs. Support is hidden behind PAN_MESA_DEBUG=afbc as the implementation is incomplete (software access to AFBC is unimplemented at the moment) and therefore would regress significantly. Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
This commit is contained in:
parent
d60994989e
commit
5ad00fb3ed
|
@ -2334,6 +2334,32 @@ panfrost_sampler_view_destroy(
|
|||
ralloc_free(view);
|
||||
}
|
||||
|
||||
/* Hints that a framebuffer should use AFBC where possible */
|
||||
|
||||
static void
|
||||
panfrost_hint_afbc(
|
||||
struct panfrost_screen *screen,
|
||||
const struct pipe_framebuffer_state *fb)
|
||||
{
|
||||
/* AFBC implemenation incomplete; hide it */
|
||||
if (!(pan_debug & PAN_DBG_AFBC)) return;
|
||||
|
||||
/* Hint AFBC to the resources bound to each color buffer */
|
||||
|
||||
for (unsigned i = 0; i < fb->nr_cbufs; ++i) {
|
||||
struct pipe_surface *surf = fb->cbufs[i];
|
||||
struct panfrost_resource *rsrc = pan_resource(surf->texture);
|
||||
panfrost_resource_hint_layout(screen, rsrc, PAN_AFBC, 1);
|
||||
}
|
||||
|
||||
/* Also hint it to the depth buffer */
|
||||
|
||||
if (fb->zsbuf) {
|
||||
struct panfrost_resource *rsrc = pan_resource(fb->zsbuf->texture);
|
||||
panfrost_resource_hint_layout(screen, rsrc, PAN_AFBC, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_set_framebuffer_state(struct pipe_context *pctx,
|
||||
const struct pipe_framebuffer_state *fb)
|
||||
|
@ -2379,6 +2405,11 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx,
|
|||
}
|
||||
|
||||
if (needs_reattach) {
|
||||
/* Given that we're rendering, we'd love to have compression */
|
||||
struct panfrost_screen *screen = pan_screen(ctx->base.screen);
|
||||
|
||||
panfrost_hint_afbc(screen, &ctx->pipe_framebuffer);
|
||||
|
||||
if (ctx->require_sfbd)
|
||||
ctx->vt_framebuffer_sfbd = panfrost_emit_sfbd(ctx, ~0);
|
||||
else
|
||||
|
|
|
@ -712,6 +712,66 @@ panfrost_get_texture_address(
|
|||
return rsrc->bo->gpu + level_offset + face_offset;
|
||||
}
|
||||
|
||||
/* Given a resource that has already been allocated, hint that it should use a
|
||||
* given layout. These are suggestions, not commands; it is perfectly legal to
|
||||
* stub out this function, but there will be performance implications. */
|
||||
|
||||
void
|
||||
panfrost_resource_hint_layout(
|
||||
struct panfrost_screen *screen,
|
||||
struct panfrost_resource *rsrc,
|
||||
enum panfrost_memory_layout layout,
|
||||
signed weight)
|
||||
{
|
||||
/* Nothing to do, although a sophisticated implementation might store
|
||||
* the hint */
|
||||
|
||||
if (rsrc->layout == layout)
|
||||
return;
|
||||
|
||||
/* We don't use the weight yet, but we should check that it's positive
|
||||
* (semantically meaning that we should choose the given `layout`) */
|
||||
|
||||
if (weight <= 0)
|
||||
return;
|
||||
|
||||
/* Check if the preferred layout is legal for this buffer */
|
||||
|
||||
if (layout == PAN_AFBC) {
|
||||
bool can_afbc = panfrost_format_supports_afbc(rsrc->base.format);
|
||||
bool is_scanout = rsrc->base.bind &
|
||||
(PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
|
||||
|
||||
if (!can_afbc || is_scanout)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Simple heuristic so far: if the resource is uninitialized, switch to
|
||||
* the hinted layout. If it is initialized, keep the original layout.
|
||||
* This misses some cases where it would be beneficial to switch and
|
||||
* blit. */
|
||||
|
||||
bool is_initialized = false;
|
||||
|
||||
for (unsigned i = 0; i < MAX_MIP_LEVELS; ++i)
|
||||
is_initialized |= rsrc->slices[i].initialized;
|
||||
|
||||
if (is_initialized)
|
||||
return;
|
||||
|
||||
/* We're uninitialized, so do a layout switch. Reinitialize slices. */
|
||||
|
||||
size_t new_size;
|
||||
rsrc->layout = layout;
|
||||
panfrost_setup_slices(rsrc, &new_size);
|
||||
|
||||
/* If we grew in size, reallocate the BO */
|
||||
if (new_size > rsrc->bo->size) {
|
||||
panfrost_drm_release_bo(screen, rsrc->bo, true);
|
||||
rsrc->bo = panfrost_drm_create_bo(screen, new_size, PAN_ALLOCATE_DELAY_MMAP);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_resource_set_stencil(struct pipe_resource *prsrc,
|
||||
struct pipe_resource *stencil)
|
||||
|
|
|
@ -112,6 +112,13 @@ void panfrost_resource_screen_init(struct panfrost_screen *screen);
|
|||
|
||||
void panfrost_resource_context_init(struct pipe_context *pctx);
|
||||
|
||||
void
|
||||
panfrost_resource_hint_layout(
|
||||
struct panfrost_screen *screen,
|
||||
struct panfrost_resource *rsrc,
|
||||
enum panfrost_memory_layout layout,
|
||||
signed weight);
|
||||
|
||||
/* AFBC */
|
||||
|
||||
bool
|
||||
|
|
|
@ -54,7 +54,7 @@ static const struct debug_named_value debug_options[] = {
|
|||
{"msgs", PAN_DBG_MSGS, "Print debug messages"},
|
||||
{"trace", PAN_DBG_TRACE, "Trace the command stream"},
|
||||
{"deqp", PAN_DBG_DEQP, "Hacks for dEQP"},
|
||||
/* ^^ If Rob can do it, so can I */
|
||||
{"afbc", PAN_DBG_AFBC, "Enable non-conformant AFBC impl"},
|
||||
DEBUG_NAMED_VALUE_END
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define PAN_DBG_MSGS 0x0001
|
||||
#define PAN_DBG_TRACE 0x0002
|
||||
#define PAN_DBG_DEQP 0x0004
|
||||
#define PAN_DBG_AFBC 0x0008
|
||||
|
||||
extern int pan_debug;
|
||||
|
||||
|
|
Loading…
Reference in New Issue