<div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Mar 11, 2019 at 10:05 AM Eleni Maria Stea <<a href="mailto:estea@igalia.com">estea@igalia.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Allowing the user to set custom sample locations non-dynamically, by<br>
filling the extension structs and chaining them to the pipeline structs<br>
according to the Vulkan specification section [26.5. Custom Sample Locations]<br>
for the following structures:<br>
<br>
'VkPipelineSampleLocationsStateCreateInfoEXT'<br>
'VkSampleLocationsInfoEXT'<br>
'VkSampleLocationEXT'<br>
<br>
Once custom locations are used, the default locations are lost and need to be<br>
re-emitted again in the next pipeline creation. For that, we emit the<br>
3DSTATE_SAMPLE_PATTERN at every pipeline creation.<br>
---<br>
 src/intel/common/gen_sample_positions.h | 53 ++++++++++++++++<br>
 src/intel/vulkan/anv_genX.h             |  5 ++<br>
 src/intel/vulkan/anv_private.h          |  9 +++<br>
 src/intel/vulkan/anv_sample_locations.c | 38 +++++++++++-<br>
 src/intel/vulkan/anv_sample_locations.h | 29 +++++++++<br>
 src/intel/vulkan/genX_pipeline.c        | 80 +++++++++++++++++++++----<br>
 src/intel/vulkan/genX_state.c           | 59 ++++++++++++++++++<br>
 7 files changed, 259 insertions(+), 14 deletions(-)<br>
 create mode 100644 src/intel/vulkan/anv_sample_locations.h<br>
<br>
diff --git a/src/intel/common/gen_sample_positions.h b/src/intel/common/gen_sample_positions.h<br>
index da48dcb5ed0..e8af2a552dc 100644<br>
--- a/src/intel/common/gen_sample_positions.h<br>
+++ b/src/intel/common/gen_sample_positions.h<br>
@@ -160,4 +160,57 @@ prefix##14YOffset  = 0.9375; \<br>
 prefix##15XOffset  = 0.0625; \<br>
 prefix##15YOffset  = 0.0000;<br>
