summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolai Hähnle <[email protected]>2016-01-11 15:07:48 -0500
committerNicolai Hähnle <[email protected]>2016-02-03 14:04:06 +0100
commit761c7d59c4403832c33d931bb097d060ed07e555 (patch)
tree53db3635ba745e2e27131bf0f37159afb6f734b1
parent115c643b1669bd050af8d890adbfc771d9ff8126 (diff)
vbo: disable the minmax cache when the hit rate is low
When applications stream their index buffers, the caches for those BOs become useless and add overhead, so we want to disable them. The tricky part is coming up with the right heuristic for *when* to disable them. The first question is which hit rate to aim for. Since I'm not aware of any interesting borderline applications that do something like "draw two or three times for each upload", I just kept it simple. The second question is how soon we should give up on the caching. Applications might have a warm-up phase where they fill a buffer gradually but then keep reusing it. For this reason, I count the number of indices that hit and miss (instead of the number of calls that hit or miss), since comparing that to the size of the buffer makes sense. Reviewed-by: Marek Olšák <[email protected]>
-rw-r--r--src/mesa/main/mtypes.h2
-rw-r--r--src/mesa/vbo/vbo_minmax_index.c34
2 files changed, 34 insertions, 2 deletions
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 6099ae1c463..58064aac1cd 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1286,6 +1286,8 @@ struct gl_buffer_object
/** Memoization of min/max index computations for static index buffers */
struct hash_table *MinMaxCache;
+ unsigned MinMaxCacheHitIndices;
+ unsigned MinMaxCacheMissIndices;
bool MinMaxCacheDirty;
};
diff --git a/src/mesa/vbo/vbo_minmax_index.c b/src/mesa/vbo/vbo_minmax_index.c
index 47b0d9cf2a3..0f75a87f3f3 100644
--- a/src/mesa/vbo/vbo_minmax_index.c
+++ b/src/mesa/vbo/vbo_minmax_index.c
@@ -117,9 +117,24 @@ vbo_get_minmax_cached(struct gl_buffer_object *bufferObj,
mtx_lock(&bufferObj->Mutex);
if (bufferObj->MinMaxCacheDirty) {
+ /* Disable the cache permanently for this BO if the number of hits
+ * is asymptotically less than the number of misses. This happens when
+ * applications use the BO for streaming.
+ *
+ * However, some initial optimism allows applications that interleave
+ * draw calls with glBufferSubData during warmup.
+ */
+ unsigned optimism = bufferObj->Size;
+ if (bufferObj->MinMaxCacheMissIndices > optimism &&
+ bufferObj->MinMaxCacheHitIndices < bufferObj->MinMaxCacheMissIndices - optimism) {
+ bufferObj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
+ vbo_delete_minmax_cache(bufferObj);
+ goto out_disable;
+ }
+
_mesa_hash_table_clear(bufferObj->MinMaxCache, vbo_minmax_cache_delete_entry);
bufferObj->MinMaxCacheDirty = false;
- goto out;
+ goto out_invalidate;
}
key.type = type;
@@ -134,7 +149,22 @@ vbo_get_minmax_cached(struct gl_buffer_object *bufferObj,
found = GL_TRUE;
}
-out:
+out_invalidate:
+ if (found) {
+ /* The hit counter saturates so that we don't accidently disable the
+ * cache in a long-running program.
+ */
+ unsigned new_hit_count = bufferObj->MinMaxCacheHitIndices + count;
+
+ if (new_hit_count >= bufferObj->MinMaxCacheHitIndices)
+ bufferObj->MinMaxCacheHitIndices = new_hit_count;
+ else
+ bufferObj->MinMaxCacheHitIndices = ~(unsigned)0;
+ } else {
+ bufferObj->MinMaxCacheMissIndices += count;
+ }
+
+out_disable:
mtx_unlock(&bufferObj->Mutex);
return found;
}