This code is probably a wholesale duplication of the corresponding code in mesa/src/vbo/vbo_minmax_indices.c; we should investigate reusing that.
Signed-off-by: Alyssa Rosenzweig <aly...@rosenzweig.io> --- src/gallium/drivers/panfrost/pan_context.c | 108 ++++++++++++++------ src/gallium/drivers/panfrost/pan_resource.c | 37 ++++++- src/gallium/drivers/panfrost/pan_resource.h | 9 ++ 3 files changed, 117 insertions(+), 37 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index 19cdb6c0444..2e8a0f03b1a 100644 --- a/src/gallium/drivers/panfrost/pan_context.c +++ b/src/gallium/drivers/panfrost/pan_context.c @@ -1355,17 +1355,82 @@ panfrost_translate_index_size(unsigned size) } } -static const uint8_t * -panfrost_get_index_buffer_raw(const struct pipe_draw_info *info) +#define CALCULATE_MIN_MAX_INDEX(T, buffer, start, count) \ + for (unsigned _idx = (start); _idx < (start + count); ++_idx) { \ + T idx = buffer[_idx]; \ + if (idx > max_index) max_index = idx; \ + if (idx < min_index) min_index = idx; \ + } + +/* Computes the index bounds, rescanning if necessary */ + +static void +panfrost_get_index_bounds( + const struct pipe_draw_info *info, + int *o_min_index, + int *o_max_index) { - if (info->has_user_indices) { - return (const uint8_t *) info->index.user; + int min_index = INT_MAX, max_index = 0; + + struct panfrost_resource *rsrc = + info->has_user_indices ? NULL : + pan_resource(info->index.resource); + + if (rsrc) { + assert(rsrc->bo); + } + + uint64_t key = ((uint64_t) info->start << 32) | ((uint32_t) info->count); + + /* Reuse bounds from cache if possible */ + if (rsrc) { + struct panfrost_indices *cached = (struct panfrost_indices *) + _mesa_hash_table_u64_search(rsrc->indices, key); + + if (cached) { + *o_min_index = cached->min; + *o_max_index = cached->max; + return; + } + } + + const uint8_t *ibuf8 = + rsrc ? rsrc->bo->cpu[0] : info->index.user; + + /* Scan the buffer */ + + if (info->index_size == 1) { + CALCULATE_MIN_MAX_INDEX(uint8_t, ibuf8, info->start, info->count); + } else if (info->index_size == 2) { + const uint16_t *ibuf16 = (const uint16_t *) ibuf8; + CALCULATE_MIN_MAX_INDEX(uint16_t, ibuf16, info->start, info->count); + } else if (info->index_size == 4) { + const uint32_t *ibuf32 = (const uint32_t *) ibuf8; + CALCULATE_MIN_MAX_INDEX(uint32_t, ibuf32, info->start, info->count); } else { - struct panfrost_resource *rsrc = (struct panfrost_resource *) (info->index.resource); - return (const uint8_t *) rsrc->bo->cpu[0]; + assert(0); + } + + /* Make sure we didn't go crazy */ + assert(min_index < INT_MAX); + assert(max_index > 0); + assert(max_index > min_index); + + /* Write bounds back */ + *o_min_index = min_index; + *o_max_index = max_index; + + /* Write bounds to cache */ + if (rsrc) { + struct panfrost_indices *ind = CALLOC_STRUCT(panfrost_indices); + ind->min = min_index; + ind->max = max_index; + _mesa_hash_table_u64_insert(rsrc->indices, key, ind); } } +#undef CALCULATE_MIN_MAX_INDEX + /* Gets a GPU address for the associated index buffer. Only gauranteed to be * good for the duration of the draw (transient), could last longer */ @@ -1381,18 +1446,11 @@ panfrost_get_index_buffer_mapped(struct panfrost_context *ctx, const struct pipe return rsrc->bo->gpu[0] + offset; } else { /* Otherwise, we need to upload to transient memory */ - const uint8_t *ibuf8 = panfrost_get_index_buffer_raw(info); + const uint8_t *ibuf8 = (const uint8_t *) info->index.user; return panfrost_upload_transient(ctx, ibuf8 + offset, info->count * info->index_size); } } -#define CALCULATE_MIN_MAX_INDEX(T, buffer, start, count) \ - for (unsigned _idx = (start); _idx < (start + count); ++_idx) { \ - T idx = buffer[_idx]; \ - if (idx > max_index) max_index = idx; \ - if (idx < min_index) min_index = idx; \ - } - static void panfrost_draw_vbo( struct pipe_context *pipe, @@ -1445,27 +1503,9 @@ panfrost_draw_vbo( /* Calculate the min/max index used so we can figure out how * many times to invoke the vertex shader */ - const uint8_t *ibuf8 = panfrost_get_index_buffer_raw(info); - - int min_index = INT_MAX; - int max_index = 0; - - if (info->index_size == 1) { - CALCULATE_MIN_MAX_INDEX(uint8_t, ibuf8, info->start, info->count); - } else if (info->index_size == 2) { - const uint16_t *ibuf16 = (const uint16_t *) ibuf8; - CALCULATE_MIN_MAX_INDEX(uint16_t, ibuf16, info->start, info->count); - } else if (info->index_size == 4) { - const uint32_t *ibuf32 = (const uint32_t *) ibuf8; - CALCULATE_MIN_MAX_INDEX(uint32_t, ibuf32, info->start, info->count); - } else { - assert(0); - } + int min_index, max_index; - /* Make sure we didn't go crazy */ - assert(min_index < INT_MAX); - assert(max_index > 0); - assert(max_index > min_index); + panfrost_get_index_bounds(info, &min_index, &max_index); /* Use the corresponding values */ invocation_count = max_index - min_index + 1; diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index 6fe871594ea..8bf242d7e94 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -282,6 +282,13 @@ panfrost_resource_create(struct pipe_screen *screen, assert(0); } + /* Allocate room for index buffer cache */ + + if (template->bind & PIPE_BIND_INDEX_BUFFER) { + /* TODO leaks */ + so->indices = _mesa_hash_table_u64_create(NULL); + } + if (template->bind & PIPE_BIND_DISPLAY_TARGET || template->bind & PIPE_BIND_SCANOUT || template->bind & PIPE_BIND_SHARED) { @@ -353,6 +360,12 @@ panfrost_destroy_bo(struct panfrost_screen *screen, struct panfrost_bo *pbo) } } +static void +panfrost_delete_entry(struct hash_entry *entry) +{ + free(entry->data); +} + static void panfrost_resource_destroy(struct pipe_screen *screen, struct pipe_resource *pt) @@ -366,6 +379,9 @@ panfrost_resource_destroy(struct pipe_screen *screen, if (rsrc->bo) panfrost_destroy_bo(pscreen, rsrc->bo); + if (rsrc->indices) + _mesa_hash_table_u64_destroy(rsrc->indices, panfrost_delete_entry); + FREE(rsrc); } @@ -377,9 +393,16 @@ panfrost_map_bo(struct panfrost_context *ctx, struct pipe_transfer *transfer) /* If non-zero level, it's a mipmapped resource and needs to be treated as such */ bo->is_mipmap |= transfer->level; - if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY && bo->layout != PAN_LINEAR) { - /* We can only directly map linear resources */ - return NULL; + if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY) { + if (bo->layout != PAN_LINEAR) { + /* We can only directly map linear resources */ + return NULL; + } + + if (transfer->resource->bind & PIPE_BIND_INDEX_BUFFER) { + /* Direct mapping messes with index buffer scanning */ + return NULL; + } } if (transfer->resource->bind & PIPE_BIND_DEPTH_STENCIL) { @@ -490,6 +513,14 @@ panfrost_unmap_bo(struct panfrost_context *ctx, panfrost_tile_texture(screen, prsrc, transfer->level); } } + + /* Invalidate index buffer scans, TODO leaks */ + struct panfrost_resource *r = pan_resource(transfer->resource); + + if (r->indices) { + _mesa_hash_table_u64_destroy(r->indices, panfrost_delete_entry); + r->indices = _mesa_hash_table_u64_create(NULL); + } } } diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h index 4b5b9c49c07..e6fb7cda5a2 100644 --- a/src/gallium/drivers/panfrost/pan_resource.h +++ b/src/gallium/drivers/panfrost/pan_resource.h @@ -84,6 +84,12 @@ struct panfrost_bo { unsigned int stride; }; +/* Container for cached index buffer bounds */ +struct panfrost_indices { + /* Calculated bounds */ + uint32_t min, max; +}; + struct panfrost_resource { struct pipe_resource base; @@ -91,6 +97,9 @@ struct panfrost_resource { struct renderonly_scanout *scanout; struct panfrost_resource *separate_stencil; + + /* Hash mapping (start<<32 | count) to struct panfrost_indices */ + struct hash_table_u64 *indices; }; static inline struct panfrost_resource * -- 2.20.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev