[Mesa-dev] [RFC PATCH 2/7] gallium/util Add a bounce buffer cache utility v2

Thomas Hellstrom thellstrom at vmware.com
Thu Mar 2 20:00:06 UTC 2017


The bounce buffer cache is suitable for small caches of temporary GPU
pixel buffers. It's useful for state-trackers that have a more detailed
knowledge of when it's suitable to cache buffers than drivers have and
where the buffers are not accessed by the CPU.

Testing done: Replaced the vdpau state tracker mixer bounce buffers with
util_bounce buffers and played a couple of videos with various filters
enabled.

v2: Addressed review comments, documented testing.

Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
Reviewed-by: Brian Paul <brianp at vmware.com>
---
 src/gallium/auxiliary/Makefile.sources |   2 +
 src/gallium/auxiliary/util/u_bounce.c  | 326 +++++++++++++++++++++++++++++++++
 src/gallium/auxiliary/util/u_bounce.h  |  85 +++++++++
 3 files changed, 413 insertions(+)
 create mode 100644 src/gallium/auxiliary/util/u_bounce.c
 create mode 100644 src/gallium/auxiliary/util/u_bounce.h

diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
index 18a822f..32f0128 100644
--- a/src/gallium/auxiliary/Makefile.sources
+++ b/src/gallium/auxiliary/Makefile.sources
@@ -189,6 +189,8 @@ C_SOURCES := \
 	util/u_blit.h \
 	util/u_blitter.c \
 	util/u_blitter.h \
+	util/u_bounce.h \
+	util/u_bounce.c \
 	util/u_box.h \
 	util/u_cache.c \
 	util/u_cache.h \
