<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Apr 7, 2017 at 1:26 PM, Chris Wilson <span dir="ltr"><<a href="mailto:chris@chris-wilson.co.uk" target="_blank">chris@chris-wilson.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Fri, Apr 07, 2017 at 12:55:53PM -0700, Jason Ekstrand wrote:<br>
> We tend to try to reduce the number of allocation calls the Vulkan<br>
> driver uses by doing a single allocation whenever possible for a data<br>
> structure.  While this has certain downsides (usually code complexity),<br>
> it does mean error handling and cleanup is much easier.  This commit<br>
> adds a nice little helper struct for getting rid of some of that<br>
> complexity.<br>
> ---<br>
>  src/intel/vulkan/anv_private.h | 77 ++++++++++++++++++++++++++++++<wbr>++++++++++++<br>
>  1 file changed, 77 insertions(+)<br>
><br>
> diff --git a/src/intel/vulkan/anv_<wbr>private.h b/src/intel/vulkan/anv_<wbr>private.h<br>
> index 90974d9..f941cc7 100644<br>
> --- a/src/intel/vulkan/anv_<wbr>private.h<br>
> +++ b/src/intel/vulkan/anv_<wbr>private.h<br>
> @@ -269,6 +269,83 @@ void anv_loge_v(const char *format, va_list va);<br>
>  #define anv_assert(x)<br>
>  #endif<br>
><br>
> +struct anv_multialloc {<br>
> +    size_t size;<br>
> +    size_t align;<br>
> +<br>
> +    uint32_t ptr_count;<br>
> +    void **ptrs[8];<br>
> +};<br>
> +<br>
> +#define ANV_MULTIALLOC_INIT \<br>
> +   ((struct anv_multialloc) { 0, })<br>
> +<br>
> +#define ANV_MULTIALLOC(_name) \<br>
> +   struct anv_multialloc _name = ANV_MULTIALLOC_INIT<br>
> +<br>
> +static inline void<br>
> +_anv_multialloc_add(struct anv_multialloc *ma,<br>
> +                    void **ptr, size_t size, size_t align)<br>
> +{<br>
> +   size_t offset = align_u64(ma->size, align);<br>
> +   ma->size = offset + size;<br>
> +   ma->align = MAX2(ma->align, align);<br>
> +<br>
> +   /* Store the offset in the pointer. */<br>
> +   *ptr = (void *)(uintptr_t)offset;<br>
> +<br>
> +   assert(ma->ptr_count < ARRAY_SIZE(ma->ptrs));<br>
> +   ma->ptrs[ma->ptr_count++] = ptr;<br>
> +}<br>
> +<br>
> +#define anv_multialloc_add(_ma, _ptr, _count) \<br>
> +   _anv_multialloc_add((_ma), (void **)(_ptr), \<br>
> +                       (_count) * sizeof(**(_ptr)), __alignof__(**(_ptr)))<br>
> +<br>
> +static inline void *<br>
> +anv_multialloc_alloc(struct anv_multialloc *ma,<br>
> +                     const VkAllocationCallbacks *alloc,<br>
> +                     VkSystemAllocationScope scope)<br>
> +{<br>
> +   void *ptr = vk_alloc(alloc, ma->size, ma->align, scope);<br>
> +   if (!ptr)<br>
> +      return NULL;<br>
> +<br>
> +   /* Fill out each of the pointers with their final value.<br>
> +    *<br>
> +    *   for (uint32_t i = 0; i < ma->ptr_count; i++)<br>
> +    *      *ma->ptrs[i] = ptr + (uintptr_t)*ma->ptrs[i];<br>
> +    *<br>
> +    * Unfortunately, even though ma->ptr_count is basically guaranteed to be a<br>
> +    * constant, GCC is incapable of figuring this out and unrolling the loop<br>
> +    * so we have to give it a little help.<br>
> +    */<br>
> +   STATIC_ASSERT(ARRAY_SIZE(ma-><wbr>ptrs) == 8);<br>
> +#define _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(_i) \<br>
> +   if ((_i) < ma->ptr_count) \<br>
> +      *ma->ptrs[_i] = ptr + (uintptr_t)*ma->ptrs[_i]<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(0);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(1);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(2);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(3);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(4);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(5);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(6);<br>
> +   _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(7);<br>
> +#undef _ANV_MULTIALLOC_UPDATE_POINTER<br>
<br>
</div></div>#define _ANV_MULTIALLOC_UPDATE_<wbr>POINTER(_i) case _i + 1: *ma->ptrs[_i] = ptr +(uintptr)*ma->ptrs[_i]<br>
<br>
switch (ma->ptr_count) {<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(7);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(6);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(5);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(4);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(3);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(2);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(1);<br>
_ANV_MULTIALLOC_UPDATE_<wbr>POINTER(0);<br>
}<br>
<br>
#undef _ANV_MULITALLOC_UPDATE_POINTER<span class="HOEnZb"><font color="#888888"><br></font></span></blockquote><div><br></div><div>If ma->ptr_count is constant, they generate exactly the same code.  If it isn't (i.e. if one of the multialloc_adds is predicated), then they still generate basically the same code with the code for the if version being slightly more straightforward. <br></div></div><br></div></div>