diff options
author | Lucas Stach <l.stach@pengutronix.de> | 2017-06-22 15:14:31 +0200 |
---|---|---|
committer | Lucas Stach <l.stach@pengutronix.de> | 2017-07-19 16:26:50 +0200 |
commit | 58c3ce071c28b2d132cb15e309b3168953d957bd (patch) | |
tree | 3e17f70ae68082b36a2b1703f4753a7ba9813bf6 | |
parent | d06cfaf4fc21d45d09045af9ea2a248ef3968767 (diff) |
etnaviv: implement resource creation with modifier
This allows to create buffers with a specific tiling layout, which is primarily
used by GBM to allocate the EGL back buffers with the correct tiling/modifier
for use with the scanout engines.
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_resource.c | 95 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_resource.h | 2 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_texture.c | 5 | ||||
-rw-r--r-- | src/gallium/drivers/etnaviv/etnaviv_transfer.c | 5 |
4 files changed, 100 insertions, 7 deletions
diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index 63ed8bacf0..d6cccd2dbb 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -179,7 +179,7 @@ setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY, /* Create a new resource object, using the given template info */ struct pipe_resource * etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, - const struct pipe_resource *templat) + uint64_t modifier, const struct pipe_resource *templat) { struct etna_screen *screen = etna_screen(pscreen); struct etna_resource *rsc; @@ -231,8 +231,11 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, struct winsys_handle handle; /* pad scanout buffer size to be compatible with the RS */ - etna_adjust_rs_align(screen->specs.pixel_pipes, - &scanout_templat.width0, &scanout_templat.height0); + if (modifier == DRM_FORMAT_MOD_LINEAR) + etna_adjust_rs_align(screen->specs.pixel_pipes, &paddingX, &paddingY); + + scanout_templat.width0 = align(scanout_templat.width0, paddingX); + scanout_templat.height0 = align(scanout_templat.height0, paddingY); scanout = renderonly_scanout_for_resource(&scanout_templat, screen->ro, &handle); @@ -240,6 +243,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, return NULL; assert(handle.type == DRM_API_HANDLE_TYPE_FD); + handle.modifier = modifier; rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat, &handle, PIPE_HANDLE_USAGE_WRITE)); @@ -344,7 +348,89 @@ etna_resource_create(struct pipe_screen *pscreen, if (templat->target == PIPE_TEXTURE_3D) layout = ETNA_LAYOUT_LINEAR; - return etna_resource_alloc(pscreen, layout, templat); + /* modifier is only used for scanout surfaces, so safe to use LINEAR here */ + return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat); +} + +enum modifier_priority { + MODIFIER_PRIORITY_INVALID = 0, + MODIFIER_PRIORITY_LINEAR, + MODIFIER_PRIORITY_SPLIT_TILED, + MODIFIER_PRIORITY_SPLIT_SUPER_TILED, + MODIFIER_PRIORITY_TILED, + MODIFIER_PRIORITY_SUPER_TILED, +}; + +const uint64_t priority_to_modifier[] = { + [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, + [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, + [MODIFIER_PRIORITY_SPLIT_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED, + [MODIFIER_PRIORITY_SPLIT_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED, + [MODIFIER_PRIORITY_TILED] = DRM_FORMAT_MOD_VIVANTE_TILED, + [MODIFIER_PRIORITY_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SUPER_TILED, +}; + +static uint64_t +select_best_modifier(const struct etna_screen * screen, + const uint64_t *modifiers, const unsigned count) +{ + enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; + + for (int i = 0; i < count; i++) { + switch (modifiers[i]) { + case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: + if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) || + !screen->specs.can_supertile) + break; + prio = MAX2(prio, MODIFIER_PRIORITY_SUPER_TILED); + break; + case DRM_FORMAT_MOD_VIVANTE_TILED: + if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) + break; + prio = MAX2(prio, MODIFIER_PRIORITY_TILED); + break; + case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: + if ((screen->specs.pixel_pipes < 2) || !screen->specs.can_supertile) + break; + prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_SUPER_TILED); + break; + case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: + if (screen->specs.pixel_pipes < 2) + break; + prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_TILED); + break; + case DRM_FORMAT_MOD_LINEAR: + prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); + break; + case DRM_FORMAT_MOD_INVALID: + default: + break; + } + } + + return priority_to_modifier[prio]; +} + +static struct pipe_resource * +etna_resource_create_modifiers(struct pipe_screen *pscreen, + const struct pipe_resource *templat, + const uint64_t *modifiers, int count) +{ + struct etna_screen *screen = etna_screen(pscreen); + struct pipe_resource tmpl = *templat; + uint64_t modifier = select_best_modifier(screen, modifiers, count); + + if (modifier == DRM_FORMAT_MOD_INVALID) + return NULL; + + /* + * We currently assume that all buffers allocated through this interface + * should be scanout enabled. + */ + tmpl.bind |= PIPE_BIND_SCANOUT; + + return etna_resource_alloc(pscreen, modifier_to_layout(modifier), + modifier, &tmpl); } static void @@ -542,6 +628,7 @@ etna_resource_screen_init(struct pipe_screen *pscreen) { pscreen->can_create_resource = etna_screen_can_create_resource; pscreen->resource_create = etna_resource_create; + pscreen->resource_create_with_modifiers = etna_resource_create_modifiers; pscreen->resource_from_handle = etna_resource_from_handle; pscreen->resource_get_handle = etna_resource_get_handle; pscreen->resource_changed = etna_resource_changed; diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 5f563c06ad..0b135e2373 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -151,7 +151,7 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, struct pipe_resource * etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, - const struct pipe_resource *templat); + uint64_t modifier, const struct pipe_resource *templat); void etna_resource_screen_init(struct pipe_screen *pscreen); diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c index 954daea7ba..b8ebab6082 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c @@ -36,6 +36,8 @@ #include "util/u_inlines.h" #include "util/u_memory.h" +#include <drm_fourcc.h> + static void * etna_create_sampler_state(struct pipe_context *pipe, const struct pipe_sampler_state *ss) @@ -187,7 +189,8 @@ etna_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc, templat.bind &= ~(PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE); res->texture = - etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED, &templat); + etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED, + DRM_FORMAT_MOD_LINEAR, &templat); } if (!res->texture) { diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c index 27e1be1957..6c1edd4835 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c +++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c @@ -39,6 +39,8 @@ #include "util/u_surface.h" #include "util/u_transfer.h" +#include <drm_fourcc.h> + /* Compute offset into a 1D/2D/3D buffer of a certain box. * This box must be aligned to the block width and height of the * underlying format. */ @@ -203,7 +205,8 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, templ.nr_samples = 0; templ.bind = PIPE_BIND_RENDER_TARGET; - trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, &templ); + trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, + DRM_FORMAT_MOD_LINEAR, &templ); if (!trans->rsc) { slab_free(&ctx->transfer_pool, trans); return NULL; |