[Mesa-dev] [PATCH] panfrost: Cache index buffer bounds
Alyssa Rosenzweig
alyssa at rosenzweig.io
Sun Mar 24 05:15:05 UTC 2019
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 <alyssa at 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
More information about the mesa-dev
mailing list