<br>
+/* Examples:<br>
+ * in case of GEN_GEN < 8:<br>
+ * SET_SAMPLE_POS(ms.Sample, 0); expands to:<br>
+ *    ms.Sample0XOffset = anv_samples[0].offs_x;<br>
+ *    ms.Sample0YOffset = anv_samples[0].offs_y;<br>
+ *<br>
+ * in case of GEN_GEN >= 8:<br>
+ * SET_SAMPLE_POS(sp._16xSample, 0); expands to:<br>
+ *    sp._16xSample0XOffset = anv_samples[0].offs_x;<br>
+ *    sp._16xSample0YOffset = anv_samples[0].offs_y;<br>
+ */<br>
+#define SET_SAMPLE_POS(prefix, sample_idx) \<br>
+prefix##sample_idx##XOffset = anv_samples[sample_idx].offs_x; \<br>
+prefix##sample_idx##YOffset = anv_samples[sample_idx].offs_y;<br></blockquote><div><br></div><div>I'm not a huge fan of hanving anv-specific stuff in gen_sample_positions.h and I also don't think I really like having the array be implicit in the macro.  Maybe the best thing to do here would be to have a</div><div><br></div><div>struct gen_sample_position {</div><div>   float x_offset;</div><div>   float y_offset;</div><div>}</div><div><br></div><div>And then <br></div><div><br></div><div>#define GEN_SAMPLE_POS_ELEM(prefix, arr, sample_idx) \</div><div>prefix##sample_idx##XOffset = arr[sample_idx].x_offset; \</div><div>prefix##sample_idx##YOffset = arr[sample_idx].y_offset;<br></div><div><br></div><div>And</div><div><br></div><div>#define GEN_SAMPLE_POS_1X_ARRAY(prefix, arr) \</div><div>   SET_SAMPLE_POS_ELEM(prefix, arr, 0)</div><div><br></div><div><div>#define GEN_SAMPLE_POS_2X_ARRAY(prefix, arr) \</div><div>   SET_SAMPLE_POS_ELEM(prefix, arr, 0) \</div><div><div>   SET_SAMPLE_POS_ELEM(prefix, arr, 1)</div><div><br></div><div>etc.<br></div></div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+#define SET_SAMPLE_POS_2X(prefix) \<br>
+SET_SAMPLE_POS(prefix, 0); \<br>
+SET_SAMPLE_POS(prefix, 1);<br>
+<br>
+#define SET_SAMPLE_POS_4X(prefix) \<br>
+SET_SAMPLE_POS(prefix, 0); \<br>
+SET_SAMPLE_POS(prefix, 1); \<br>
+SET_SAMPLE_POS(prefix, 2); \<br>
+SET_SAMPLE_POS(prefix, 3);<br>
+<br>
+#define SET_SAMPLE_POS_8X(prefix) \<br>
+SET_SAMPLE_POS(prefix, 0); \<br>
+SET_SAMPLE_POS(prefix, 1); \<br>
+SET_SAMPLE_POS(prefix, 2); \<br>
+SET_SAMPLE_POS(prefix, 3); \<br>
+SET_SAMPLE_POS(prefix, 4); \<br>
+SET_SAMPLE_POS(prefix, 5); \<br>
+SET_SAMPLE_POS(prefix, 6); \<br>
+SET_SAMPLE_POS(prefix, 7);<br>
+<br>
+#define SET_SAMPLE_POS_16X(prefix) \<br>
+SET_SAMPLE_POS(prefix, 0); \<br>
+SET_SAMPLE_POS(prefix, 1); \<br>
+SET_SAMPLE_POS(prefix, 2); \<br>
+SET_SAMPLE_POS(prefix, 3); \<br>
+SET_SAMPLE_POS(prefix, 4); \<br>
+SET_SAMPLE_POS(prefix, 5); \<br>
+SET_SAMPLE_POS(prefix, 6); \<br>
+SET_SAMPLE_POS(prefix, 7); \<br>
+SET_SAMPLE_POS(prefix, 8); \<br>
+SET_SAMPLE_POS(prefix, 9); \<br>
+SET_SAMPLE_POS(prefix, 10); \<br>
+SET_SAMPLE_POS(prefix, 11); \<br>
+SET_SAMPLE_POS(prefix, 12); \<br>
+SET_SAMPLE_POS(prefix, 13); \<br>
+SET_SAMPLE_POS(prefix, 14); \<br>
+SET_SAMPLE_POS(prefix, 15);<br>
+<br>
 #endif /* GEN_SAMPLE_POSITIONS_H */<br>
diff --git a/src/intel/vulkan/anv_genX.h b/src/intel/vulkan/anv_genX.h<br>
index 8fd32cabf1e..52415c04a45 100644<br>
--- a/src/intel/vulkan/anv_genX.h<br>
+++ b/src/intel/vulkan/anv_genX.h<br>
@@ -88,3 +88,8 @@ void genX(cmd_buffer_mi_memset)(struct anv_cmd_buffer *cmd_buffer,<br>
<br>
 void genX(blorp_exec)(struct blorp_batch *batch,<br>
                       const struct blorp_params *params);<br>
+<br>
+void genX(emit_sample_locations)(struct anv_batch *batch,<br>
+                                 uint32_t num_samples,<br>
+                                 const VkSampleLocationsInfoEXT *sl,<br>
+                                 bool custom_locations);<br>
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h<br>
index 5905299e59d..981956e5706 100644<br>
--- a/src/intel/vulkan/anv_private.h<br>
+++ b/src/intel/vulkan/anv_private.h<br>
@@ -71,6 +71,7 @@ struct anv_buffer;<br>
 struct anv_buffer_view;<br>
 struct anv_image_view;<br>
 struct anv_instance;<br>
+struct anv_sample;<br>
<br>
 struct gen_l3_config;<br>
<br>
@@ -165,6 +166,7 @@ struct gen_l3_config;<br>
 #define MAX_PUSH_DESCRIPTORS 32 /* Minimum requirement */<br>
 #define MAX_INLINE_UNIFORM_BLOCK_SIZE 4096<br>
 #define MAX_INLINE_UNIFORM_BLOCK_DESCRIPTORS 32<br>
+#define MAX_SAMPLE_LOCATIONS 16<br>
<br>
 /* The kernel relocation API has a limitation of a 32-bit delta value<br>
  * applied to the address before it is written which, in spite of it being<br>
@@ -2086,6 +2088,13 @@ struct anv_push_constants {<br>
    struct brw_image_param images[MAX_GEN8_IMAGES];<br>
 };<br>
<br>
+struct<br>
+anv_sample {<br>
+   float offs_x;<br>
+   float offs_y;<br>
+   float radius;<br>
+};<br></blockquote><div><br></div><div>Here, you could either embed a gen_sample_pos struct or you could just use it directly and calculate the radius on the fly in the comparison function.  That radius computation isn't so expensive that I'd worry about it on a qsort of 16 sample locations.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
 struct anv_dynamic_state {<br>
    struct {<br>
       uint32_t                                  count;<br>
diff --git a/src/intel/vulkan/anv_sample_locations.c b/src/intel/vulkan/anv_sample_locations.c<br>
index 1ebf280e05b..c660cb5ae84 100644<br>
--- a/src/intel/vulkan/anv_sample_locations.c<br>
+++ b/src/intel/vulkan/anv_sample_locations.c<br>
@@ -21,7 +21,7 @@<br>
  * IN THE SOFTWARE.<br>
  */<br>
<br>
-#include "anv_private.h"<br>
+#include "anv_sample_locations.h"<br>
<br>
 void<br>
 anv_GetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice,<br>
@@ -58,3 +58,39 @@ anv_GetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice,<br>
       .maxSampleLocationGridSize = grid_size<br>
    };<br>
 }<br>
