diff --git a/src/gallium/drivers/etnaviv/etnaviv_blt.c b/src/gallium/drivers/etnaviv/etnaviv_blt.c index 8ec41e1d915..125d6255234 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_blt.c +++ b/src/gallium/drivers/etnaviv/etnaviv_blt.c @@ -258,6 +258,12 @@ etna_blit_clear_color_blt(struct pipe_context *pctx, struct pipe_surface *dst, if (surf->surf.ts_size) { ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value; ctx->framebuffer.TS_COLOR_CLEAR_VALUE_EXT = new_clear_value >> 32; + + /* update clear color in SW meta area of the buffer if TS is exported */ + if (unlikely(new_clear_value != surf->level->clear_value && + etna_resource_ext_ts(etna_resource(dst->texture)))) + etna_resource(dst->texture)->ts_meta->v0.clear_value = new_clear_value; + surf->level->ts_valid = true; ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index 113f9cf53b7..bef5a9d4367 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -177,7 +177,7 @@ etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) etna_copy_resource(pctx, prsc, rsc->render, 0, 0); rsc->seqno = etna_resource(rsc->render)->seqno; } - } else if (etna_resource_needs_flush(rsc)) { + } else if (!etna_resource_ext_ts(rsc) && etna_resource_needs_flush(rsc)) { etna_copy_resource(pctx, prsc, prsc, 0, 0); rsc->flush_seqno = rsc->seqno; } diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index b807e587aa7..7e730a35e41 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -37,11 +37,9 @@ #include "util/u_inlines.h" #include "util/u_memory.h" -#include "drm-uapi/drm_fourcc.h" - static enum etna_surface_layout modifier_to_layout(uint64_t modifier) { - switch (modifier) { + switch (modifier & ~VIVANTE_MOD_EXT_MASK) { case DRM_FORMAT_MOD_VIVANTE_TILED: return ETNA_LAYOUT_TILED; case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: @@ -75,19 +73,27 @@ static uint64_t layout_to_modifier(enum etna_surface_layout layout) } } +static uint64_t etna_resource_modifier(struct etna_resource *rsc) +{ + if (etna_resource_ext_ts(rsc)) + return rsc->modifier; + + return layout_to_modifier(rsc->layout); +} + /* A tile is either 64 bytes or, when the GPU has the CACHE128B256BPERLINE * feature, 128/256 bytes of color/depth data, tracked by * 'screen->specs.bits_per_tile' bits of tile status. */ bool etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, - struct etna_resource *rsc) + struct etna_resource *rsc, uint64_t modifier) { struct etna_screen *screen = etna_screen(pscreen); struct pipe_resource *prsc = &rsc->base; - size_t tile_size, rt_ts_size, ts_layer_stride; + size_t tile_size, ts_size, ts_bo_size, ts_layer_stride, ts_data_offset = 0; uint8_t ts_mode = TS_MODE_128B; - int8_t ts_compress_fmt; + int8_t ts_compress_fmt = -1; unsigned layers; assert(!rsc->ts_bo); @@ -96,36 +102,64 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, * v4 compression can be enabled everywhere without any known drawback, * except that in-place resolve must go through a slower path */ - ts_compress_fmt = (screen->specs.v4_compression || prsc->nr_samples > 1) ? - translate_ts_format(prsc->format) : -1; + if ((screen->specs.v4_compression && + (!modifier || (modifier & VIVANTE_MOD_COMP_DEC400))) || + (!modifier && prsc->nr_samples > 1)) + ts_compress_fmt = translate_ts_format(prsc->format); /* enable 256B ts mode with compression, as it improves performance * the size of the resource might also determine if we want to use it or not */ - if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE) && - ts_compress_fmt >= 0 && - (rsc->layout != ETNA_LAYOUT_LINEAR || - rsc->levels[0].stride % 256 == 0) ) + if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE)) { + if ((modifier & VIVANTE_MOD_TS_MASK) == VIVANTE_MOD_TS_128_4) + ts_mode = TS_MODE_128B; + else if ((modifier & VIVANTE_MOD_TS_MASK) == VIVANTE_MOD_TS_256_4) ts_mode = TS_MODE_256B; + else { + /* Without a TS modifier TS is only internal, so we can choose the + * mode to use freely. Enable 256B ts mode with compression, as it + * improves performance. The size of the resource might also determine + * if we want to use it or not. + */ + if (ts_compress_fmt >= 0 && + (rsc->layout != ETNA_LAYOUT_LINEAR || + rsc->levels[0].stride % 256 == 0)) + ts_mode = TS_MODE_256B; + else + ts_mode = TS_MODE_128B; + } + } tile_size = etna_screen_get_tile_size(screen, ts_mode, prsc->nr_samples > 1); layers = prsc->target == PIPE_TEXTURE_3D ? prsc->depth0 : prsc->array_size; ts_layer_stride = align(DIV_ROUND_UP(rsc->levels[0].layer_stride, tile_size * 8 / screen->specs.bits_per_tile), 0x100 * screen->specs.pixel_pipes); - rt_ts_size = ts_layer_stride * layers; - if (rt_ts_size == 0) + ts_size = ts_bo_size = ts_layer_stride * layers; + if (ts_size == 0) return true; + /* add space for the software meta */ + if (modifier & VIVANTE_MOD_TS_MASK) { + /* The offset is a educated guess for a safe value based on the experience + * that various object pointers on the GPU need to be 64B aligned. Maybe + * some GPU needs even more alignment, or we could drop this to 32B. 64B + * has worked well across various GPU generations so far. + */ + ts_data_offset = 64; + assert(ts_data_offset >= sizeof(struct etna_ts_sw_meta)); + ts_bo_size += ts_data_offset; + } + DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu", - rsc, rt_ts_size); + rsc, ts_bo_size); if ((rsc->base.bind & PIPE_BIND_SCANOUT) && screen->ro->kms_fd >= 0) { struct pipe_resource scanout_templat; struct winsys_handle handle; scanout_templat.format = PIPE_FORMAT_R8_UNORM; - scanout_templat.width0 = align(rt_ts_size, 4096); + scanout_templat.width0 = align(ts_bo_size, 4096); scanout_templat.height0 = 1; rsc->ts_scanout = renderonly_scanout_for_resource(&scanout_templat, @@ -147,12 +181,21 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, return false; } - rsc->levels[0].ts_offset = 0; + rsc->levels[0].ts_offset = ts_data_offset; rsc->levels[0].ts_layer_stride = ts_layer_stride; - rsc->levels[0].ts_size = rt_ts_size; + rsc->levels[0].ts_size = ts_size; rsc->levels[0].ts_mode = ts_mode; rsc->levels[0].ts_compress_fmt = ts_compress_fmt; + /* fill software meta */ + if (modifier & VIVANTE_MOD_TS_MASK) { + rsc->ts_meta = etna_bo_map(rsc->ts_bo); + rsc->ts_meta->version = 0; + rsc->ts_meta->v0.data_size = ts_size; + rsc->ts_meta->v0.data_offset = ts_data_offset; + rsc->ts_meta->v0.layer_stride = ts_layer_stride; + rsc->ts_meta->v0.comp_format = ts_format_to_drmfourcc(rsc->levels[0].ts_compress_fmt); + } return true; } @@ -305,6 +348,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, rsc->base.screen = pscreen; rsc->base.nr_samples = templat->nr_samples; rsc->layout = layout; + rsc->modifier = modifier; rsc->halign = halign; rsc->explicit_flush = true; @@ -346,6 +390,12 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, } } + /* If TS is externally visible set it up now, so it can be exported before + * the first rendering to a surface. + */ + if (etna_resource_ext_ts(rsc)) + etna_screen_resource_alloc_ts(pscreen, rsc, modifier); + if (DBG_ENABLED(ETNA_DBG_ZERO)) { void *map = etna_bo_map(rsc->bo); etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_WRITE); @@ -433,9 +483,10 @@ select_best_modifier(const struct etna_screen * screen, const uint64_t *modifiers, const unsigned count) { enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; + uint64_t best_modifier, base_modifier; for (int i = 0; i < count; i++) { - switch (modifiers[i]) { + switch (modifiers[i] & ~VIVANTE_MOD_EXT_MASK) { case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) || !screen->specs.can_supertile) @@ -466,7 +517,32 @@ select_best_modifier(const struct etna_screen * screen, } } - return priority_to_modifier[prio]; + best_modifier = base_modifier = priority_to_modifier[prio]; + + /* Make a second pass to try and find the best TS modifier if any. */ + for (int i = 0; i < count; i++) { + if ((modifiers[i] & ~VIVANTE_MOD_EXT_MASK) == base_modifier) + if ((modifiers[i] & VIVANTE_MOD_TS_MASK) > + (best_modifier & VIVANTE_MOD_TS_MASK)) + best_modifier = modifiers[i]; + } + + /* If no modifier with TS was found, there is no point in looking further, + * as compression depends on TS. + */ + if (best_modifier == base_modifier) + return best_modifier; + + /* Make a third pass to find a modifier allowing compression. */ + base_modifier = best_modifier; + for (int i = 0; i < count; i++) { + if ((modifiers[i] & ~VIVANTE_MOD_COMP_MASK) == base_modifier) + if ((modifiers[i] & VIVANTE_MOD_COMP_MASK) > + (best_modifier & VIVANTE_MOD_COMP_MASK)) + best_modifier = modifiers[i]; + } + + return best_modifier; } static struct pipe_resource * @@ -504,6 +580,9 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) if (rsc->scanout) renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro); + if (rsc->ts_scanout) + renderonly_scanout_destroy(rsc->ts_scanout, etna_screen(pscreen)->ro); + util_range_destroy(&rsc->valid_buffer_range); pipe_resource_reference(&rsc->texture, NULL); @@ -515,6 +594,38 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) FREE(rsc); } +static void etna_resource_finish_ts_import(struct etna_screen *screen, + struct etna_resource *rsc) +{ + struct etna_resource *ts_rsc = etna_resource(rsc->base.next); + uint64_t ts_modifier = rsc->modifier & VIVANTE_MOD_TS_MASK; + uint8_t ts_mode = 0; + + if (ts_modifier == VIVANTE_MOD_TS_256_4) + ts_mode = TS_MODE_256B; + + rsc->ts_bo = etna_bo_ref(ts_rsc->bo); + rsc->ts_meta = etna_bo_map(rsc->ts_bo) + ts_rsc->levels[0].offset; + + rsc->ts_scanout = ts_rsc->scanout; + ts_rsc->scanout = NULL; + + /* Get TS layout/usage information from the SW meta. FIXME: clear color may + * change over the lifetime of the resource, so might need to look this up + * at a few other places. For now it's not an issue, as buffers with shared + * TS get re-imported all the time. */ + rsc->levels[0].ts_compress_fmt = drmfourcc_to_ts_format(rsc->ts_meta->v0.comp_format); + rsc->levels[0].ts_offset = ts_rsc->levels[0].offset + rsc->ts_meta->v0.data_offset; + rsc->levels[0].ts_layer_stride = rsc->ts_meta->v0.layer_stride; + rsc->levels[0].clear_value = rsc->ts_meta->v0.clear_value; + rsc->levels[0].ts_size = rsc->ts_meta->v0.data_size; + rsc->levels[0].ts_mode = ts_mode; + rsc->levels[0].ts_valid = true; + + etna_resource_destroy(&screen->base, rsc->base.next); + rsc->base.next = NULL; +} + static struct pipe_resource * etna_resource_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *tmpl, @@ -554,6 +665,7 @@ etna_resource_from_handle(struct pipe_screen *pscreen, rsc->seqno = 1; rsc->layout = modifier_to_layout(modifier); + rsc->modifier = modifier; if (usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) rsc->explicit_flush = true; @@ -576,6 +688,20 @@ etna_resource_from_handle(struct pipe_screen *pscreen, level->padded_height); level->size = level->layer_stride; + if (screen->ro) { + struct pipe_resource *imp_prsc = prsc; + do { + etna_resource(imp_prsc)->scanout = + renderonly_create_gpu_import_for_resource(imp_prsc, screen->ro, + NULL); + /* failure is expected for scanout incompatible buffers */ + } while ((imp_prsc = imp_prsc->next)); + } + + /* If the buffer is for a TS plane, skip the RS compatible checks */ + if (handle->plane >= util_format_get_num_planes(prsc->format)) + return prsc; + /* 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. */ @@ -592,15 +718,8 @@ etna_resource_from_handle(struct pipe_screen *pscreen, goto fail; } - if (screen->ro) { - struct pipe_resource *imp_prsc = prsc; - do { - etna_resource(imp_prsc)->scanout = - renderonly_create_gpu_import_for_resource(imp_prsc, screen->ro, - NULL); - /* failure is expected for scanout incompatible buffers */ - } while ((imp_prsc = imp_prsc->next)); - } + if (handle->plane == 0 && etna_resource_ext_ts(rsc)) + etna_resource_finish_ts_import(screen, rsc); return prsc; @@ -618,9 +737,12 @@ etna_resource_get_handle(struct pipe_screen *pscreen, { struct etna_screen *screen = etna_screen(pscreen); struct etna_resource *rsc = etna_resource(prsc); + bool wants_ts = etna_resource_ext_ts(rsc) && + handle->plane >= util_format_get_num_planes(prsc->format); struct renderonly_scanout *scanout; + struct etna_bo *bo; - if (handle->plane) { + if (handle->plane && !wants_ts) { struct pipe_resource *cur = prsc; for (int i = 0; i < handle->plane; i++) { @@ -634,24 +756,37 @@ etna_resource_get_handle(struct pipe_screen *pscreen, /* Scanout is always attached to the base resource */ scanout = rsc->scanout; - handle->stride = rsc->levels[0].stride; - handle->offset = rsc->levels[0].offset; - handle->modifier = layout_to_modifier(rsc->layout); + if (wants_ts) { + handle->stride = DIV_ROUND_UP(rsc->levels[0].stride, + etna_screen_get_tile_size(screen, + rsc->levels[0].ts_mode, + false) + * 8 /screen->specs.bits_per_tile); + handle->offset = rsc->levels[0].ts_offset - rsc->ts_meta->v0.data_offset; + scanout = rsc->ts_scanout; + bo = rsc->ts_bo; + } else { + handle->stride = rsc->levels[0].stride; + handle->offset = rsc->levels[0].offset; + scanout = rsc->scanout; + bo = rsc->bo; + } + handle->modifier = etna_resource_modifier(rsc); if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) rsc->explicit_flush = false; if (handle->type == WINSYS_HANDLE_TYPE_SHARED) { - return etna_bo_get_name(rsc->bo, &handle->handle) == 0; + return etna_bo_get_name(bo, &handle->handle) == 0; } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) { if (screen->ro) { return renderonly_get_handle(scanout, handle); } else { - handle->handle = etna_bo_handle(rsc->bo); + handle->handle = etna_bo_handle(bo); return true; } } else if (handle->type == WINSYS_HANDLE_TYPE_FD) { - handle->handle = etna_bo_dmabuf(rsc->bo); + handle->handle = etna_bo_dmabuf(bo); return true; } else { return false; @@ -665,32 +800,54 @@ etna_resource_get_param(struct pipe_screen *pscreen, enum pipe_resource_param param, unsigned usage, uint64_t *value) { - if (param == PIPE_RESOURCE_PARAM_NPLANES) { - unsigned count = 0; + struct etna_screen *screen = etna_screen(pscreen); + struct etna_resource *rsc = etna_resource(prsc); + bool wants_ts = etna_resource_ext_ts(rsc) && + plane >= util_format_get_num_planes(prsc->format); - for (struct pipe_resource *cur = prsc; cur; cur = cur->next) - count++; - *value = count; + if (param == PIPE_RESOURCE_PARAM_NPLANES) { + if (etna_resource_ext_ts(rsc)) { + *value = 2; + } else { + unsigned count = 0; + + for (struct pipe_resource *cur = prsc; cur; cur = cur->next) + count++; + *value = count; + } return true; } - struct pipe_resource *cur = prsc; - for (int i = 0; i < plane; i++) { - cur = cur->next; - if (!cur) - return false; + if (!wants_ts) { + struct pipe_resource *cur = prsc; + for (int i = 0; i < plane; i++) { + cur = cur->next; + if (!cur) + return false; + } + rsc = etna_resource(cur); } - struct etna_resource *rsc = etna_resource(cur); switch (param) { case PIPE_RESOURCE_PARAM_STRIDE: - *value = rsc->levels[level].stride; + if (wants_ts) { + *value = DIV_ROUND_UP(rsc->levels[0].stride, + etna_screen_get_tile_size(screen, + rsc->levels[0].ts_mode, + prsc->nr_samples > 1) + * 8 / screen->specs.bits_per_tile); + } else { + *value = rsc->levels[0].stride; + } return true; case PIPE_RESOURCE_PARAM_OFFSET: - *value = rsc->levels[level].offset; + if (wants_ts) + *value = rsc->levels[0].ts_offset - rsc->ts_meta->v0.data_offset; + else + *value = rsc->levels[0].offset; return true; case PIPE_RESOURCE_PARAM_MODIFIER: - *value = layout_to_modifier(rsc->layout); + *value = etna_resource_modifier(rsc); return true; default: return false; diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 14a02bf7a6a..ffd46ddac38 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -36,10 +36,23 @@ #include "util/u_helpers.h" #include "util/u_range.h" +#include "drm-uapi/drm_fourcc.h" + struct etna_context; struct pipe_screen; struct util_dynarray; +struct etna_ts_sw_meta { + uint16_t version; + struct { + uint16_t data_offset; + uint32_t data_size; + uint32_t layer_stride; + uint32_t comp_format; + uint64_t clear_value; + } v0; +}; + struct etna_resource_level { unsigned width, padded_width; /* in pixels */ unsigned height, padded_height; /* in samples */ @@ -79,10 +92,13 @@ struct etna_resource { /* only lod 0 used for non-texture buffers */ /* Layout for surface (tiled, multitiled, split tiled, ...) */ enum etna_surface_layout layout; + uint64_t modifier; /* Horizontal alignment for texture unit (TEXTURE_HALIGN_*) */ unsigned halign; struct etna_bo *bo; /* Surface video memory */ struct etna_bo *ts_bo; /* Tile status video memory */ + struct renderonly_scanout *ts_scanout; /* display compatible TS */ + struct etna_ts_sw_meta *ts_meta; /* metadata for shared TS */ struct etna_resource_level levels[ETNA_NUM_LOD]; @@ -142,6 +158,13 @@ etna_resource_hw_tileable(bool use_blt, const struct pipe_resource *pres) util_format_get_blocksize(pres->format) == 4; } +/* returns TRUE if resource TS buffer is exposed externally */ +static inline bool +etna_resource_ext_ts(const struct etna_resource *res) +{ + return res->modifier & VIVANTE_MOD_TS_MASK; +} + static inline struct etna_resource * etna_resource(struct pipe_resource *p) { @@ -173,7 +196,8 @@ etna_resource_status(struct etna_context *ctx, struct etna_resource *res); * This is also called "fast clear". */ bool etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, - struct etna_resource *prsc); + struct etna_resource *prsc, + uint64_t modifier); struct pipe_resource * etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c index 52c7b36f84c..e49279cd138 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_rs.c +++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c @@ -340,6 +340,11 @@ etna_blit_clear_color_rs(struct pipe_context *pctx, struct pipe_surface *dst, ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_COLOR_AUTO_DISABLE; } + /* update clear color in SW meta area of the buffer if TS is exported */ + if (unlikely(new_clear_value != surf->level->clear_value && + etna_resource_ext_ts(etna_resource(dst->texture)))) + etna_resource(dst->texture)->ts_meta->v0.clear_value = new_clear_value; + surf->level->ts_valid = true; ctx->dirty |= ETNA_DIRTY_TS | ETNA_DIRTY_DERIVE_TS; } else if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c index 4eaed980892..dadd57d7fac 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_screen.c +++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c @@ -643,22 +643,66 @@ etna_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen, unsigned int *external_only, int *count) { struct etna_screen *screen = etna_screen(pscreen); - int num_modifiers = etna_get_num_modifiers(screen); - int i; + int num_base_mods = etna_get_num_modifiers(screen); + int mods_multiplier = 1; + int i, j; - if (max > num_modifiers) - max = num_modifiers; + if (VIV_FEATURE(screen, chipFeatures, FAST_CLEAR)) { + /* If TS is supported expose the TS modifiers. GPUs with feature + * CACHE128B256BPERLINE have both 128B and 256B color tile TS modes, + * older cores support exactly one TS layout. + */ + if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE)) + if (screen->specs.v4_compression && + translate_ts_format(format) != ETNA_NO_MATCH) + mods_multiplier += 4; + else + mods_multiplier += 2; + else + mods_multiplier += 1; + } + + if (max > num_base_mods * mods_multiplier) + max = num_base_mods * mods_multiplier; if (!max) { modifiers = NULL; - max = num_modifiers; + max = num_base_mods * mods_multiplier; } - for (i = 0, *count = 0; *count < max && i < num_modifiers; i++, (*count)++) { - if (modifiers) - modifiers[*count] = supported_modifiers[i]; - if (external_only) - external_only[*count] = util_format_is_yuv(format) ? 1 : 0; + for (i = 0, *count = 0; *count < max && i < num_base_mods; i++) { + for (j = 0; *count < max && j < mods_multiplier; j++, (*count)++) { + uint64_t ts_mod; + + if (j == 0) { + ts_mod = 0; + } else if (VIV_FEATURE(screen, chipMinorFeatures6, + CACHE128B256BPERLINE)) { + switch (j) { + case 1: + ts_mod = VIVANTE_MOD_TS_128_4; + break; + case 2: + ts_mod = VIVANTE_MOD_TS_256_4; + break; + case 3: + ts_mod = VIVANTE_MOD_TS_128_4 | VIVANTE_MOD_COMP_DEC400; + break; + case 4: + ts_mod = VIVANTE_MOD_TS_256_4 | VIVANTE_MOD_COMP_DEC400; + } + } else { + if (screen->specs.bits_per_tile == 2) + ts_mod = VIVANTE_MOD_TS_64_2; + else + ts_mod = VIVANTE_MOD_TS_64_4; + } + + if (modifiers) + modifiers[*count] = supported_modifiers[i] | ts_mod; + if (external_only) + external_only[*count] = util_format_is_yuv(format) ? 1 : 0; + } } } @@ -669,13 +713,36 @@ etna_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, bool *external_only) { struct etna_screen *screen = etna_screen(pscreen); - int num_modifiers = etna_get_num_modifiers(screen); + int num_base_mods = etna_get_num_modifiers(screen); + uint64_t base_mod = modifier & ~VIVANTE_MOD_EXT_MASK; + uint64_t ts_mod = modifier & VIVANTE_MOD_TS_MASK; int i; - for (i = 0; i < num_modifiers; i++) { - if (modifier != supported_modifiers[i]) + for (i = 0; i < num_base_mods; i++) { + if (base_mod != supported_modifiers[i]) continue; + if ((modifier & VIVANTE_MOD_COMP_DEC400) && + (!screen->specs.v4_compression || translate_ts_format(format) == ETNA_NO_MATCH)) + return false; + + if (ts_mod) { + if (!VIV_FEATURE(screen, chipFeatures, FAST_CLEAR)) + return false; + + if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE)) { + if (ts_mod != VIVANTE_MOD_TS_128_4 && + ts_mod != VIVANTE_MOD_TS_256_4) + return false; + } else { + if ((screen->specs.bits_per_tile == 2 && + ts_mod != VIVANTE_MOD_TS_64_2) || + (screen->specs.bits_per_tile == 4 && + ts_mod != VIVANTE_MOD_TS_64_4)) + return false; + } + } + if (external_only) *external_only = util_format_is_yuv(format) ? 1 : 0; @@ -685,6 +752,19 @@ etna_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, return false; } +static unsigned int +etna_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, + uint64_t modifier, + enum pipe_format format) +{ + unsigned planes = util_format_get_num_planes(format); + + if (modifier & VIVANTE_MOD_TS_MASK) + return planes * 2; + + return planes; +} + static void etna_determine_uniform_limits(struct etna_screen *screen) { @@ -1141,6 +1221,7 @@ etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu, pscreen->is_format_supported = etna_screen_is_format_supported; pscreen->query_dmabuf_modifiers = etna_screen_query_dmabuf_modifiers; pscreen->is_dmabuf_modifier_supported = etna_screen_is_dmabuf_modifier_supported; + pscreen->get_dmabuf_modifier_planes = etna_screen_get_dmabuf_modifier_planes; if (!etna_shader_screen_init(pscreen)) goto fail; diff --git a/src/gallium/drivers/etnaviv/etnaviv_surface.c b/src/gallium/drivers/etnaviv/etnaviv_surface.c index a705ef3ebee..89cae6ad352 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_surface.c +++ b/src/gallium/drivers/etnaviv/etnaviv_surface.c @@ -119,7 +119,7 @@ etna_create_surface(struct pipe_context *pctx, struct pipe_resource *prsc, /* Multi-layer resources would need to keep much more state (TS valid and * clear color per layer) and are unlikely to profit from TS usage. */ prsc->depth0 == 1 && prsc->array_size == 1) { - etna_screen_resource_alloc_ts(pctx->screen, rsc); + etna_screen_resource_alloc_ts(pctx->screen, rsc, 0); } surf->base.format = templat->format; diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c index 3120364bfd8..27557bc6270 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_texture.c +++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c @@ -231,6 +231,7 @@ struct etna_resource * etna_texture_handle_incompatible(struct pipe_context *pctx, struct pipe_resource *prsc) { struct etna_resource *res = etna_resource(prsc); + if (!etna_resource_sampler_compatible(res)) { /* The original resource is not compatible with the sampler. * Allocate an appropriately tiled texture. */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_translate.h b/src/gallium/drivers/etnaviv/etnaviv_translate.h index 0aa19e5e71c..aea4070a2f6 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_translate.h +++ b/src/gallium/drivers/etnaviv/etnaviv_translate.h @@ -333,6 +333,44 @@ translate_blt_format(enum pipe_format fmt) } } +static inline uint32_t +drmfourcc_to_ts_format(uint32_t fourcc) +{ + switch (fourcc) { + case DRM_FORMAT_ARGB8888: + return COMPRESSION_FORMAT_A8R8G8B8; + case DRM_FORMAT_XRGB8888: + return COMPRESSION_FORMAT_X8R8G8B8; + case DRM_FORMAT_RGB565: + return COMPRESSION_FORMAT_R5G6B5; + case DRM_FORMAT_ARGB4444: + return COMPRESSION_FORMAT_A4R4G4B4; + case DRM_FORMAT_ARGB1555: + return COMPRESSION_FORMAT_A1R5G5B5; + default: + return ~0; + } +} + +static inline uint32_t +ts_format_to_drmfourcc(uint32_t comp_format) +{ + switch (comp_format) { + case COMPRESSION_FORMAT_A8R8G8B8: + return DRM_FORMAT_ARGB8888; + case COMPRESSION_FORMAT_X8R8G8B8: + return DRM_FORMAT_XRGB8888; + case COMPRESSION_FORMAT_R5G6B5: + return DRM_FORMAT_RGB565; + case COMPRESSION_FORMAT_A4R4G4B4: + return DRM_FORMAT_ARGB4444; + case COMPRESSION_FORMAT_A1R5G5B5: + return DRM_FORMAT_ARGB1555; + default: + return 0; + } +} + /* Return normalization flag for vertex element format */ static inline uint32_t translate_vertex_format_normalize(enum pipe_format fmt)