<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Mar 14, 2019 at 2:52 PM 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<br>
Locations] 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<br>
to be re-emitted again in the next pipeline creation. For that, we emit<br>
the 3DSTATE_SAMPLE_PATTERN at every pipeline creation.<br>
<br>
v2: In v1, we used the custom anv_sample struct to store the location<br>
    and the distance from the pixel center because we would then use<br>
    this distance to sort the locations and send them in increasing<br>
    monotonical order to the GPU. That was because the Skylake PRM Vol.<br>
    2a "3DSTATE_SAMPLE_PATTERN" says that the samples must have<br>
    monotonically increasing distance from the pixel center to get the<br>
    correct centroid computation in the device. However, the Vulkan<br>
    spec seems to require that the samples occur in the order provided<br>
    through the API and this requirement is only for the standard<br>
    locations. As long as this only affects centroid calculations as<br>
    the docs say, we should be ok because OpenGL and Vulkan only<br>
    require that the centroid be some lit sample and that it's the same<br>
    for all samples in a pixel; they have no requirement that it be the<br>
    one closest to center. (Jason Ekstrand)<br>
    For that we made the following changes:<br>
    1- We removed the custom structs and functions from anv_private.h<br>
       and anv_sample_locations.h and anv_sample_locations.c (the last<br>
       two files were removed). (Jason Ekstrand)<br>
    2- We modified the macros used to take also the array as parameter<br>
       and we renamed them to start by GEN_. (Jason Ekstrand)<br>
    3- We don't sort the samples anymore. (Jason Ekstrand)<br>
---<br>
 src/intel/common/gen_sample_positions.h | 57 ++++++++++++++++++<br>
 src/intel/vulkan/anv_genX.h             |  5 ++<br>
 src/intel/vulkan/anv_private.h          |  1 +<br>
 src/intel/vulkan/genX_pipeline.c        | 79 +++++++++++++++++++++----<br>
 src/intel/vulkan/genX_state.c           | 72 ++++++++++++++++++++++<br>
 5 files changed, 201 insertions(+), 13 deletions(-)<br>
<br>
diff --git a/src/intel/common/gen_sample_positions.h b/src/intel/common/gen_sample_positions.h<br>
index da48dcb5ed0..850661931cf 100644<br>
--- a/src/intel/common/gen_sample_positions.h<br>
+++ b/src/intel/common/gen_sample_positions.h<br>
@@ -160,4 +160,61 @@ 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>
+ * GEN_SAMPLE_POS_ELEM(ms.Sample, info->pSampleLocations, 0); expands to:<br>
+ *    ms.Sample0XOffset = info->pSampleLocations[0].pos.x;<br>
+ *    ms.Sample0YOffset = info->pSampleLocations[0].y;<br>
+ *<br>
+ * in case of GEN_GEN >= 8:<br>
+ * GEN_SAMPLE_POS_ELEM(sp._16xSample, info->pSampleLocations, 0); expands to:<br>
+ *    sp._16xSample0XOffset = info->pSampleLocations[0].x;<br>
+ *    sp._16xSample0YOffset = info->pSampleLocations[0].y;<br>
+ */<br>
+<br>
+#define GEN_SAMPLE_POS_ELEM(prefix, arr, sample_idx) \<br>
+prefix##sample_idx##XOffset = arr[sample_idx].x; \<br>
+prefix##sample_idx##YOffset = arr[sample_idx].y;<br>
+<br>
+#define GEN_SAMPLE_POS_1X_ARRAY(prefix, arr)\<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 0);<br>
+<br>
+#define GEN_SAMPLE_POS_2X_ARRAY(prefix, arr) \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 0); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 1);<br>
+<br>
+#define GEN_SAMPLE_POS_4X_ARRAY(prefix, arr) \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 0); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 1); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 2); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 3);<br>
+<br>
+#define GEN_SAMPLE_POS_8X_ARRAY(prefix, arr) \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 0); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 1); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 2); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 3); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 4); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 5); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 6); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 7);<br>
+<br>
+#define GEN_SAMPLE_POS_16X_ARRAY(prefix, arr) \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 0); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 1); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 2); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 3); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 4); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 5); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 6); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 7); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 8); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 9); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 10); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 11); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 12); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 13); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 14); \<br>
+GEN_SAMPLE_POS_ELEM(prefix, arr, 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..fb7419b6347 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>
+                                 const VkSampleLocationEXT *sl,<br>
+                                 uint32_t num_samples,<br>
+                                 bool custom_locations);<br></blockquote><div><br></div><div>You probably don't need the "custom_locations bool.  You could just use sl == NULL or num_samples == 0 for that.<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">
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h<br>
index eed282ff985..a39195733cd 100644<br>
--- a/src/intel/vulkan/anv_private.h<br>
+++ b/src/intel/vulkan/anv_private.h<br>
@@ -165,6 +165,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>
diff --git a/src/intel/vulkan/genX_pipeline.c b/src/intel/vulkan/genX_pipeline.c<br>
index 975052deb79..07b45db1988 100644<br>
--- a/src/intel/vulkan/genX_pipeline.c<br>
+++ b/src/intel/vulkan/genX_pipeline.c<br>
@@ -548,12 +548,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 +563,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></blockquote><div><br></div><div>Is there some particular reason why you're breaking emit_ms_state up into multiple functions?  It seems unrelated to enabling this feature and it makes this patch very hard to read.<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">
    anv_batch_emit(&pipeline->batch, GENX(3DSTATE_MULTISAMPLE), ms) {<br>
       ms.NumberofMultisamples       = log2_samples;<br>
<br>
@@ -605,10 +607,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>
+   VkSampleLocationsInfoEXT *sl;<br>
+   bool custom_locations = false;<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></blockquote><div><br></div><div>You should be able to assert that these are equal</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>
+               custom_locations = true;<br>
+            }<br>
+         }<br>
+      }<br></blockquote><div><br></div><div>There are two ways to do this both of which are easier and less complicated than what you have here:</div><div><br></div><div> 1. vk_foreach_struct() and a switch statement like we do for the Properties2 queries</div><div> 2. vk_find_struct_const() to just look for the one struct.<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">
+#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, sl->pSampleLocations,<br>
+                               samples, custom_locations);<br>
+#endif<br>
 }<br>
