<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Feb 23, 2018 at 1:26 AM, Jose Maria Casanova Crespo <span dir="ltr"><<a href="mailto:jmcasanova@igalia.com" target="_blank">jmcasanova@igalia.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The surfaces that backup the GPU buffers have a boundary check that<br>
considers that access to partial dwords are considered out-of-bounds.<br>
For example is basic 16-bit cases of buffers with size 2 or 6 where the<br>
last two bytes will always be read as 0 or its writting ignored.<br>
<br>
The introduction of 16-bit types implies that we need to align the size<br>
to 4-bytes multiples so that partial dwords could be read/written.<br>
Adding an inconditional +2 size to buffers not being multiple of 2<br>
solves this issue for the general cases of UBO or SSBO.<br>
<br>
But, when unsized_arrays of 16-bit elements are used it is not possible<br>
to know if the size was padded or not. To solve this issue the<br>
implementation of SSBO calculates the needed size of the surface,<br>
as suggested by Jason:<br>
<br>
surface_size = 2 * aling_u64(buffer_size, 4)  - buffer_size<br>
<br>
So when we calculate backwards the SpvOpArrayLenght with a nir expresion<br>
when the array stride is not multiple of 4.<br>
<br>
array_size = (surface_size & ~3) - (surface_size & 3)<br>
<br>
It is also exposed this buffer requirements when robust buffer access<br>
is enabled so these buffer sizes recommend being multiple of 4.<br>
---<br>
<br>
I have some doubts if vtn_variables.c is the best place to include<br>
this specific to calculate the real buffer size as this is new<br>
calculus seems to be quite HW dependent and maybe other drivers different<br>
to ANV don't need this kind of solution.<br>
<br>
 src/compiler/spirv/vtn_<wbr>variables.c    | 14 ++++++++++++++<br>
 src/intel/vulkan/anv_<wbr>descriptor_set.c | 16 ++++++++++++++++<br>
 src/intel/vulkan/anv_device.c         | 11 +++++++++++<br>
 3 files changed, 41 insertions(+)<br>
<br>
diff --git a/src/compiler/spirv/vtn_<wbr>variables.c b/src/compiler/spirv/vtn_<wbr>variables.c<br>
index 9eb85c24e9..78adab3ed2 100644<br>
--- a/src/compiler/spirv/vtn_<wbr>variables.c<br>
+++ b/src/compiler/spirv/vtn_<wbr>variables.c<br>
@@ -2113,6 +2113,20 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,<br>
       nir_builder_instr_insert(&b-><wbr>nb, &instr->instr);<br>
       nir_ssa_def *buf_size = &instr->dest.ssa;<br>
<br>
+      /* Calculate real length if padding was done to align the buffer<br>
+       * to 32-bits. This only could happen is stride is not multiple<br>
+       * of 4. Introduced to support 16-bit type unsized arrays in anv.<br>
+       */<br>
+      if (stride % 4) {<br>
+         buf_size = nir_isub(&b->nb,<br>
+                             nir_iand(&b->nb,<br>
+                                      buf_size,<br>
+                                      nir_imm_int(&b->nb, ~3)),<br>
+                             nir_iand (&b->nb,<br>
+                                       buf_size,<br>
+                                       nir_imm_int(&b->nb, 3)));<br></blockquote><div><br></div><div>We can't do this in spirv_to_nir as it's also used by radv and they may not have the same issue.  Instead, we need to handle it either in anv_nir_apply_pipeline_layout or in the back-end compiler.  Doing it here has the advantage that we can only do it in the "stride % 4 != 0" case but I don't think the three instructions are all that big of a deal given that we just did a send and are about to do an integer divide.  My preference would be to put most of it in ISL and the back-end compiler if we can.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      }<br>
+<br>
       /* array_length = max(buffer_size - offset, 0) / stride */<br>
       nir_ssa_def *array_length =<br>
          nir_idiv(&b->nb,<br>
diff --git a/src/intel/vulkan/anv_<wbr>descriptor_set.c b/src/intel/vulkan/anv_<wbr>descriptor_set.c<br>
index edb829601e..a97f2f37dc 100644<br>
--- a/src/intel/vulkan/anv_<wbr>descriptor_set.c<br>
+++ b/src/intel/vulkan/anv_<wbr>descriptor_set.c<br>
@@ -704,6 +704,22 @@ anv_descriptor_set_write_<wbr>buffer(struct anv_descriptor_set *set,<br>
       bview->offset = buffer->offset + offset;<br>
       bview->range = anv_buffer_get_range(buffer, offset, range);<br>
<br>
+      /* Uniform and Storage buffers need to have surface size<br>
+       * not less that the aligned 32-bit size of the buffer.<br>
+       * To calculate the array lenght on unsized arrays<br>
+       * in StorageBuffer the last 2 bits store the padding size<br>
+       * added to the surface, so we can calculate latter the original<br>
+       * buffer size to know the number of elements.<br>
+       *<br>
+       *  surface_size = 2 * aling_u64(buffer_size, 4)  - buffer_size<br>
+       *<br>
+       *  array_size = (surface_size & ~3) - (surface_size & 3)<br>
+       */<br>
+      if (type == VK_DESCRIPTOR_TYPE_STORAGE_<wbr>BUFFER)<br>
+         bview->range = 2 * align_u64(bview->range, 4) - bview->range;<br>
+      else if (type == VK_DESCRIPTOR_TYPE_UNIFORM_<wbr>BUFFER)<br>
+         bview->range = align_u64(bview->range, 4);<br></blockquote><div><br></div><div>We chatted on another e-mail about doing this in ISL instead of here but you mentioned issues with failing GL tests.  Did you ever get to the bottom of those?  If so, what was the conclusion?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
       /* If we're writing descriptors through a push command, we need to<br>
        * allocate the surface state from the command buffer. Otherwise it will<br>
        * be allocated by the descriptor pool when calling<br>
diff --git a/src/intel/vulkan/anv_device.<wbr>c b/src/intel/vulkan/anv_device.<wbr>c<br>
index a83b7a39f6..cedeed5621 100644<br>
--- a/src/intel/vulkan/anv_device.<wbr>c<br>
+++ b/src/intel/vulkan/anv_device.<wbr>c<br>
@@ -2103,6 +2103,17 @@ void anv_<wbr>GetBufferMemoryRequirements(<br>
<br>
    pMemoryRequirements->size = buffer->size;<br>
    pMemoryRequirements->alignment = alignment;<br>
+<br>
+   /* Storage and Uniform buffers should have their size aligned to<br>
+    * 32-bits to avoid boundary checks when last DWord is not complete.<br>
+    * This would ensure that not internal padding would be needed for<br>
+    * 16-bit types.<br>
+    */<br>
+   if (device->robust_buffer_access &&<br>
+       (buffer->usage & VK_BUFFER_USAGE_UNIFORM_<wbr>BUFFER_BIT ||<br>
+        buffer->usage & VK_BUFFER_USAGE_STORAGE_<wbr>BUFFER_BIT))<br>
+      pMemoryRequirements->size = align_u64(buffer->size, 4);<br>
+<br>
    pMemoryRequirements-><wbr>memoryTypeBits = memory_types;<br>
 }<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
2.14.3<br>
<br>
______________________________<wbr>_________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>