Note that I originally also had a entry-point that would construct a key
and do lookup from a pipe_surface.  I ended up not needing that (yet?)
but it is easy-enough to re-introduce later if we need it for the blit
path.

Signed-off-by: Rob Clark <robdcl...@gmail.com>
---
 src/gallium/drivers/freedreno/Makefile.sources     |   2 +
 src/gallium/drivers/freedreno/freedreno_batch.c    |   5 +
 src/gallium/drivers/freedreno/freedreno_batch.h    |   6 +
 .../drivers/freedreno/freedreno_batch_cache.c      | 246 +++++++++++++++++++++
 .../drivers/freedreno/freedreno_batch_cache.h      |  51 +++++
 src/gallium/drivers/freedreno/freedreno_context.c  |   4 +
 src/gallium/drivers/freedreno/freedreno_context.h  |   3 +
 src/gallium/drivers/freedreno/freedreno_resource.c |   2 +
 src/gallium/drivers/freedreno/freedreno_resource.h |   6 +
 9 files changed, 325 insertions(+)
 create mode 100644 src/gallium/drivers/freedreno/freedreno_batch_cache.c
 create mode 100644 src/gallium/drivers/freedreno/freedreno_batch_cache.h

diff --git a/src/gallium/drivers/freedreno/Makefile.sources 
b/src/gallium/drivers/freedreno/Makefile.sources
index 4ba8c9d..92d9186 100644
--- a/src/gallium/drivers/freedreno/Makefile.sources
+++ b/src/gallium/drivers/freedreno/Makefile.sources
@@ -4,6 +4,8 @@ C_SOURCES := \
        disasm.h \
        freedreno_batch.c \
        freedreno_batch.h \
+       freedreno_batch_cache.c \
+       freedreno_batch_cache.h \
        freedreno_context.c \
        freedreno_context.h \
        freedreno_draw.c \
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.c 
b/src/gallium/drivers/freedreno/freedreno_batch.c
index 1fbce43..5c6ae76 100644
--- a/src/gallium/drivers/freedreno/freedreno_batch.c
+++ b/src/gallium/drivers/freedreno/freedreno_batch.c
@@ -79,7 +79,10 @@ fd_batch_create(struct fd_context *ctx)
 void
 __fd_batch_destroy(struct fd_batch *batch)
 {
+       fd_bc_invalidate_batch(batch);
+
        util_copy_framebuffer_state(&batch->framebuffer, NULL);
+
        fd_ringbuffer_del(batch->draw);
        fd_ringbuffer_del(batch->binning);
        fd_ringbuffer_del(batch->gmem);
@@ -120,6 +123,8 @@ fd_batch_flush(struct fd_batch *batch)
        }
 
        assert(LIST_IS_EMPTY(&batch->used_resources));
+       batch->needs_flush = false;
+       fd_bc_invalidate_batch(batch);
 }
 
 void
diff --git a/src/gallium/drivers/freedreno/freedreno_batch.h 
b/src/gallium/drivers/freedreno/freedreno_batch.h
index 4607250..d500f95 100644
--- a/src/gallium/drivers/freedreno/freedreno_batch.h
+++ b/src/gallium/drivers/freedreno/freedreno_batch.h
@@ -119,6 +119,12 @@ struct fd_batch {
 
        /** list of resources used by currently-unsubmitted batch */
        struct list_head used_resources;
+
+       /** key in batch-cache (if not null): */
+       const void *key;
+
+       /** set of dependent batches.. holds refs to dependent batches: */
+       struct set *dependencies;
 };
 
 struct fd_batch * fd_batch_create(struct fd_context *ctx);
