Module: Mesa Branch: main Commit: 0e15d5af81bba7c1e798cf10fc838988c86daafd URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=0e15d5af81bba7c1e798cf10fc838988c86daafd
Author: Daniel Stone <[email protected]> Date: Fri Aug 27 16:52:31 2021 +0100 fdno/resource: Rewrite layout selection for allocation The previous code had a number of errors, the most glaring of which was forcing linear when it was one of the possible layouts requested. When modifiers are being used, a list of _acceptable_ modifiers is supplied; it's up to the driver to then make a decision as to which it thinks is most optimal. Normally we would select between linear/tiled/UBWC in ascending order of preference according to what's possible, however we can't use a tiled layout with explicit modifiers as there is no modifier token defined for it. Rewrite the layout-selection mechanism to always try to do the most optimal thing. If the use flags force us to, or we have a shared resource without explicit modifiers, we use linear. Failing that, we use UBWC wherever possible; if this is not possible, we use tiled for internal resources only or linear for shared resources. v2 (Rob): respect FD_FORMAT_MOD_QCOM_TILED; do not print perf warning on user choice of disabling UBWC; v3: fix several issues breaking CI tests: revert removal of using MOD_INVALID in various places, and assume implicit modifiers if present; do not attempt to set UBWC flags when screen->tile_mode(prsc) falls back to LINEAR (e.g. for small mip-maps levels); use TILED for implicit modifier case with non-shared resources v4: fix unintended demotion of UBWC, i.e. only check QCOM_COMPRESSED modifier and demote UBWC to less optimal format when using explicit modifiers Signed-off-by: Daniel Stone <[email protected]> Tested-by: Heinrich Fink <[email protected]> Signed-off-by: Heinrich Fink <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12595> --- src/gallium/drivers/freedreno/freedreno_resource.c | 138 +++++++++++++-------- 1 file changed, 89 insertions(+), 49 deletions(-) diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index 9c90055038f..cc4d15f5d60 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -1118,6 +1118,87 @@ alloc_resource_struct(struct pipe_screen *pscreen, return rsc; } +enum fd_layout_type { + ERROR, + LINEAR, + TILED, + UBWC, +}; + +static enum fd_layout_type +get_best_layout(struct fd_screen *screen, struct pipe_resource *prsc, + const struct pipe_resource *tmpl, const uint64_t *modifiers, + int count) +{ + bool implicit_modifiers = + (count == 0 || + drm_find_modifier(DRM_FORMAT_MOD_INVALID, modifiers, count)); + + /* First, find all the conditions which would force us to linear */ + if (!screen->tile_mode) + return LINEAR; + + if (!screen->tile_mode(prsc)) + return LINEAR; + + if (tmpl->target == PIPE_BUFFER) + return LINEAR; + + if (tmpl->bind & PIPE_BIND_LINEAR) { + if (tmpl->usage != PIPE_USAGE_STAGING) + perf_debug("%" PRSC_FMT ": forcing linear: bind flags", + PRSC_ARGS(prsc)); + return LINEAR; + } + + if (FD_DBG(NOTILE)) + return LINEAR; + + /* Shared resources with implicit modifiers must always be linear */ + if (implicit_modifiers && (tmpl->bind & PIPE_BIND_SHARED)) { + perf_debug("%" PRSC_FMT + ": forcing linear: shared resource + implicit modifiers", + PRSC_ARGS(prsc)); + return LINEAR; + } + + bool ubwc_ok = is_a6xx(screen); + if (FD_DBG(NOUBWC)) + ubwc_ok = false; + + if (ubwc_ok && !implicit_modifiers && + !drm_find_modifier(DRM_FORMAT_MOD_QCOM_COMPRESSED, modifiers, count)) { + perf_debug("%" PRSC_FMT + ": not using UBWC: not in acceptable modifier set", + PRSC_ARGS(prsc)); + ubwc_ok = false; + } + + if (ubwc_ok) + return UBWC; + + /* We can't use tiled with explicit modifiers, as there is no modifier token + * defined for it. But we might internally force tiled allocation using a + * private modifier token. + * + * TODO we should probably also limit TILED in a similar way to UBWC above, + * once we have a public modifier token defined. + */ + if (implicit_modifiers || + drm_find_modifier(FD_FORMAT_MOD_QCOM_TILED, modifiers, count)) + return TILED; + + if (!drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count)) { + perf_debug("%" PRSC_FMT ": need linear but not in modifier set", + PRSC_ARGS(prsc)); + return ERROR; + } + + perf_debug("%" PRSC_FMT ": not using tiling: explicit modifiers and no UBWC", + PRSC_ARGS(prsc)); + return LINEAR; +} + /** * Helper that allocates a resource and resolves its layout (but doesn't * allocate its bo). @@ -1150,61 +1231,20 @@ fd_resource_allocate_and_resolve(struct pipe_screen *pscreen, fd_resource_layout_init(prsc); -#define LINEAR (PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR | PIPE_BIND_DISPLAY_TARGET) - - bool linear = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count); - if (linear) { - perf_debug("%" PRSC_FMT ": linear: DRM_FORMAT_MOD_LINEAR requested!", - PRSC_ARGS(prsc)); - } else if (tmpl->bind & LINEAR) { - if (tmpl->usage != PIPE_USAGE_STAGING) - perf_debug("%" PRSC_FMT ": linear: LINEAR bind requested!", - PRSC_ARGS(prsc)); - linear = true; - } - - if (FD_DBG(NOTILE)) - linear = true; - - /* Normally, for non-shared buffers, allow buffer compression if - * not shared, otherwise only allow if QCOM_COMPRESSED modifier - * is requested: - * - * TODO we should probably also limit tiled in a similar way, - * except we don't have a format modifier for tiled. (We probably - * should.) - */ - bool allow_ubwc = false; - if (!linear) { - allow_ubwc = drm_find_modifier(DRM_FORMAT_MOD_INVALID, modifiers, count); - if (!allow_ubwc) { - perf_debug("%" PRSC_FMT - ": not UBWC: DRM_FORMAT_MOD_INVALID not requested!", - PRSC_ARGS(prsc)); - } - if (tmpl->bind & PIPE_BIND_SHARED) { - allow_ubwc = - drm_find_modifier(DRM_FORMAT_MOD_QCOM_COMPRESSED, modifiers, count); - if (!allow_ubwc) { - perf_debug("%" PRSC_FMT - ": not UBWC: shared and DRM_FORMAT_MOD_QCOM_COMPRESSED " - "not requested!", - PRSC_ARGS(prsc)); - linear = true; - } - } + enum fd_layout_type layout = + get_best_layout(screen, prsc, tmpl, modifiers, count); + if (layout == ERROR) { + free(prsc); + return NULL; } - allow_ubwc &= !FD_DBG(NOUBWC); - - if (screen->tile_mode && (tmpl->target != PIPE_BUFFER) && !linear) { + if (layout >= TILED) rsc->layout.tile_mode = screen->tile_mode(prsc); - } + if (layout == UBWC) + rsc->layout.ubwc = true; rsc->internal_format = format; - rsc->layout.ubwc = rsc->layout.tile_mode && is_a6xx(screen) && allow_ubwc; - if (prsc->target == PIPE_BUFFER) { assert(prsc->format == PIPE_FORMAT_R8_UNORM); size = prsc->width0;
