[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