diff --git a/src/gallium/auxiliary/util/u_bounce.c b/src/gallium/auxiliary/util/u_bounce.c
new file mode 100644
index 0000000..9a99101
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_bounce.c
@@ -0,0 +1,326 @@
+/**************************************************************************
+ *
+ * Copyright 2016 VMware Inc.
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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.
+ *
+ *************************************************************************/
+/**
+ * \author Thomas Hellstrom <thellstrom at vmware.com>
+ */
+#include "util/u_bounce.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+#include "util/u_sampler.h"
+#include "util/list.h"
+#include "pipe/p_state.h"
+#include "stddef.h"
+
+/**
+ * \brief The key used to describe the texture usage.
+ */
+struct util_bounce_key {
+   unsigned width;                  /**< Texture width */
+   unsigned height;                 /**< Texture height */
+   enum pipe_format format;         /**< Texture format */
+};
+
+/**
+ *\brief Bounce buffer structure holding the texture and its views
+ */
+struct util_bounce {
+   struct util_bounce_key key;      /**< Key as described above */
+   struct list_head head;           /**< List head for bounce buffer list */
+   struct pipe_resource *texture;   /**< The texture resource */
+   struct pipe_sampler_view *sv;    /**< Sampler view if any */
+   struct pipe_surface *surface;    /**< Surface if any */
+   struct util_bounce_cache *cache; /**< Cache this bounce buffer belongs to */
+};
+
+/**
+ *\brief The cache structure
+ */
+struct util_bounce_cache {
+   struct list_head list;           /**< The list of bounce buffers */
+   unsigned count;                  /**< Current number of bounce buffers*/
+   unsigned max_entries;            /**< Max number of bounce buffers */
+   enum pipe_texture_target target; /**< Texture target for texture creation */
+   struct pipe_context *pipe;       /**< Gallium context for views */
+};
+
+/**
+ * \brief Destroy a bounce buffer.
+ *
+ * \param bounce[in,out]  The bounce buffer.
+ */
+static void
+util_bounce_destroy(struct util_bounce *bounce)
+{
+   pipe_surface_reference(&bounce->surface, NULL);
+   pipe_sampler_view_reference(&bounce->sv, NULL);
+   pipe_resource_reference(&bounce->texture, NULL);
+   FREE(bounce);
+}
+
+/**
+ * \brief Retrieve a (potentially cached) gallium surface from a bounce buffer.
+ *
+ * \param bounce[in,out]  The bounce buffer.
+ * \return a non-refcounted surface pointer. The caller is responsible for
+ * reference counting the surface if needed.
+ */
+struct pipe_surface *
+util_bounce_surface(struct util_bounce *bounce)
+{
+   if (!bounce->surface) {
+      struct pipe_context *pipe = bounce->cache->pipe;
+      struct pipe_surface stempl;
+
+      u_surface_default_template(&stempl, bounce->texture);
+      bounce->surface = pipe->create_surface(pipe, bounce->texture, &stempl);
+   }
+
+   return bounce->surface;
+}
+
+/**
+ * \brief Retrieve a (potentially cached) gallium sampler view from a
+ * bounce buffer.
+ *
+ * \param bounce[in,out]  The bounce buffer.
+ * \return a non-refcounted sampler view pointer. The caller is responsible for
+ * reference counting the sampler view if needed.
+ */
+struct pipe_sampler_view *
+util_bounce_sampler_view(struct util_bounce *bounce)
+{
+   if (!bounce->sv) {
+      struct pipe_sampler_view svtempl;
+      struct pipe_context *pipe = bounce->cache->pipe;
+
+      u_sampler_view_default_template(&svtempl, bounce->texture,
+                                      bounce->key.format);
+      bounce->sv = pipe->create_sampler_view(pipe, bounce->texture, &svtempl);
+   }
+
+   return bounce->sv;
+}
+
+/**
+ * \brief Retrieve a gallium texture from a bounce buffer
+ * \param bounce[in]  The bounce buffer.
+ * \return a non-refcounted resource pointer. The caller is responsible for
+ * reference counting the resource if needed.
+ */
+struct pipe_resource *
+util_bounce_texture(struct util_bounce *bounce)
+{
+   return bounce->texture;
+}
+
+/**
+ * \brief Get a new bounce buffer
+ *
+ * Gets a new bounce buffer from the cache or if there is no match in the
+ * cache, create one. After successful return, the bounce buffer is not
+ * present in the cache, but will be added to the cache at util_bounce_put().
+ *
+ * \param cache[in,out]  The bounce buffer cache.
+ * \param width[in]  Texture width.
+ * \param height[in]  Texture height.
+ * \param format[in]  Texture format.
+ * \param precreate_surface[in]  Precreate surface to avoid future errors.
+ * \param precreate_sv[in]  Precreate sampler view to avoid future errors.
+ * \return A bounce buffer or NULL on error.
+ */
+struct util_bounce *
+util_bounce_get(struct util_bounce_cache *cache,
+                unsigned width,
+                unsigned height,
+                enum pipe_format format,
+                boolean precreate_surface,
+                boolean precreate_sv)
+{
+   struct util_bounce *tmp;
+   boolean found = FALSE;
+
+   /*
+    * The lookup mechanism here is very simple and suitable for a small
+    * number of entries. We could use u_cache.c, but it would then
+    * have to be modified to be able to hold multiple entries with identical
+    * keys.
+    */
+   LIST_FOR_EACH_ENTRY(tmp, &cache->list, head) {
+      if (tmp->key.width == width && tmp->key.height == height &&
+          tmp->key.format == format) {
+         list_del(&tmp->head);
+         cache->count--;
+         found = TRUE;
+         break;
+      }
+   }
+
+   if (!found) {
+      struct pipe_resource templ;
+      struct pipe_screen *screen = cache->pipe->screen;
+
+      tmp = CALLOC_STRUCT(util_bounce);
+      if (!tmp)
+         return NULL;
+
+      memset(&templ, 0, sizeof(templ));
+      templ.target = cache->target;
+      templ.format = format;
+      templ.width0 = width;
+      templ.height0 = height;
+      templ.depth0 = 1;
+      templ.array_size = 1;
+      templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+
+      tmp->texture = screen->resource_create(screen, &templ);
+      if (!tmp->texture)
+         goto out_no_bounce;
+
+      tmp->key.width = width;
+      tmp->key.height = height;
+      tmp->key.format = format;
+      tmp->cache = cache;
+   }
+
+   if (precreate_surface && !util_bounce_surface(tmp))
+      goto out_no_bounce;
+
+   if (precreate_sv && !util_bounce_sampler_view(tmp))
+      goto out_no_bounce;
+
+   return tmp;
+
+ out_no_bounce:
+   util_bounce_destroy(tmp);
+   return NULL;
+}
+
+/**
+ * \brief Destroy the first (oldest) bounce buffer in the cache.
+ *
+ * \param cache[in,out]  The bounce buffer cache.
+ */
+static void
+util_bounce_destroy_first_entry(struct util_bounce_cache *cache)
+{
+   struct util_bounce *bounce =
+      list_first_entry(&cache->list, struct util_bounce, head);
+
+   list_del(&bounce->head);
+   cache->count--;
+   util_bounce_destroy(bounce);
+}
+
+/**
+ * \brief Release a bounce buffer to the cache it was created from.
+ * This adds the entry to the cache for reuse and if the cache maximum
+ * number of entries are exceeded removes the oldest entry in the cache.
+ *
+ * \param bounce[in,out]  The bounce buffer.
+ */
+void
+util_bounce_put(struct util_bounce *bounce)
+{
+   struct util_bounce_cache *cache = bounce->cache;
+
+   list_addtail(&bounce->head, &cache->list);
+   cache->count++;
+   if (cache->count > cache->max_entries)
+      util_bounce_destroy_first_entry(cache);
+}
+
+/**
+ * \brief Get a new bounce buffer, using an old one as a template.
+ *
+ * Gets a new bounce buffer from the cache or if there is no match in the
+ * cache, create one. After successful return, the bounce buffer is not
+ * present in the cache, but will be added to the cache at util_bounce_put().
+ *
+ * \param cache[in,out]  The bounce buffer cache.
+ * \param template[in]  The template to be used for bounce buffer traits.
+ * \param precreate_surface[in]  Precreate surface to avoid future errors.
+ * \param precreate_sv[in]  Precreate sampler view to avoid future errors.
+ * \return A bounce buffer or NULL on error.
+ */
+struct util_bounce *
+util_bounce_clone(struct util_bounce_cache *cache,
+                  const struct util_bounce *template,
+                  boolean precreate_surface,
+                  boolean precreate_sv)
+{
+   const struct pipe_resource *texture = template->texture;
+
+   return util_bounce_get(cache, texture->width0, texture->height0,
+                          texture->format, precreate_surface,
+                          precreate_sv);
+}
+
+/**
+ * \brief Create a bounce buffer cache.
+ *
+ * \param pipe[in]  The pipe context to be used for surfaces and sampler views.
+ * \param target[in]  Target for texture creation. Only PIPE_TEXTURE_2D and
+ * PIPE_TEXTURE_RECT allowed for now.
+ * \param size[in]  Maximum number of bounce buffers in the cache.
+ * \return A pointer to a bounce buffer cache or NULL if creation failed.
+ */
+struct util_bounce_cache *
+util_bounce_cache_create(struct pipe_context *pipe,
+                         enum pipe_texture_target target,
+                         unsigned max_entries)
+{
+   struct util_bounce_cache *cache;
+
+   cache = CALLOC_STRUCT(util_bounce_cache);
+   if (!cache)
+      return NULL;
+
+   assert(target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_RECT);
+   cache->pipe = pipe;
+   cache->target = target;
+   cache->max_entries = max_entries;
+   list_inithead(&cache->list);
+
+   return cache;
+}
+
+/**
+ * \brief Destroy a bounce buffer cache.
+ *
+ * \param cache[in,out]  The cache to destroy.
+ */
+void
+util_bounce_cache_destroy(struct util_bounce_cache *cache)
+{
+   while (cache->count)
+      util_bounce_destroy_first_entry(cache);
+
+   FREE(cache);
+}
diff --git a/src/gallium/auxiliary/util/u_bounce.h b/src/gallium/auxiliary/util/u_bounce.h
new file mode 100644
index 0000000..08c4ff6
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_bounce.h
@@ -0,0 +1,85 @@
+/**************************************************************************
+ *
+ * Copyright 2016 VMware Inc.
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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.
+ *
+ *************************************************************************/
+/**
+ * \author Thomas Hellstrom <thellstrom at vmware.com>
+ */
+#ifndef _U_BOUNCE_H_
+#define _U_BOUNCE_H_
+
+#include "pipe/p_context.h"
+
+/*
+ * A bounce buffer consists of a gallium texture, and optionally a gallium
+ * sampler view and a surface. It's used as a temporary storage for gpu
+ * pixel data.
+ * This utility is Intended for small caches (up to 10 or so due to a simple
+ * cache lookup mechanism) of bounce buffers that are never touched by the CPU
+ * and thus are, once present in the cache, considered free for immediate
+ * reuse by the GPU.
+ * Typical examples are bounce buffers used by the video postprocessor
+ * pipeline.
+ */
+struct util_bounce;
+struct util_bounce_cache;
+
+struct util_bounce_cache *
+util_bounce_cache_create(struct pipe_context *pipe,
+                         enum pipe_texture_target target,
+                         unsigned max_entries);
+
+void
+util_bounce_cache_destroy(struct util_bounce_cache *cache);
+
+struct pipe_sampler_view *
+util_bounce_sampler_view(struct util_bounce *bounce);
+
+struct pipe_surface *
+util_bounce_surface(struct util_bounce *bounce);
+
+struct pipe_resource *
+util_bounce_texture(struct util_bounce *bounce);
+
+struct util_bounce *
+util_bounce_get(struct util_bounce_cache *cache,
+                unsigned width,
+                unsigned height,
+                enum pipe_format format,
+                boolean precreate_surface,
+                boolean precreate_sv);
+
+struct util_bounce *
+util_bounce_clone(struct util_bounce_cache *cache,
+                  const struct util_bounce *template,
+                  boolean precreate_surface,
+                  boolean precreate_sv);
+
+void
+util_bounce_put(struct util_bounce *bounce);
+
+#endif
-- 
2.4.11



More information about the mesa-dev mailing list