+<br>
+static int<br>
+compare_samples(const void *a, const void *b)<br>
+{<br>
+   struct anv_sample *s1 = (struct anv_sample *)a;<br>
+   struct anv_sample *s2 = (struct anv_sample *)b;<br>
+<br>
+   return s1->radius - s2->radius;<br>
+}<br>
+<br>
+void<br>
+anv_calc_sample_locations(struct anv_sample *samples,<br>
+                          uint32_t num_samples,<br>
+                          const VkSampleLocationsInfoEXT *info)<br>
+{<br>
+   int i;<br>
+<br>
+   for(i = 0; i < num_samples; i++) {<br>
+      float dx, dy;<br>
+<br>
+      /* this is because the grid is 1x1, in case that<br>
+       * we support different grid sizes in the future<br>
+       * this must be changed.<br>
+       */<br>
+      samples[i].offs_x = info->pSampleLocations[i].x;<br>
+      samples[i].offs_y = info->pSampleLocations[i].y;<br>
+<br>
+      /* distance from the center */<br>
+      dx = samples[i].offs_x - 0.5;<br>
+      dy = samples[i].offs_y - 0.5;<br>
+<br>
+      samples[i].radius = dx * dx + dy * dy;<br>
+   }<br>
+<br>
+   qsort(samples, num_samples, sizeof *samples, compare_samples);<br>
+}<br>
diff --git a/src/intel/vulkan/anv_sample_locations.h b/src/intel/vulkan/anv_sample_locations.h<br>
new file mode 100644<br>
index 00000000000..000d04aca08<br>
--- /dev/null<br>
+++ b/src/intel/vulkan/anv_sample_locations.h<br>
@@ -0,0 +1,29 @@<br>
+/*<br>
+ * Copyright © 2019 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include "anv_private.h"<br>
+<br>
+void<br>
+anv_calc_sample_locations(struct anv_sample *samples,<br>
+                          uint32_t num_samples,<br>
+                          const VkSampleLocationsInfoEXT *info);<br>
diff --git a/src/intel/vulkan/genX_pipeline.c b/src/intel/vulkan/genX_pipeline.c<br>
index 975052deb79..feb431e10cd 100644<br>
--- a/src/intel/vulkan/genX_pipeline.c<br>
+++ b/src/intel/vulkan/genX_pipeline.c<br>
@@ -22,6 +22,7 @@<br>
  */<br>
<br>
 #include "anv_private.h"<br>
+#include "anv_sample_locations.h"<br>
<br>
 #include "genxml/gen_macros.h"<br>
 #include "genxml/genX_pack.h"<br>
@@ -548,12 +549,9 @@ emit_rs_state(struct anv_pipeline *pipeline,<br>
 }<br>
<br>
 static void<br>
