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 <thellst...@vmware.com> Reviewed-by: Brian Paul <bri...@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 <thellst...@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 <thellst...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev