summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/main/bufferobj.c12
-rw-r--r--src/mesa/main/mtypes.h4
-rw-r--r--src/mesa/vbo/vbo.h3
-rw-r--r--src/mesa/vbo/vbo_minmax_index.c168
4 files changed, 186 insertions, 1 deletions
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index 2fcad6501ae..3d93cf826b2 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -458,6 +458,7 @@ _mesa_delete_buffer_object(struct gl_context *ctx,
{
(void) ctx;
+ vbo_delete_minmax_cache(bufObj);
_mesa_align_free(bufObj->Data);
/* assign strange values here to help w/ debugging */
@@ -1528,6 +1529,7 @@ _mesa_buffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj,
bufObj->Written = GL_TRUE;
bufObj->Immutable = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
assert(ctx->Driver.BufferData);
if (!ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW,
@@ -1641,6 +1643,7 @@ _mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
#ifdef VBO_DEBUG
printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
@@ -1753,6 +1756,7 @@ _mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
}
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
assert(ctx->Driver.BufferSubData);
ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj);
@@ -1872,6 +1876,8 @@ _mesa_clear_buffer_sub_data(struct gl_context *ctx,
if (size == 0)
return;
+ bufObj->MinMaxCacheDirty = true;
+
if (data == NULL) {
/* clear to zeros, per the spec */
ctx->Driver.ClearBufferSubData(ctx, offset, size,
@@ -2285,6 +2291,8 @@ _mesa_copy_buffer_sub_data(struct gl_context *ctx,
}
}
+ dst->MinMaxCacheDirty = true;
+
ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
}
@@ -2489,8 +2497,10 @@ _mesa_map_buffer_range(struct gl_context *ctx,
assert(bufObj->Mappings[MAP_USER].AccessFlags == access);
}
- if (access & GL_MAP_WRITE_BIT)
+ if (access & GL_MAP_WRITE_BIT) {
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
+ }
#ifdef VBO_DEBUG
if (strstr(func, "Range") == NULL) { /* If not MapRange */
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 4446d94b407..28aa781790b 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1282,6 +1282,10 @@ struct gl_buffer_object
GLuint NumMapBufferWriteCalls;
struct gl_buffer_mapping Mappings[MAP_COUNT];
+
+ /** Memoization of min/max index computations for static index buffers */
+ struct hash_table *MinMaxCache;
+ bool MinMaxCacheDirty;
};
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 0b8b6a9de56..6494aa518a2 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -181,6 +181,9 @@ vbo_sizeof_ib_type(GLenum type)
}
void
+vbo_delete_minmax_cache(struct gl_buffer_object *bufferObj);
+
+void
vbo_get_minmax_indices(struct gl_context *ctx, const struct _mesa_prim *prim,
const struct _mesa_index_buffer *ib,
GLuint *min_index, GLuint *max_index, GLuint nr_prims);
diff --git a/src/mesa/vbo/vbo_minmax_index.c b/src/mesa/vbo/vbo_minmax_index.c
index b43ed983676..1aabab3434f 100644
--- a/src/mesa/vbo/vbo_minmax_index.c
+++ b/src/mesa/vbo/vbo_minmax_index.c
@@ -32,6 +32,167 @@
#include "main/macros.h"
#include "main/sse_minmax.h"
#include "x86/common_x86_asm.h"
+#include "util/hash_table.h"
+
+
+struct minmax_cache_key {
+ GLintptr offset;
+ GLuint count;
+ GLenum type;
+};
+
+
+struct minmax_cache_entry {
+ struct minmax_cache_key key;
+ GLuint min;
+ GLuint max;
+};
+
+
+static uint32_t
+vbo_minmax_cache_hash(const struct minmax_cache_key *key)
+{
+ return _mesa_hash_data(key, sizeof(*key));
+}
+
+
+static bool
+vbo_minmax_cache_key_equal(const struct minmax_cache_key *a,
+ const struct minmax_cache_key *b)
+{
+ return (a->offset == b->offset) && (a->count == b->count) && (a->type == b->type);
+}
+
+
+static void
+vbo_minmax_cache_delete_entry(struct hash_entry *entry)
+{
+ free(entry->data);
+}
+
+
+static GLboolean
+vbo_use_minmax_cache(struct gl_buffer_object *bufferObj)
+{
+ if (bufferObj->UsageHistory & (USAGE_TEXTURE_BUFFER |
+ USAGE_ATOMIC_COUNTER_BUFFER |
+ USAGE_SHADER_STORAGE_BUFFER |
+ USAGE_TRANSFORM_FEEDBACK_BUFFER |
+ USAGE_PIXEL_PACK_BUFFER))
+ return GL_FALSE;
+
+ if ((bufferObj->Mappings[MAP_USER].AccessFlags &
+ (GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT)) ==
+ (GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+void
+vbo_delete_minmax_cache(struct gl_buffer_object *bufferObj)
+{
+ _mesa_hash_table_destroy(bufferObj->MinMaxCache, vbo_minmax_cache_delete_entry);
+ bufferObj->MinMaxCache = NULL;
+}
+
+
+static GLboolean
+vbo_get_minmax_cached(struct gl_buffer_object *bufferObj,
+ GLenum type, GLintptr offset, GLuint count,
+ GLuint *min_index, GLuint *max_index)
+{
+ GLboolean found = GL_FALSE;
+ struct minmax_cache_key key;
+ uint32_t hash;
+ struct hash_entry *result;
+
+ if (!bufferObj->MinMaxCache)
+ return GL_FALSE;
+ if (!vbo_use_minmax_cache(bufferObj))
+ return GL_FALSE;
+
+ mtx_lock(&bufferObj->Mutex);
+
+ if (bufferObj->MinMaxCacheDirty) {
+ _mesa_hash_table_clear(bufferObj->MinMaxCache, vbo_minmax_cache_delete_entry);
+ bufferObj->MinMaxCacheDirty = false;
+ goto out;
+ }
+
+ key.type = type;
+ key.offset = offset;
+ key.count = count;
+ hash = vbo_minmax_cache_hash(&key);
+ result = _mesa_hash_table_search_pre_hashed(bufferObj->MinMaxCache, hash, &key);
+ if (result) {
+ struct minmax_cache_entry *entry = result->data;
+ *min_index = entry->min;
+ *max_index = entry->max;
+ found = GL_TRUE;
+ }
+
+out:
+ mtx_unlock(&bufferObj->Mutex);
+ return found;
+}
+
+
+static void
+vbo_minmax_cache_store(struct gl_context *ctx,
+ struct gl_buffer_object *bufferObj,
+ GLenum type, GLintptr offset, GLuint count,
+ GLuint min, GLuint max)
+{
+ struct minmax_cache_entry *entry;
+ struct hash_entry *table_entry;
+ uint32_t hash;
+
+ if (!vbo_use_minmax_cache(bufferObj))
+ return;
+
+ mtx_lock(&bufferObj->Mutex);
+
+ if (!bufferObj->MinMaxCache) {
+ bufferObj->MinMaxCache =
+ _mesa_hash_table_create(NULL,
+ (uint32_t (*)(const void *))vbo_minmax_cache_hash,
+ (bool (*)(const void *, const void *))vbo_minmax_cache_key_equal);
+ if (!bufferObj->MinMaxCache)
+ goto out;
+ }
+
+ entry = MALLOC_STRUCT(minmax_cache_entry);
+ if (!entry)
+ goto out;
+
+ entry->key.offset = offset;
+ entry->key.count = count;
+ entry->key.type = type;
+ entry->min = min;
+ entry->max = max;
+ hash = vbo_minmax_cache_hash(&entry->key);
+
+ table_entry = _mesa_hash_table_search_pre_hashed(bufferObj->MinMaxCache,
+ hash, &entry->key);
+ if (table_entry) {
+ /* It seems like this could happen when two contexts are rendering using
+ * the same buffer object from multiple threads.
+ */
+ _mesa_debug(ctx, "duplicate entry in minmax cache\n");
+ free(entry);
+ goto out;
+ }
+
+ table_entry = _mesa_hash_table_insert_pre_hashed(bufferObj->MinMaxCache,
+ hash, &entry->key, entry);
+ if (!table_entry)
+ free(entry);
+
+out:
+ mtx_unlock(&bufferObj->Mutex);
+}
/**
@@ -56,6 +217,11 @@ vbo_get_minmax_index(struct gl_context *ctx,
indices = (char *) ib->ptr + prim->start * index_size;
if (_mesa_is_bufferobj(ib->obj)) {
GLsizeiptr size = MIN2(count * index_size, ib->obj->Size);
+
+ if (vbo_get_minmax_cached(ib->obj, ib->type, (GLintptr) indices, count,
+ min_index, max_index))
+ return;
+
indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size,
GL_MAP_READ_BIT, ib->obj,
MAP_INTERNAL);
@@ -139,6 +305,8 @@ vbo_get_minmax_index(struct gl_context *ctx,
}
if (_mesa_is_bufferobj(ib->obj)) {
+ vbo_minmax_cache_store(ctx, ib->obj, ib->type, prim->start, count,
+ *min_index, *max_index);
ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
}
}