-emit_ms_state(struct anv_pipeline *pipeline,<br>
-              const VkPipelineMultisampleStateCreateInfo *info)<br>
+emit_sample_mask(struct anv_pipeline *pipeline,<br>
+                 const VkPipelineMultisampleStateCreateInfo *info)<br>
 {<br>
-   uint32_t samples = 1;<br>
-   uint32_t log2_samples = 0;<br>
-<br>
    /* From the Vulkan 1.0 spec:<br>
     *    If pSampleMask is NULL, it is treated as if the mask has all bits<br>
     *    enabled, i.e. no coverage is removed from fragments.<br>
@@ -566,14 +564,19 @@ emit_ms_state(struct anv_pipeline *pipeline,<br>
    uint32_t sample_mask = 0xff;<br>
 #endif<br>
<br>
-   if (info) {<br>
-      samples = info->rasterizationSamples;<br>
-      log2_samples = __builtin_ffs(samples) - 1;<br>
-   }<br>
-<br>
    if (info && info->pSampleMask)<br>
       sample_mask &= info->pSampleMask[0];<br>
<br>
+   anv_batch_emit(&pipeline->batch, GENX(3DSTATE_SAMPLE_MASK), sm) {<br>
+      sm.SampleMask = sample_mask;<br>
+   }<br>
+}<br>
+<br>
+static void<br>
+emit_multisample(struct anv_pipeline *pipeline,<br>
+                 uint32_t samples,<br>
+                 uint32_t log2_samples)<br>
+{<br>
    anv_batch_emit(&pipeline->batch, GENX(3DSTATE_MULTISAMPLE), ms) {<br>
       ms.NumberofMultisamples       = log2_samples;<br>
<br>
@@ -605,10 +608,61 @@ emit_ms_state(struct anv_pipeline *pipeline,<br>
       }<br>
 #endif<br>
    }<br>
+}<br>
<br>
-   anv_batch_emit(&pipeline->batch, GENX(3DSTATE_SAMPLE_MASK), sm) {<br>
-      sm.SampleMask = sample_mask;<br>
+static void<br>
+emit_ms_state(struct anv_pipeline *pipeline,<br>
+              const VkPipelineMultisampleStateCreateInfo *info,<br>
+              const VkPipelineDynamicStateCreateInfo *dinfo)<br>
+{<br>
+#if GEN_GEN >= 8<br>
+   bool custom_locations = false;<br>
+   VkSampleLocationsInfoEXT *sl;<br>
+#endif<br>
+<br>
+   uint32_t samples = 1;<br>
+   uint32_t log2_samples = 0;<br>
+<br>
+   emit_sample_mask(pipeline, info);<br>
+<br>
+   if (info) {<br>
+      samples = info->rasterizationSamples;<br>
+<br>
+#if GEN_GEN >= 8<br>
+      if (info->pNext) {<br>
+         VkPipelineSampleLocationsStateCreateInfoEXT *slinfo =<br>
+            (VkPipelineSampleLocationsStateCreateInfoEXT *)info->pNext;<br>
+<br>
+         if (slinfo &&<br>
+               (slinfo->sType ==<br>
+                VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT)) {<br>
+            if (slinfo->sampleLocationsEnable == VK_TRUE) {<br>
+               uint32_t i;<br>
+<br>
+               for (i = 0; i < dinfo->dynamicStateCount; i++) {<br>
+                  if (dinfo->pDynamicStates[i] ==<br>
+                      VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT)<br>
+                     return;<br>
+               }<br>
+<br>
+               if ((sl = &slinfo->sampleLocationsInfo))<br>
+                  samples = sl->sampleLocationsPerPixel;<br>
+<br>
+               custom_locations = true;<br>
+            }<br>
+         }<br>
+      }<br>
+#endif<br>
+<br>
+      log2_samples = __builtin_ffs(samples) - 1;<br>
    }<br>
+<br>
+   emit_multisample(pipeline, samples, log2_samples);<br>
+<br>
+#if GEN_GEN >= 8<br>
+   genX(emit_sample_locations)(&pipeline->batch, samples, sl,<br>
+                               custom_locations);<br>
+#endif<br>
 }<br>
<br>
 static const uint32_t vk_to_gen_logic_op[] = {<br>
@@ -1938,7 +1992,7 @@ genX(graphics_pipeline_create)(<br>
    assert(pCreateInfo->pRasterizationState);<br>
    emit_rs_state(pipeline, pCreateInfo->pRasterizationState,<br>
                  pCreateInfo->pMultisampleState, pass, subpass);<br>
-   emit_ms_state(pipeline, pCreateInfo->pMultisampleState);<br>
+   emit_ms_state(pipeline, pCreateInfo->pMultisampleState, pCreateInfo->pDynamicState);<br>
    emit_ds_state(pipeline, pCreateInfo->pDepthStencilState, pass, subpass);<br>
    emit_cb_state(pipeline, pCreateInfo->pColorBlendState,<br>
                            pCreateInfo->pMultisampleState);<br>
diff --git a/src/intel/vulkan/genX_state.c b/src/intel/vulkan/genX_state.c<br>
index cffd1e47247..c14e502a68d 100644<br>
--- a/src/intel/vulkan/genX_state.c<br>
+++ b/src/intel/vulkan/genX_state.c<br>
@@ -28,6 +28,7 @@<br>
 #include <fcntl.h><br>
<br>
 #include "anv_private.h"<br>
+#include "anv_sample_locations.h"<br>
<br>
 #include "common/gen_sample_positions.h"<br>
 #include "genxml/gen_macros.h"<br>
@@ -435,3 +436,61 @@ VkResult genX(CreateSampler)(<br>
<br>
    return VK_SUCCESS;<br>
 }<br>
+<br>
+void<br>
+genX(emit_sample_locations)(struct anv_batch *batch,<br>
+                            uint32_t num_samples,<br>
+                            const VkSampleLocationsInfoEXT *sl,<br>
+                            bool custom_locations)<br>
+{<br>
+#if GEN_GEN >= 8<br>
+   struct anv_sample anv_samples[MAX_SAMPLE_LOCATIONS];<br>
+<br>
+#if GEN_GEN == 10<br>
+   gen10_emit_wa_cs_stall_flush(batch);<br>
+#endif<br>
+<br>
+   if (custom_locations) {<br>
+      anv_calc_sample_locations(anv_samples, num_samples, sl);<br></blockquote><div><br></div><div>Except your doing it in an emit function... Is this ever going to be in the hot path?  If so, maybe the thing we should cache should be the sorted thing?  I'm also a bit unsure about the sorting.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+      anv_batch_emit(batch,  GENX(3DSTATE_SAMPLE_PATTERN), sp) {<br>
+         switch (num_samples) {<br>
+         case 1:<br>
+            SET_SAMPLE_POS(sp._1xSample, 0);<br>
+            break;<br>
+         case 2:<br>
+            SET_SAMPLE_POS_2X(sp._2xSample);<br>
+            break;<br>
+         case 4:<br>
+            SET_SAMPLE_POS_4X(sp._4xSample);<br>
+            break;<br>
+         case 8:<br>
+            SET_SAMPLE_POS_8X(sp._8xSample);<br>
+            break;<br>
+#if GEN_GEN >= 9<br>
+         case 16:<br>
+            SET_SAMPLE_POS_16X(sp._16xSample);<br>
+            break;<br>
+#endif<br>
+         default:<br>
+            break;<br>
+         }<br>
+      }<br>
+   } else {<br>
+      anv_batch_emit(batch, GENX(3DSTATE_SAMPLE_PATTERN), sp) {<br>
+         GEN_SAMPLE_POS_1X(sp._1xSample);<br>
+         GEN_SAMPLE_POS_2X(sp._2xSample);<br>
+         GEN_SAMPLE_POS_4X(sp._4xSample);<br>
+         GEN_SAMPLE_POS_8X(sp._8xSample);<br>
+#if GEN_GEN >= 9<br>
+         GEN_SAMPLE_POS_16X(sp._16xSample);<br>
+#endif<br>
+      }<br>
+   }<br>
+<br>
+#if GEN_GEN == 10<br>
+   gen10_emit_wa_lri_to_cache_mode_zero(batch);<br>
+#endif<br>
+<br>
+#endif<br>
+}<br>
-- <br>
2.20.1<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">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/mailman/listinfo/mesa-dev</a></blockquote></div></div></div>