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);
|
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
|
static void
|
||||||
panfrost_set_framebuffer_state(struct pipe_context *pctx,
|
panfrost_set_framebuffer_state(struct pipe_context *pctx,
|
||||||
const struct pipe_framebuffer_state *fb)
|
const struct pipe_framebuffer_state *fb)
|
||||||
|
@ -2379,6 +2405,11 @@ panfrost_set_framebuffer_state(struct pipe_context *pctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_reattach) {
|
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)
|
if (ctx->require_sfbd)
|
||||||
ctx->vt_framebuffer_sfbd = panfrost_emit_sfbd(ctx, ~0);
|
ctx->vt_framebuffer_sfbd = panfrost_emit_sfbd(ctx, ~0);
|
||||||
else
|
else
|
||||||
|
|
|
@ -712,6 +712,66 @@ panfrost_get_texture_address(
|
||||||
return rsrc->bo->gpu + level_offset + face_offset;
|
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
|
static void
|
||||||
panfrost_resource_set_stencil(struct pipe_resource *prsrc,
|
panfrost_resource_set_stencil(struct pipe_resource *prsrc,
|
||||||
struct pipe_resource *stencil)
|
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_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 */
|
/* AFBC */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -54,7 +54,7 @@ static const struct debug_named_value debug_options[] = {
|
||||||
{"msgs", PAN_DBG_MSGS, "Print debug messages"},
|
{"msgs", PAN_DBG_MSGS, "Print debug messages"},
|
||||||
{"trace", PAN_DBG_TRACE, "Trace the command stream"},
|
{"trace", PAN_DBG_TRACE, "Trace the command stream"},
|
||||||
{"deqp", PAN_DBG_DEQP, "Hacks for dEQP"},
|
{"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
|
DEBUG_NAMED_VALUE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define PAN_DBG_MSGS 0x0001
|
#define PAN_DBG_MSGS 0x0001
|
||||||
#define PAN_DBG_TRACE 0x0002
|
#define PAN_DBG_TRACE 0x0002
|
||||||
#define PAN_DBG_DEQP 0x0004
|
#define PAN_DBG_DEQP 0x0004
|
||||||
|
#define PAN_DBG_AFBC 0x0008
|
||||||
|
|
||||||
extern int pan_debug;
|
extern int pan_debug;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue