X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fetnaviv%2Fetnaviv_resource.c;h=b1a814d4a398720c5a15898331c21379a3a988ce;hp=aefe65bf0e47e79466b2e9fd8f0af25914f59d7e;hb=8a44aa50435b905b6cdf4524711702b7645cbd2b;hpb=c9e8b49b885242d84ba031dacef5aa4a5ac1e5b6 diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index aefe65bf0e4..b1a814d4a39 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -36,6 +36,29 @@ #include "util/u_inlines.h" #include "util/u_memory.h" +#include + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) +#endif + +static enum etna_surface_layout modifier_to_layout(uint64_t modifier) +{ + switch (modifier) { + case DRM_FORMAT_MOD_VIVANTE_TILED: + return ETNA_LAYOUT_TILED; + case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: + return ETNA_LAYOUT_SUPER_TILED; + case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: + return ETNA_LAYOUT_MULTI_TILED; + case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: + return ETNA_LAYOUT_MULTI_SUPERTILED; + case DRM_FORMAT_MOD_LINEAR: + default: + return ETNA_LAYOUT_LINEAR; + } +} + /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status. * So, in a buffer of N pixels, there are N / (4 * 4) tiles. * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or @@ -52,7 +75,8 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, /* TS only for level 0 -- XXX is this formula correct? */ pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format); - ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, 0x100); + ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, + 0x100 * screen->specs.pixel_pipes); rt_ts_size = ts_layer_stride * rsc->base.array_size; if (rt_ts_size == 0) return true; @@ -140,6 +164,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, const struct pipe_resource *templat) { struct etna_screen *screen = etna_screen(pscreen); + struct etna_resource *rsc; unsigned size; DBG_F(ETNA_DBG_RESOURCE_MSGS, @@ -179,14 +204,37 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, &paddingY, &halign); assert(paddingX && paddingY); - if (templat->bind != PIPE_BUFFER) { - unsigned min_paddingY = 4 * screen->specs.pixel_pipes; - if (paddingY < min_paddingY) - paddingY = min_paddingY; - } + if (templat->target != PIPE_BUFFER) + etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY); + + if (templat->bind & PIPE_BIND_SCANOUT) { + struct pipe_resource scanout_templat = *templat; + struct renderonly_scanout *scanout; + 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); + + scanout = renderonly_scanout_for_resource(&scanout_templat, + screen->ro, &handle); + if (!scanout) + return NULL; + + assert(handle.type == DRM_API_HANDLE_TYPE_FD); + rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat, + &handle, + PIPE_HANDLE_USAGE_WRITE)); + close(handle.handle); + if (!rsc) + return NULL; - struct etna_resource *rsc = CALLOC_STRUCT(etna_resource); + rsc->scanout = scanout; + return &rsc->base; + } + + rsc = CALLOC_STRUCT(etna_resource); if (!rsc) return NULL; @@ -201,24 +249,28 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale); - struct etna_bo *bo = etna_bo_new(screen->dev, size, DRM_ETNA_GEM_CACHE_WC); + uint32_t flags = DRM_ETNA_GEM_CACHE_WC; + if (templat->bind & PIPE_BIND_VERTEX_BUFFER) + flags |= DRM_ETNA_GEM_FORCE_MMU; + struct etna_bo *bo = etna_bo_new(screen->dev, size, flags); if (unlikely(bo == NULL)) { BUG("Problem allocating video memory for resource"); - return NULL; + goto free_rsc; } rsc->bo = bo; rsc->ts_bo = 0; /* TS is only created when first bound to surface */ - if (templat->bind & PIPE_BIND_SCANOUT) - rsc->scanout = renderonly_scanout_for_resource(&rsc->base, screen->ro); - if (DBG_ENABLED(ETNA_DBG_ZERO)) { void *map = etna_bo_map(bo); memset(map, 0, size); } return &rsc->base; + +free_rsc: + FREE(rsc); + return NULL; } static struct pipe_resource * @@ -227,12 +279,9 @@ etna_resource_create(struct pipe_screen *pscreen, { struct etna_screen *screen = etna_screen(pscreen); - /* Figure out what tiling to use -- for now, assume that textures cannot be - * supertiled, and cannot be linear. - * There is a feature flag SUPERTILED_TEXTURE (not supported on any known hw) - * that may allow this, as well - * as LINEAR_TEXTURE_SUPPORT (supported on gc880 and gc2000 at least), but - * not sure how it works. + /* Figure out what tiling to use -- for now, assume that texture cannot be linear. + * there is a capability LINEAR_TEXTURE_SUPPORT (supported on gc880 and + * gc2000 at least), but not sure how it works. * Buffers always have LINEAR layout. */ unsigned layout = ETNA_LAYOUT_LINEAR; @@ -245,8 +294,14 @@ etna_resource_create(struct pipe_screen *pscreen, if (util_format_is_compressed(templat->format)) layout = ETNA_LAYOUT_LINEAR; } else if (templat->target != PIPE_BUFFER) { - bool want_multitiled = screen->specs.pixel_pipes > 1; - bool want_supertiled = screen->specs.can_supertile && !DBG_ENABLED(ETNA_DBG_NO_SUPERTILE); + bool want_multitiled = false; + bool want_supertiled = screen->specs.can_supertile; + + /* When this GPU supports single-buffer rendering, don't ever enable + * multi-tiling. This replicates the blob behavior on GC3000. + */ + if (!screen->specs.single_buffer) + want_multitiled = screen->specs.pixel_pipes > 1; /* Keep single byte blocksized resources as tiled, since we * are unable to use the RS blit to de-tile them. However, @@ -274,6 +329,17 @@ etna_resource_create(struct pipe_screen *pscreen, return etna_resource_alloc(pscreen, layout, templat); } +static void +etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc) +{ + struct etna_resource *res = etna_resource(prsc); + + if (res->external) + etna_resource(res->external)->seqno++; + else + res->seqno++; +} + static void etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) { @@ -286,11 +352,12 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) etna_bo_del(rsc->ts_bo); if (rsc->scanout) - renderonly_scanout_destroy(rsc->scanout); + renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro); list_delinit(&rsc->list); pipe_resource_reference(&rsc->texture, NULL); + pipe_resource_reference(&rsc->external, NULL); FREE(rsc); } @@ -301,9 +368,9 @@ etna_resource_from_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, unsigned usage) { struct etna_screen *screen = etna_screen(pscreen); - struct etna_resource *rsc = CALLOC_STRUCT(etna_resource); - struct etna_resource_level *level = &rsc->levels[0]; - struct pipe_resource *prsc = &rsc->base; + struct etna_resource *rsc; + struct etna_resource_level *level; + struct pipe_resource *prsc; struct pipe_resource *ptiled = NULL; DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " @@ -312,9 +379,13 @@ etna_resource_from_handle(struct pipe_screen *pscreen, tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level, tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags); + rsc = CALLOC_STRUCT(etna_resource); if (!rsc) return NULL; + level = &rsc->levels[0]; + prsc = &rsc->base; + *prsc = *tmpl; pipe_reference_init(&prsc->reference, 1); @@ -325,17 +396,27 @@ etna_resource_from_handle(struct pipe_screen *pscreen, if (!rsc->bo) goto fail; + rsc->seqno = 1; + rsc->layout = modifier_to_layout(handle->modifier); + rsc->halign = TEXTURE_HALIGN_FOUR; + + level->width = tmpl->width0; level->height = tmpl->height0; - /* We will be using the RS to copy with this resource, so we must - * ensure that it is appropriately aligned for the RS requirements. */ - unsigned paddingX = ETNA_RS_WIDTH_MASK + 1; - unsigned paddingY = (ETNA_RS_HEIGHT_MASK + 1) * screen->specs.pixel_pipes; + /* Determine padding of the imported resource. */ + unsigned paddingX = 0, paddingY = 0; + etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes, + VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN), + &paddingX, &paddingY, &rsc->halign); + etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY); level->padded_width = align(level->width, paddingX); level->padded_height = align(level->height, paddingY); + level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format, + level->padded_height); + /* The DDX must give us a BO which conforms to our padding size. * The stride of the BO must be greater or equal to our padded * stride. The size of the BO must accomodate the padded height. */ @@ -348,20 +429,25 @@ etna_resource_from_handle(struct pipe_screen *pscreen, goto fail; } - if (handle->type == DRM_API_HANDLE_TYPE_SHARED && tmpl->bind & PIPE_BIND_RENDER_TARGET) { - /* Render targets are linear in Xorg but must be tiled - * here. It would be nice if dri_drawable_get_format() - * set scanout for these buffers too. */ - struct etna_resource *tiled; + if (rsc->layout == ETNA_LAYOUT_LINEAR) { + /* + * Both sampler and pixel pipes can't handle linear, create a compatible + * base resource, where we can attach the imported buffer as an external + * resource. + */ + struct pipe_resource tiled_templat = *tmpl; + + /* + * Remove BIND_SCANOUT to avoid recursion, as etna_resource_create uses + * this function to import the scanout buffer and get a tiled resource. + */ + tiled_templat.bind &= ~PIPE_BIND_SCANOUT; - ptiled = etna_resource_create(pscreen, tmpl); + ptiled = etna_resource_create(pscreen, &tiled_templat); if (!ptiled) goto fail; - tiled = etna_resource(ptiled); - tiled->scanout = renderonly_scanout_for_prime(prsc, screen->ro); - if (!tiled->scanout) - goto fail; + etna_resource(ptiled)->external = prsc; return ptiled; } @@ -383,8 +469,18 @@ etna_resource_get_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, unsigned usage) { struct etna_resource *rsc = etna_resource(prsc); + /* Scanout is always attached to the base resource */ + struct renderonly_scanout *scanout = rsc->scanout; + + /* + * External resources are preferred, so a import->export chain of + * render/sampler incompatible buffers yield the same handle. + */ + if (rsc->external) + rsc = etna_resource(rsc->external); - if (renderonly_get_handle(rsc->scanout, handle)) + if (handle->type == DRM_API_HANDLE_TYPE_KMS && + renderonly_get_handle(scanout, handle)) return TRUE; return etna_screen_bo_get_handle(pscreen, rsc->bo, rsc->levels[0].stride, @@ -411,22 +507,6 @@ etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, rsc->pending_ctx = ctx; } -void -etna_resource_wait(struct pipe_context *pctx, struct etna_resource *rsc) -{ - if (rsc->status & ETNA_PENDING_WRITE) { - struct pipe_fence_handle *fence; - struct pipe_screen *pscreen = pctx->screen; - - pctx->flush(pctx, &fence, 0); - - if (!pscreen->fence_finish(pscreen, pctx, fence, 5000000000ULL)) - BUG("fence timed out (hung GPU?)"); - - pscreen->fence_reference(pscreen, &fence, NULL); - } -} - void etna_resource_screen_init(struct pipe_screen *pscreen) { @@ -434,5 +514,6 @@ etna_resource_screen_init(struct pipe_screen *pscreen) pscreen->resource_create = etna_resource_create; pscreen->resource_from_handle = etna_resource_from_handle; pscreen->resource_get_handle = etna_resource_get_handle; + pscreen->resource_changed = etna_resource_changed; pscreen->resource_destroy = etna_resource_destroy; }