diff --git a/src/gallium/drivers/freedreno/freedreno_batch_cache.c 
b/src/gallium/drivers/freedreno/freedreno_batch_cache.c
new file mode 100644
index 0000000..bd47251
--- /dev/null
+++ b/src/gallium/drivers/freedreno/freedreno_batch_cache.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 Rob Clark <robcl...@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robcl...@freedesktop.org>
+ */
+
+#include "util/hash_table.h"
+#include "util/set.h"
+#include "util/list.h"
+#include "util/u_string.h"
+
+#include "freedreno_batch.h"
+#include "freedreno_batch_cache.h"
+#include "freedreno_context.h"
+#include "freedreno_resource.h"
+
+/* Overview:
+ *
+ *   The batch cache provides lookup for mapping pipe_framebuffer_state
+ *   to a batch.
+ *
+ *   It does this via hashtable, with key that roughly matches the
+ *   pipe_framebuffer_state, as described below.
+ *
+ * Batch Cache hashtable key:
+ *
+ *   To serialize the key, and to avoid dealing with holding a reference to
+ *   pipe_surface's (which hold a reference to pipe_resource and complicate
+ *   the whole refcnting thing), the key is variable length and inline's the
+ *   pertinent details of the pipe_surface.
+ *
+ * Batch:
+ *
+ *   Each batch needs to hold a reference to each resource it depends on (ie.
+ *   anything that needs a mem2gmem).  And a weak reference to resources it
+ *   renders to.  (If both src[n] and dst[n] are not NULL then they are the
+ *   same.)
+ *
+ *   When a resource is destroyed, we need to remove entries in the batch
+ *   cache that reference the resource, to avoid dangling pointer issues.
+ *   So each resource holds a hashset of batches which have reference them
+ *   in their hashtable key.
+ *
+ *   When a batch has weak reference to no more resources (ie. all the
+ *   surfaces it rendered to are destroyed) the batch can be destroyed.
+ *   Could happen in an app that renders and never uses the result.  More
+ *   common scenario, I think, will be that some, but not all, of the
+ *   surfaces are destroyed before the batch is submitted.
+ *
+ *   If (for example), batch writes to zsbuf but that surface is destroyed
+ *   before batch is submitted, we can skip gmem2mem (but still need to
+ *   alloc gmem space as before.  If the batch depended on previous contents
+ *   of that surface, it would be holding a reference so the surface would
+ *   not have been destroyed.
+ */
+
+struct key {
+       uint32_t width, height, layers;
+       uint16_t samples, num_surfs;
+       struct {
+               struct pipe_resource *texture;
+               union pipe_surface_desc u;
+               uint16_t pos, format;
+       } surf[0];
+};
+
+static struct key *
+key_alloc(unsigned num_surfs)
+{
+       struct key *key =
+               CALLOC_VARIANT_LENGTH_STRUCT(key, sizeof(key->surf[0]) * 
num_surfs);
+       key->num_surfs = num_surfs;
+       return key;
+}
+
+static uint32_t
+key_hash(const void *_key)
+{
+       const struct key *key = _key;
+       uint32_t hash = _mesa_fnv32_1a_offset_bias;
+       hash = _mesa_fnv32_1a_accumulate_block(hash, key, offsetof(struct key, 
surf[0]));
+       hash = _mesa_fnv32_1a_accumulate_block(hash, key->surf, 
sizeof(key->surf[0]) * key->num_surfs);
+       return hash;
+}
+
+static bool
+key_equals(const void *_a, const void *_b)
+{
+       const struct key *a = _a;
+       const struct key *b = _b;
+       return (memcmp(a, b, offsetof(struct key, surf[0])) == 0) &&
+               (memcmp(a->surf, b->surf, sizeof(a->surf[0]) * a->num_surfs) == 
0);
+}
+
+void
+fd_bc_init(struct fd_batch_cache *cache)
+{
+       cache->ht = _mesa_hash_table_create(NULL, key_hash, key_equals);
+}
+
+void
+fd_bc_fini(struct fd_batch_cache *cache)
+{
+       _mesa_hash_table_destroy(cache->ht, NULL);
+}
+
+uint32_t
+fd_bc_flush(struct fd_batch_cache *cache)
+{
+       struct hash_entry *entry;
+       uint32_t timestamp = 0;
+
+       hash_table_foreach(cache->ht, entry) {
+               struct fd_batch *batch = NULL;
+               fd_batch_reference(&batch, (struct fd_batch *)entry->data);
+               fd_batch_flush(batch);
+               timestamp = MAX2(timestamp, 
fd_ringbuffer_timestamp(batch->gmem));
+               fd_batch_reference(&batch, NULL);
+       }
+
+       return timestamp;
+}
+
+void
+fd_bc_invalidate_batch(struct fd_batch *batch)
+{
+       struct fd_batch_cache *cache = &batch->ctx->batch_cache;
+       struct key *key;
+
+       if (!batch->key)
+               return;
+
+       key = (struct key *)batch->key;
+
+       for (unsigned idx = 0; idx < key->num_surfs; idx++) {
+               struct fd_resource *rsc = fd_resource(key->surf[idx].texture);
+               struct set_entry *entry = _mesa_set_search(rsc->batches, batch);
+               _mesa_set_remove(rsc->batches, entry);
+       }
+
+       struct hash_entry *entry = _mesa_hash_table_search(cache->ht, key);
+       _mesa_hash_table_remove(cache->ht, entry);
+
+       batch->key = NULL;
+       free(key);
+}
+
+void
+fd_bc_invalidate_resource(struct fd_resource *rsc)
+{
+       struct set_entry *entry;
+
+       if (!rsc->batches)
+               return;
+
+       set_foreach(rsc->batches, entry)
+               fd_bc_invalidate_batch((struct fd_batch *)entry->key);
+
+       _mesa_set_destroy(rsc->batches, NULL);
+       rsc->batches = NULL;
+}
+
+static struct fd_batch *
+batch_from_key(struct fd_batch_cache *cache, struct key *key,
+               struct fd_context *ctx)
+{
+       struct fd_batch *batch = NULL;
+       uint32_t hash = key_hash(key);
+       struct hash_entry *entry =
+               _mesa_hash_table_search_pre_hashed(cache->ht, hash, key);
+
+       if (entry) {
+               free(key);
+               fd_batch_reference(&batch, (struct fd_batch *)entry->data);
+               return batch;
+       }
+
+       batch = fd_batch_create(ctx);
+       if (!batch)
+               return NULL;
+
+       _mesa_hash_table_insert_pre_hashed(cache->ht, hash, key, batch);
+       batch->key = key;
+
+       for (unsigned idx = 0; idx < key->num_surfs; idx++) {
+               struct fd_resource *rsc = fd_resource(key->surf[idx].texture);
+               if (!rsc->batches) {
+                       rsc->batches = _mesa_set_create(NULL, 
_mesa_hash_pointer,
+                                       _mesa_key_pointer_equal);
+               }
+
+               _mesa_set_add(rsc->batches, batch);
+       }
+
+       return batch;
+}
+
+static void
+key_surf(struct key *key, unsigned idx, unsigned pos, struct pipe_surface 
*psurf)
+{
+       key->surf[idx].texture = psurf->texture;
+       key->surf[idx].u = psurf->u;
+       key->surf[idx].pos = pos;
+       key->surf[idx].format = psurf->format;
+}
+
+struct fd_batch *
+fd_batch_from_fb(struct fd_batch_cache *cache, struct fd_context *ctx,
+               const struct pipe_framebuffer_state *pfb)
+{
+       unsigned idx = 0, n = pfb->nr_cbufs + (pfb->zsbuf ? 1 : 0);
+       struct key *key = key_alloc(n);
+
+       key->width = pfb->width;
+       key->height = pfb->height;
+       key->layers = pfb->layers;
+       key->samples = pfb->samples;
+
+       if (pfb->zsbuf)
+               key_surf(key, idx++, 0, pfb->zsbuf);
+
+       for (unsigned i = 0; i < pfb->nr_cbufs; i++)
+               key_surf(key, idx++, i + 1, pfb->cbufs[i]);
+
+       return batch_from_key(cache, key, ctx);
+}
diff --git a/src/gallium/drivers/freedreno/freedreno_batch_cache.h 
b/src/gallium/drivers/freedreno/freedreno_batch_cache.h
new file mode 100644
index 0000000..2daab6c
--- /dev/null
+++ b/src/gallium/drivers/freedreno/freedreno_batch_cache.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Rob Clark <robcl...@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robcl...@freedesktop.org>
+ */
+
+#ifndef FREEDRENO_BATCH_CACHE_H_
+#define FREEDRENO_BATCH_CACHE_H_
+
+#include "pipe/p_state.h"
+
+#include "freedreno_batch.h"
+
+struct hash_table;
+
+struct fd_batch_cache {
+       struct hash_table *ht;
+};
+
+void fd_bc_init(struct fd_batch_cache *cache);
+void fd_bc_fini(struct fd_batch_cache *cache);
+
+uint32_t fd_bc_flush(struct fd_batch_cache *cache);
+
+void fd_bc_invalidate_resource(struct fd_resource *rsc);
+void fd_bc_invalidate_batch(struct fd_batch *batch);
+
+struct fd_batch * fd_batch_from_fb(struct fd_batch_cache *cache,
+               struct fd_context *ctx, const struct pipe_framebuffer_state 
*pfb);
+
+#endif /* FREEDRENO_BATCH_CACHE_H_ */
diff --git a/src/gallium/drivers/freedreno/freedreno_context.c 
b/src/gallium/drivers/freedreno/freedreno_context.c
index ce30833..4359fb2 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.c
+++ b/src/gallium/drivers/freedreno/freedreno_context.c
@@ -110,6 +110,8 @@ fd_context_destroy(struct pipe_context *pctx)
 
        DBG("");
 