<br>
 static const uint32_t vk_to_gen_logic_op[] = {<br>
@@ -1938,7 +1991,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..3f628710b31 100644<br>
--- a/src/intel/vulkan/genX_state.c<br>
+++ b/src/intel/vulkan/genX_state.c<br>
@@ -435,3 +435,75 @@ VkResult genX(CreateSampler)(<br>
<br>
    return VK_SUCCESS;<br>
 }<br>
+<br>
+void<br>
+genX(emit_sample_locations)(struct anv_batch *batch,<br>
+                            const VkSampleLocationEXT *sl,<br>
+                            uint32_t num_samples,<br>
+                            bool custom_locations)<br>
+{<br>
+   /* The Skylake PRM Vol. 2a "3DSTATE_SAMPLE_PATTERN" says:<br>
+    * "When programming the sample offsets (for NUMSAMPLES_4 or _8 and<br>
+    * MSRASTMODE_xxx_PATTERN), the order of the samples 0 to 3 (or 7 for 8X,<br>
+    * or 15 for 16X) must have monotonically increasing distance from the<br>
+    * pixel center. This is required to get the correct centroid computation<br>
+    * in the device."<br>
+    *<br>
+    * However, the Vulkan spec seems to require that the the samples occur in<br>
+    * the order provided through the API. The standard sample patterns have<br>
+    * the above property that they have monotonically increasing distances<br>
+    * from the center but client-provided ones do not. As long as this only<br>
+    * affects centroid calculations as the docs say, we should be ok because<br>
+    * OpenGL and Vulkan only require that the centroid be some lit sample and<br>
+    * that it's the same for all samples in a pixel; they have no requirement<br>
+    * that it be the one closest to center.<br>
+    */<br>
+<br>
+#if GEN_GEN >= 8<br>
+<br>
+#if GEN_GEN == 10<br>
+   gen10_emit_wa_cs_stall_flush(batch);<br>
+#endif<br>
+<br>
+   if (custom_locations) {<br>
+      anv_batch_emit(batch,  GENX(3DSTATE_SAMPLE_PATTERN), sp) {<br>
+         switch (num_samples) {<br>
+         case 1:<br>
+            GEN_SAMPLE_POS_1X_ARRAY(sp._1xSample, sl);<br>
+            break;<br>
+         case 2:<br>
+            GEN_SAMPLE_POS_2X_ARRAY(sp._2xSample, sl);<br>
+            break;<br>
+         case 4:<br>
+            GEN_SAMPLE_POS_4X_ARRAY(sp._4xSample, sl);<br>
+            break;<br>
+         case 8:<br>
+            GEN_SAMPLE_POS_8X_ARRAY(sp._8xSample, sl);<br>
+            break;<br>
+#if GEN_GEN >= 9<br>
+         case 16:<br>
+            GEN_SAMPLE_POS_16X_ARRAY(sp._16xSample, sl);<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>
</blockquote></div></div>