+       fd_bc_fini(&ctx->batch_cache);
+
        fd_prog_fini(pctx);
        fd_hw_query_fini(pctx);
 
@@ -197,6 +199,8 @@ fd_context_init(struct fd_context *ctx, struct pipe_screen 
*pscreen,
        if (!ctx->primconvert)
                goto fail;
 
+       fd_bc_init(&ctx->batch_cache);
+
        return pctx;
 
 fail:
diff --git a/src/gallium/drivers/freedreno/freedreno_context.h 
b/src/gallium/drivers/freedreno/freedreno_context.h
index 92d14bb..6be7437 100644
--- a/src/gallium/drivers/freedreno/freedreno_context.h
+++ b/src/gallium/drivers/freedreno/freedreno_context.h
@@ -37,6 +37,7 @@
 #include "util/u_string.h"
 
 #include "freedreno_batch.h"
+#include "freedreno_batch_cache.h"
 #include "freedreno_screen.h"
 #include "freedreno_gmem.h"
 #include "freedreno_util.h"
@@ -141,6 +142,8 @@ struct fd_context {
        struct fd_device *dev;
        struct fd_screen *screen;
 
+       struct fd_batch_cache batch_cache;
+
        struct blitter_context *blitter;
        struct primconvert_context *primconvert;
 
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c 
b/src/gallium/drivers/freedreno/freedreno_resource.c
index a35dc90..4fd8559 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.c
+++ b/src/gallium/drivers/freedreno/freedreno_resource.c
@@ -35,6 +35,7 @@
 #include "util/u_surface.h"
 
 #include "freedreno_resource.h"
+#include "freedreno_batch_cache.h"
 #include "freedreno_screen.h"
 #include "freedreno_surface.h"
 #include "freedreno_context.h"
@@ -451,6 +452,7 @@ fd_resource_destroy(struct pipe_screen *pscreen,
                struct pipe_resource *prsc)
 {
        struct fd_resource *rsc = fd_resource(prsc);
+       fd_bc_invalidate_resource(rsc);
        if (rsc->bo)
                fd_bo_del(rsc->bo);
        fd_batch_reference(&rsc->pending_batch, NULL);
diff --git a/src/gallium/drivers/freedreno/freedreno_resource.h 
b/src/gallium/drivers/freedreno/freedreno_resource.h
index f8131c7..3b990a9 100644
--- a/src/gallium/drivers/freedreno/freedreno_resource.h
+++ b/src/gallium/drivers/freedreno/freedreno_resource.h
@@ -70,6 +70,8 @@ enum fd_resource_status {
        FD_PENDING_READ  = 0x02,
 };
 
+struct set;
+
 struct fd_resource {
        struct u_resource base;
        struct fd_bo *bo;
@@ -88,11 +90,15 @@ struct fd_resource {
 
        /* pending read/write state: */
        enum fd_resource_status status;
+
        /* resources accessed by queued but not flushed draws are tracked
         * in the used_resources list.
         */
        struct list_head list;
        struct fd_batch *pending_batch;
+
+       /* set of batches whose batch-cache key references this resource: */
+       struct set *batches;
 };
 
 static inline struct fd_resource *
-- 
2.7.4

_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno

Reply via email to