Mesa (main): anv: Update VK_KHR_fragment_shading_rate for newer HW

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Feb 2 17:39:54 UTC 2022


Module: Mesa
Branch: main
Commit: 665ffd4bf9c681f8fc37dc07b3c2445e1ed5bf25
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=665ffd4bf9c681f8fc37dc07b3c2445e1ed5bf25

Author: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
Date:   Fri Feb  5 21:16:38 2021 +0200

anv: Update VK_KHR_fragment_shading_rate for newer HW

Per primitive & attachment shading rate support added.

v2: Rebase on KHR_dynamic_rendering

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
Reviewed-by: Ivan Briano <ivan.briano at intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13739>

---

 src/intel/genxml/meson.build       |   1 +
 src/intel/vulkan/anv_cmd_buffer.c  |  55 +++++++++++++-
 src/intel/vulkan/anv_device.c      | 122 +++++++++++++++++++++++++------
 src/intel/vulkan/anv_formats.c     |   5 ++
 src/intel/vulkan/anv_genX.h        |   3 +-
 src/intel/vulkan/anv_image.c       |   3 +
 src/intel/vulkan/anv_pass.c        |  56 ++++++++++++--
 src/intel/vulkan/anv_pipeline.c    |   9 ++-
 src/intel/vulkan/anv_private.h     |  29 +++++++-
 src/intel/vulkan/genX_cmd_buffer.c |  92 ++++++++++++++++++++++-
 src/intel/vulkan/genX_pipeline.c   |  22 +++---
 src/intel/vulkan/genX_state.c      | 146 ++++++++++++++++++++++++++++++++-----
 src/intel/vulkan/gfx8_cmd_buffer.c |  24 ++----
 13 files changed, 480 insertions(+), 87 deletions(-)

diff --git a/src/intel/genxml/meson.build b/src/intel/genxml/meson.build
index 0932e2c0179..7e131c319a7 100644
--- a/src/intel/genxml/meson.build
+++ b/src/intel/genxml/meson.build
@@ -70,6 +70,7 @@ genX_bits_included_symbols = [
   'RENDER_SURFACE_STATE::Alpha Clear Color',
   'CLEAR_COLOR',
   'VERTEX_BUFFER_STATE::Buffer Starting Address',
+  'CPS_STATE',
 ]
 
 genX_bits_h = custom_target(
diff --git a/src/intel/vulkan/anv_cmd_buffer.c b/src/intel/vulkan/anv_cmd_buffer.c
index d197f3e9dd0..9b548a5c487 100644
--- a/src/intel/vulkan/anv_cmd_buffer.c
+++ b/src/intel/vulkan/anv_cmd_buffer.c
@@ -208,8 +208,10 @@ anv_dynamic_state_copy(struct anv_dynamic_state *dest,
 
    ANV_CMP_COPY(color_writes, ANV_CMD_DIRTY_DYNAMIC_COLOR_BLEND_STATE);
 
-   ANV_CMP_COPY(fragment_shading_rate.width, ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
-   ANV_CMP_COPY(fragment_shading_rate.height, ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
+   ANV_CMP_COPY(fragment_shading_rate.rate.width, ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
+   ANV_CMP_COPY(fragment_shading_rate.rate.height, ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
+   ANV_CMP_COPY(fragment_shading_rate.ops[0], ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
+   ANV_CMP_COPY(fragment_shading_rate.ops[1], ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE);
 
 #undef ANV_CMP_COPY
 
@@ -1338,6 +1340,25 @@ void anv_TrimCommandPool(
    /* Nothing for us to do here.  Our pools stay pretty tidy. */
 }
 
+/**
+ * Return NULL if the current subpass has no color attachment.
+ */
+const struct anv_image_view *
+anv_cmd_buffer_get_first_color_view(const struct anv_cmd_buffer *cmd_buffer)
+{
+   const struct anv_subpass *subpass = cmd_buffer->state.subpass;
+
+   if (subpass->color_count == 0)
+      return NULL;
+
+   const struct anv_image_view *iview =
+      cmd_buffer->state.attachments[subpass->color_attachments[0].attachment].image_view;
+
+   assert(iview->vk.aspects & VK_IMAGE_ASPECT_COLOR_BIT);
+
+   return iview;
+}
+
 /**
  * Return NULL if the current subpass has no depthstencil attachment.
  */
@@ -1358,6 +1379,25 @@ anv_cmd_buffer_get_depth_stencil_view(const struct anv_cmd_buffer *cmd_buffer)
    return iview;
 }
 
+/**
+ * Return NULL if the current subpass has no fragment shading rate attachment.
+ */
+const struct anv_image_view *
+anv_cmd_buffer_get_fsr_view(const struct anv_cmd_buffer *cmd_buffer)
+{
+   const struct anv_subpass *subpass = cmd_buffer->state.subpass;
+
+   if (subpass->fsr_attachment == NULL)
+      return NULL;
+
+   const struct anv_image_view *iview =
+      cmd_buffer->state.attachments[subpass->fsr_attachment->attachment].image_view;
+
+   assert(iview->image->vk.usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR);
+
+   return iview;
+}
+
 static struct anv_descriptor_set *
 anv_cmd_buffer_push_descriptor_set(struct anv_cmd_buffer *cmd_buffer,
                                    VkPipelineBindPoint bind_point,
@@ -1610,8 +1650,15 @@ void anv_CmdSetFragmentShadingRateKHR(
 {
    ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
 
-   cmd_buffer->state.gfx.dynamic.fragment_shading_rate = *pFragmentSize;
-   cmd_buffer->state.gfx.dirty |= ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE;
+   if (cmd_buffer->state.gfx.dynamic.fragment_shading_rate.rate.width != pFragmentSize->width ||
+       cmd_buffer->state.gfx.dynamic.fragment_shading_rate.rate.height != pFragmentSize->height ||
+       cmd_buffer->state.gfx.dynamic.fragment_shading_rate.ops[0] != combinerOps[0] ||
+       cmd_buffer->state.gfx.dynamic.fragment_shading_rate.ops[1] != combinerOps[1]) {
+      cmd_buffer->state.gfx.dynamic.fragment_shading_rate.rate = *pFragmentSize;
+      memcpy(cmd_buffer->state.gfx.dynamic.fragment_shading_rate.ops, combinerOps,
+             sizeof(cmd_buffer->state.gfx.dynamic.fragment_shading_rate.ops));
+      cmd_buffer->state.gfx.dirty |= ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE;
+   }
 }
 
 static inline uint32_t
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 1a325ea63c2..cfe1d21ed97 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -60,6 +60,7 @@
 #include "perf/intel_perf.h"
 
 #include "genxml/gen7_pack.h"
+#include "genxml/genX_bits.h"
 
 static const driOptionDescription anv_dri_options[] = {
    DRI_CONF_SECTION_PERFORMANCE
@@ -1554,7 +1555,10 @@ void anv_GetPhysicalDeviceFeatures2(
             (VkPhysicalDeviceFragmentShadingRateFeaturesKHR *)ext;
          features->attachmentFragmentShadingRate = false;
          features->pipelineFragmentShadingRate = true;
-         features->primitiveFragmentShadingRate = false;
+         features->primitiveFragmentShadingRate =
+            pdevice->info.has_coarse_pixel_primitive_and_cb;
+         features->attachmentFragmentShadingRate =
+            pdevice->info.has_coarse_pixel_primitive_and_cb;
          break;
       }
 
@@ -2288,27 +2292,48 @@ void anv_GetPhysicalDeviceProperties2(
       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR: {
          VkPhysicalDeviceFragmentShadingRatePropertiesKHR *props =
             (VkPhysicalDeviceFragmentShadingRatePropertiesKHR *)ext;
-         /* Those must be 0 if attachmentFragmentShadingRate is not
-          * supported.
-          */
-         props->minFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 0, 0 };
-         props->maxFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 0, 0 };
-         props->maxFragmentShadingRateAttachmentTexelSizeAspectRatio = 0;
-
-         props->primitiveFragmentShadingRateWithMultipleViewports = false;
-         props->layeredShadingRateAttachments = false;
-         props->fragmentShadingRateNonTrivialCombinerOps = false;
+         props->primitiveFragmentShadingRateWithMultipleViewports =
+            pdevice->info.has_coarse_pixel_primitive_and_cb;
+         props->layeredShadingRateAttachments = pdevice->info.has_coarse_pixel_primitive_and_cb;
+         props->fragmentShadingRateNonTrivialCombinerOps =
+            pdevice->info.has_coarse_pixel_primitive_and_cb;
          props->maxFragmentSize = (VkExtent2D) { 4, 4 };
-         props->maxFragmentSizeAspectRatio = 4;
-         props->maxFragmentShadingRateCoverageSamples = 4 * 4 * 16;
-         props->maxFragmentShadingRateRasterizationSamples = VK_SAMPLE_COUNT_16_BIT;
+         props->maxFragmentSizeAspectRatio =
+            pdevice->info.has_coarse_pixel_primitive_and_cb ?
+            2 : 4;
+         props->maxFragmentShadingRateCoverageSamples = 4 * 4 *
+            (pdevice->info.has_coarse_pixel_primitive_and_cb ? 4 : 16);
+         props->maxFragmentShadingRateRasterizationSamples =
+            pdevice->info.has_coarse_pixel_primitive_and_cb ?
+            VK_SAMPLE_COUNT_4_BIT :  VK_SAMPLE_COUNT_16_BIT;
          props->fragmentShadingRateWithShaderDepthStencilWrites = false;
          props->fragmentShadingRateWithSampleMask = true;
          props->fragmentShadingRateWithShaderSampleMask = false;
          props->fragmentShadingRateWithConservativeRasterization = true;
          props->fragmentShadingRateWithFragmentShaderInterlock = true;
          props->fragmentShadingRateWithCustomSampleLocations = true;
-         props->fragmentShadingRateStrictMultiplyCombiner = false;
+
+         /* Fix in DG2_G10_C0 and DG2_G11_B0. Consider any other Sku as having
+          * the fix.
+          */
+         props->fragmentShadingRateStrictMultiplyCombiner =
+            pdevice->info.platform == INTEL_PLATFORM_DG2_G10 ?
+            pdevice->info.revision >= 8 :
+            pdevice->info.platform == INTEL_PLATFORM_DG2_G11 ?
+            pdevice->info.revision >= 4 : true;
+
+         if (pdevice->info.has_coarse_pixel_primitive_and_cb) {
+            props->minFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 8, 8 };
+            props->maxFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 8, 8 };
+            props->maxFragmentShadingRateAttachmentTexelSizeAspectRatio = 1;
+         } else {
+            /* Those must be 0 if attachmentFragmentShadingRate is not
+             * supported.
+             */
+            props->minFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 0, 0 };
+            props->maxFragmentShadingRateAttachmentTexelSize = (VkExtent2D) { 0, 0 };
+            props->maxFragmentShadingRateAttachmentTexelSizeAspectRatio = 0;
+         }
          break;
       }
 
@@ -3233,6 +3258,28 @@ VkResult anv_CreateDevice(
    if (result != VK_SUCCESS)
       goto fail_workaround_bo;
 
+   if (device->info.ver >= 12 &&
+       device->vk.enabled_extensions.KHR_fragment_shading_rate) {
+      uint32_t n_cps_states = 3 * 3; /* All combinaisons of X by Y CP sizes (1, 2, 4) */
+
+      if (device->info.has_coarse_pixel_primitive_and_cb)
+         n_cps_states *= 5 * 5; /* 5 combiners by 2 operators */
+
+      n_cps_states += 1; /* Disable CPS */
+
+       /* Each of the combinaison must be replicated on all viewports */
+      n_cps_states *= MAX_VIEWPORTS;
+
+      device->cps_states =
+         anv_state_pool_alloc(&device->dynamic_state_pool,
+                              n_cps_states * CPS_STATE_length(&device->info) * 4,
+                              32);
+      if (device->cps_states.map == NULL)
+         goto fail_trivial_batch;
+
+      anv_genX(&device->info, init_cps_device_state)(device);
+   }
+
    /* Allocate a null surface state at surface state offset 0.  This makes
     * NULL descriptor handling trivial because we can just memset structures
     * to zero and they have a valid descriptor.
@@ -3277,6 +3324,7 @@ VkResult anv_CreateDevice(
    anv_pipeline_cache_finish(&device->default_pipeline_cache);
  fail_trivial_batch_bo_and_scratch_pool:
    anv_scratch_pool_finish(device, &device->scratch_pool);
+ fail_trivial_batch:
    anv_device_release_bo(device, device->trivial_batch_bo);
  fail_workaround_bo:
    anv_device_release_bo(device, device->workaround_bo);
@@ -3352,6 +3400,7 @@ void anv_DestroyDevice(
       anv_state_reserved_pool_finish(&device->custom_border_colors);
    anv_state_pool_free(&device->dynamic_state_pool, device->border_colors);
    anv_state_pool_free(&device->dynamic_state_pool, device->slice_hash);
+   anv_state_pool_free(&device->dynamic_state_pool, device->cps_states);
 #endif
 
    for (unsigned i = 0; i < ARRAY_SIZE(device->rt_scratch_bos); i++) {
@@ -4651,14 +4700,45 @@ VkResult anv_GetPhysicalDeviceFragmentShadingRatesKHR(
    VkSampleCountFlags sample_counts =
       isl_device_get_sample_counts(&physical_device->isl_dev);
 
+   /* BSpec 47003: There are a number of restrictions on the sample count
+    * based off the coarse pixel size.
+    */
+   static const VkSampleCountFlags cp_size_sample_limits[] = {
+      [1]  = ISL_SAMPLE_COUNT_16_BIT | ISL_SAMPLE_COUNT_8_BIT |
+             ISL_SAMPLE_COUNT_4_BIT | ISL_SAMPLE_COUNT_2_BIT | ISL_SAMPLE_COUNT_1_BIT,
+      [2]  = ISL_SAMPLE_COUNT_4_BIT | ISL_SAMPLE_COUNT_2_BIT | ISL_SAMPLE_COUNT_1_BIT,
+      [4]  = ISL_SAMPLE_COUNT_4_BIT | ISL_SAMPLE_COUNT_2_BIT | ISL_SAMPLE_COUNT_1_BIT,
+      [8]  = ISL_SAMPLE_COUNT_2_BIT | ISL_SAMPLE_COUNT_1_BIT,
+      [16] = ISL_SAMPLE_COUNT_1_BIT,
+   };
+
    for (uint32_t x = 4; x >= 1; x /= 2) {
        for (uint32_t y = 4; y >= 1; y /= 2) {
-          /* For size {1, 1}, the sample count must be ~0 */
-          if (x == 1 && y == 1)
-             append_rate(~0, x, y);
-          else
-             append_rate(sample_counts, x, y);
-      }
+          if (physical_device->info.has_coarse_pixel_primitive_and_cb) {
+             /* BSpec 47003:
+              *   "CPsize 1x4 and 4x1 are not supported"
+              */
+             if ((x == 1 && y == 4) || (x == 4 && y == 1))
+                continue;
+
+             /* For size {1, 1}, the sample count must be ~0
+              *
+              * 4x2 is also a specially case.
+              */
+             if (x == 1 && y == 1)
+                append_rate(~0, x, y);
+             else if (x == 4 && y == 2)
+                append_rate(ISL_SAMPLE_COUNT_1_BIT, x, y);
+             else
+                append_rate(cp_size_sample_limits[x * y], x, y);
+          } else {
+             /* For size {1, 1}, the sample count must be ~0 */
+             if (x == 1 && y == 1)
+                append_rate(~0, x, y);
+             else
+                append_rate(sample_counts, x, y);
+          }
+       }
    }
 
 #undef append_rate
diff --git a/src/intel/vulkan/anv_formats.c b/src/intel/vulkan/anv_formats.c
index 8e264085b1c..5343433bd00 100644
--- a/src/intel/vulkan/anv_formats.c
+++ b/src/intel/vulkan/anv_formats.c
@@ -807,6 +807,11 @@ anv_get_image_format_features2(const struct intel_device_info *devinfo,
       }
    }
 
+   if (devinfo->has_coarse_pixel_primitive_and_cb &&
+       vk_format == VK_FORMAT_R8_UINT &&
+       vk_tiling == VK_IMAGE_TILING_OPTIMAL)
+      flags |= VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
+
    return flags;
 }
 
diff --git a/src/intel/vulkan/anv_genX.h b/src/intel/vulkan/anv_genX.h
index 88b45a889ee..3a7d87cae08 100644
--- a/src/intel/vulkan/anv_genX.h
+++ b/src/intel/vulkan/anv_genX.h
@@ -52,6 +52,8 @@ void genX(init_physical_device_state)(struct anv_physical_device *device);
 
 VkResult genX(init_device_state)(struct anv_device *device);
 
+void genX(init_cps_device_state)(struct anv_device *device);
+
 void genX(cmd_buffer_emit_state_base_address)(struct anv_cmd_buffer *cmd_buffer);
 
 void genX(cmd_buffer_apply_pipe_flushes)(struct anv_cmd_buffer *cmd_buffer);
@@ -132,7 +134,6 @@ void genX(emit_sample_pattern)(struct anv_batch *batch, uint32_t samples,
 
 void genX(emit_shading_rate)(struct anv_batch *batch,
                              const struct anv_graphics_pipeline *pipeline,
-                             struct anv_state cps_states,
                              struct anv_dynamic_state *dynamic_state);
 
 void genX(cmd_buffer_so_memcpy)(struct anv_cmd_buffer *cmd_buffer,
diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
index ef8a7171c34..755adf2f2dd 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -216,6 +216,9 @@ choose_isl_surf_usage(VkImageCreateFlags vk_create_flags,
    if (vk_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
       isl_usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT;
 
+   if (vk_usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR)
+      isl_usage |= ISL_SURF_USAGE_CPB_BIT;
+
    if (vk_create_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
       isl_usage |= ISL_SURF_USAGE_CUBE_BIT;
 
diff --git a/src/intel/vulkan/anv_pass.c b/src/intel/vulkan/anv_pass.c
index d823760f99a..a4765479c60 100644
--- a/src/intel/vulkan/anv_pass.c
+++ b/src/intel/vulkan/anv_pass.c
@@ -247,12 +247,16 @@ num_subpass_attachments2(const VkSubpassDescription2KHR *desc)
    const VkSubpassDescriptionDepthStencilResolveKHR *ds_resolve =
       vk_find_struct_const(desc->pNext,
                            SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR);
+   const VkFragmentShadingRateAttachmentInfoKHR *fsr_attachment =
+      vk_find_struct_const(desc->pNext,
+                           FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR);
 
    return desc->inputAttachmentCount +
           desc->colorAttachmentCount +
           (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) +
           (desc->pDepthStencilAttachment != NULL) +
-          (ds_resolve && ds_resolve->pDepthStencilResolveAttachment);
+          (ds_resolve && ds_resolve->pDepthStencilResolveAttachment) +
+          (fsr_attachment != NULL && fsr_attachment->pFragmentShadingRateAttachment);
 }
 
 VkResult anv_CreateRenderPass2(
@@ -391,6 +395,22 @@ VkResult anv_CreateRenderPass2(
          subpass->depth_resolve_mode = ds_resolve->depthResolveMode;
          subpass->stencil_resolve_mode = ds_resolve->stencilResolveMode;
       }
+
+      const VkFragmentShadingRateAttachmentInfoKHR *fsr_attachment =
+         vk_find_struct_const(desc->pNext,
+                              FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR);
+
+      if (fsr_attachment && fsr_attachment->pFragmentShadingRateAttachment) {
+         subpass->fsr_attachment = subpass_attachments++;
+
+         *subpass->fsr_attachment = (struct anv_subpass_attachment) {
+            .usage =          VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
+            .attachment =     fsr_attachment->pFragmentShadingRateAttachment->attachment,
+            .layout =         fsr_attachment->pFragmentShadingRateAttachment->layout,
+         };
+         subpass->fsr_extent = fsr_attachment->shadingRateAttachmentTexelSize;
+      }
+
    }
 
    for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) {
@@ -498,8 +518,8 @@ anv_dynamic_pass_init_full(struct anv_dynamic_render_pass *dyn_render_pass,
                            const VkRenderingInfoKHR *info)
 {
    uint32_t att_count;
-   uint32_t color_count = 0, ds_count = 0;
-   uint32_t ds_idx;
+   uint32_t color_count = 0, ds_count = 0, fsr_count = 0;
+   uint32_t ds_idx, fsr_idx;
    bool has_color_resolve, has_ds_resolve;
 
    struct anv_render_pass *pass = &dyn_render_pass->pass;
@@ -514,6 +534,9 @@ anv_dynamic_pass_init_full(struct anv_dynamic_render_pass *dyn_render_pass,
    dyn_render_pass->suspending = info->flags & VK_RENDERING_SUSPENDING_BIT_KHR;
    dyn_render_pass->resuming = info->flags & VK_RENDERING_RESUMING_BIT_KHR;
 
+   /* Get the total attachment count by counting color, depth & fragment
+    * shading rate views.
+    */
    color_count = info->colorAttachmentCount;
    if ((info->pDepthAttachment && info->pDepthAttachment->imageView) ||
        (info->pStencilAttachment && info->pStencilAttachment->imageView))
@@ -538,8 +561,15 @@ anv_dynamic_pass_init_full(struct anv_dynamic_render_pass *dyn_render_pass,
    if (has_ds_resolve)
       ds_count *= 2;
 
-   att_count = color_count + ds_count;
+   const VkRenderingFragmentShadingRateAttachmentInfoKHR *fsr_attachment =
+      vk_find_struct_const(info->pNext,
+                           RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR);
+   if (fsr_attachment && fsr_attachment->imageView != VK_NULL_HANDLE)
+      fsr_count = 1;
+
+   att_count = color_count + ds_count + fsr_count;
    ds_idx = color_count;
+   fsr_idx = color_count + ds_count;
 
    /* Setup pass & subpass */
    *pass = (struct anv_render_pass) {
@@ -605,7 +635,7 @@ anv_dynamic_pass_init_full(struct anv_dynamic_render_pass *dyn_render_pass,
 
       ANV_FROM_HANDLE(anv_image_view, iview, d_or_s_att->imageView);
 
-      pass->attachments[ds_idx]  = (struct anv_render_pass_attachment) {
+      pass->attachments[ds_idx] = (struct anv_render_pass_attachment) {
          .format                 = iview->vk.format,
          .samples                = iview->vk.image->samples,
          .usage                  = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
@@ -635,4 +665,20 @@ anv_dynamic_pass_init_full(struct anv_dynamic_render_pass *dyn_render_pass,
          subpass->stencil_resolve_mode = stencil_resolve_mode;
       }
    }
+
+   if (fsr_count) {
+      ANV_FROM_HANDLE(anv_image_view, iview, fsr_attachment->imageView);
+
+      pass->attachments[fsr_idx] = (struct anv_render_pass_attachment) {
+         .format  = iview->vk.format,
+         .samples = iview->vk.image->samples,
+         .usage   = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
+      };
+
+      *subpass->fsr_attachment = (struct anv_subpass_attachment) {
+         .usage      = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
+         .attachment = fsr_idx,
+      };
+      subpass->fsr_extent = fsr_attachment->shadingRateAttachmentTexelSize;
+   }
 }
diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c
index 218981df818..cf6b06c6f5c 100644
--- a/src/intel/vulkan/anv_pipeline.c
+++ b/src/intel/vulkan/anv_pipeline.c
@@ -324,8 +324,6 @@ void anv_DestroyPipeline(
 
       if (gfx_pipeline->blend_state.map)
          anv_state_pool_free(&device->dynamic_state_pool, gfx_pipeline->blend_state);
-      if (gfx_pipeline->cps_state.map)
-         anv_state_pool_free(&device->dynamic_state_pool, gfx_pipeline->cps_state);
 
       for (unsigned s = 0; s < ARRAY_SIZE(gfx_pipeline->shaders); s++) {
          if (gfx_pipeline->shaders[s])
@@ -2345,8 +2343,11 @@ copy_non_dynamic_state(struct anv_graphics_pipeline *pipeline,
       vk_find_struct_const(pCreateInfo->pNext,
                            PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR);
    if (fsr_state) {
-      if (states & ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE)
-         dynamic->fragment_shading_rate = fsr_state->fragmentSize;
+      if (states & ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE) {
+         dynamic->fragment_shading_rate.rate = fsr_state->fragmentSize;
+         memcpy(dynamic->fragment_shading_rate.ops, fsr_state->combinerOps,
+                sizeof(dynamic->fragment_shading_rate.ops));
+      }
    }
 
    pipeline->dynamic_state_mask = states;
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 82e814fd3b4..e5247634d1d 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1194,6 +1194,16 @@ struct anv_device {
 
     struct anv_state                            slice_hash;
 
+    /** An array of CPS_STATE structures grouped by MAX_VIEWPORTS elements
+     *
+     * We need to emit CPS_STATE structures for each viewport accessible by a
+     * pipeline. So rather than write many identical CPS_STATE structures
+     * dynamically, we can enumerate all possible combinaisons and then just
+     * emit a 3DSTATE_CPS_POINTERS instruction with the right offset into this
+     * array.
+     */
+    struct anv_state                            cps_states;
+
     uint32_t                                    queue_count;
     struct anv_queue  *                         queues;
 
@@ -2696,7 +2706,10 @@ struct anv_dynamic_state {
       VkSampleLocationEXT                       locations[MAX_SAMPLE_LOCATIONS];
    } sample_locations;
 
-   VkExtent2D                                   fragment_shading_rate;
+   struct {
+      VkExtent2D                                rate;
+      VkFragmentShadingRateCombinerOpKHR        ops[2];
+   } fragment_shading_rate;
 
    VkCullModeFlags                              cull_mode;
    VkFrontFace                                  front_face;
@@ -2951,6 +2964,9 @@ struct anv_subpass {
    VkResolveModeFlagBitsKHR                     depth_resolve_mode;
    VkResolveModeFlagBitsKHR                     stencil_resolve_mode;
 
+   struct anv_subpass_attachment *              fsr_attachment;
+   VkExtent2D                                   fsr_extent;
+
    uint32_t                                     view_mask;
 
    /** Subpass has a depth/stencil self-dependency */
@@ -2994,8 +3010,9 @@ struct anv_render_pass {
 
 /* RTs * 2 (for resolve attachments)
  * depth/sencil * 2
+ * fragment shading rate * 1
  */
-#define MAX_DYN_RENDER_ATTACHMENTS (MAX_RTS * 2 + 2 * 2)
+#define MAX_DYN_RENDER_ATTACHMENTS (MAX_RTS * 2 + 2 * 2 + 1)
 
 /* And this, kids, is what we call a nasty hack. */
 struct anv_dynamic_render_pass {
@@ -3271,9 +3288,15 @@ anv_cmd_buffer_gfx_push_constants(struct anv_cmd_buffer *cmd_buffer);
 struct anv_state
 anv_cmd_buffer_cs_push_constants(struct anv_cmd_buffer *cmd_buffer);
 
+const struct anv_image_view *
+anv_cmd_buffer_get_first_color_view(const struct anv_cmd_buffer *cmd_buffer);
+
 const struct anv_image_view *
 anv_cmd_buffer_get_depth_stencil_view(const struct anv_cmd_buffer *cmd_buffer);
 
+const struct anv_image_view *
+anv_cmd_buffer_get_fsr_view(const struct anv_cmd_buffer *cmd_buffer);
+
 VkResult
 anv_cmd_buffer_alloc_blorp_binding_table(struct anv_cmd_buffer *cmd_buffer,
                                          uint32_t num_entries,
@@ -3499,8 +3522,6 @@ struct anv_graphics_pipeline {
 
    struct anv_state                             blend_state;
 
-   struct anv_state                             cps_state;
-
    uint32_t                                     vb_used;
    struct anv_pipeline_vertex_binding {
       uint32_t                                  stride;
diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c
index 5b454d9ecc9..f929bc084e1 100644
--- a/src/intel/vulkan/genX_cmd_buffer.c
+++ b/src/intel/vulkan/genX_cmd_buffer.c
@@ -6011,6 +6011,42 @@ cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
    cmd_buffer->state.hiz_enabled = isl_aux_usage_has_hiz(info.hiz_usage);
 }
 
+static void
+cmd_buffer_emit_cps_control_buffer(struct anv_cmd_buffer *cmd_buffer)
+{
+#if GFX_VERx10 >= 125
+   struct anv_device *device = cmd_buffer->device;
+
+   if (!device->vk.enabled_extensions.KHR_fragment_shading_rate)
+      return;
+
+   uint32_t *dw = anv_batch_emit_dwords(&cmd_buffer->batch,
+                                        device->isl_dev.cpb.size / 4);
+   if (dw == NULL)
+      return;
+
+   struct isl_cpb_emit_info info = { };
+
+   const struct anv_image_view *fsr_iview =
+      anv_cmd_buffer_get_fsr_view(cmd_buffer);
+   if (fsr_iview) {
+      info.view = &fsr_iview->planes[0].isl;
+      info.surf = &fsr_iview->image->planes[0].primary_surface.isl;
+      info.address =
+         anv_batch_emit_reloc(&cmd_buffer->batch,
+                              dw + device->isl_dev.cpb.offset / 4,
+                              fsr_iview->image->bindings[0].address.bo,
+                              fsr_iview->image->bindings[0].address.offset +
+                              fsr_iview->image->bindings[0].memory_range.offset);
+      info.mocs =
+         anv_mocs(device, fsr_iview->image->bindings[0].address.bo,
+                  ISL_SURF_USAGE_CPB_BIT);
+   }
+
+   isl_emit_cpb_control_s(&device->isl_dev, dw, &info);
+#endif /* GFX_VERx10 >= 125 */
+}
+
 /**
  * This ANDs the view mask of the current subpass with the pending clear
  * views in the attachment to get the mask of views active in the subpass
@@ -6269,12 +6305,13 @@ cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer,
          continue;
 
       assert(a < cmd_state->pass->attachment_count);
+      struct anv_subpass_attachment *att = &subpass->attachments[i];
       struct anv_attachment_state *att_state = &cmd_state->attachments[a];
 
-      struct anv_image_view *iview = cmd_state->attachments[a].image_view;
+      struct anv_image_view *iview = att_state->image_view;
       const struct anv_image *image = iview->image;
 
-      VkImageLayout target_layout = subpass->attachments[i].layout;
+      VkImageLayout target_layout = att->layout;
       VkImageLayout target_stencil_layout =
          subpass->attachments[i].stencil_layout;
 
@@ -6295,6 +6332,22 @@ cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer,
          layer_count = fb->layers;
       }
 
+      /* Treat the fragment shading rate attachment as color. But make sure we
+       * don't use fb->layers if the fragment shading rate attachment only has
+       * one layer.
+       *
+       * Vulkan spec 1.2.170 - VkFramebufferCreateInfo :
+       *
+       *    "each element of pAttachments that is used as a fragment shading
+       *     rate attachment by renderPass must have a layerCount that is
+       *     either 1, or greater than layers"
+       */
+      if ((att->usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) &&
+          iview->planes[0].isl.array_len == 1) {
+         base_layer = 0;
+         layer_count = 1;
+      }
+
       if (image->vk.aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV) {
          bool will_full_fast_clear =
             (att_state->pending_clear_aspects & VK_IMAGE_ASPECT_COLOR_BIT) &&
@@ -6464,6 +6517,8 @@ cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer,
 #endif
 
    cmd_buffer_emit_depth_stencil(cmd_buffer);
+
+   cmd_buffer_emit_cps_control_buffer(cmd_buffer);
 }
 
 static enum blorp_filter
@@ -6820,8 +6875,9 @@ cmd_buffer_do_layout_transitions(struct anv_cmd_buffer *cmd_buffer,
          continue;
 
       assert(a < cmd_state->pass->attachment_count);
+      struct anv_subpass_attachment *att = &subpass->attachments[i];
       struct anv_attachment_state *att_state = &cmd_state->attachments[a];
-      struct anv_image_view *iview = cmd_state->attachments[a].image_view;
+      struct anv_image_view *iview = att_state->image_view;
       const struct anv_image *image = iview->image;
 
       /* Transition the image into the final layout for this render pass */
@@ -6840,6 +6896,22 @@ cmd_buffer_do_layout_transitions(struct anv_cmd_buffer *cmd_buffer,
          layer_count = fb->layers;
       }
 
+      /* Treat the fragment shading rate attachment as color. But make sure we
+       * don't use fb->layers if the fragment shading rate attachment only has
+       * one layer.
+       *
+       * Vulkan spec 1.2.170 - VkFramebufferCreateInfo :
+       *
+       *    "each element of pAttachments that is used as a fragment shading
+       *     rate attachment by renderPass must have a layerCount that is
+       *     either 1, or greater than layers"
+       */
+      if (att->usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR &&
+          iview->planes[0].isl.array_len == 1) {
+         base_layer = 0;
+         layer_count = 1;
+      }
+
       if (image->vk.aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV) {
          assert(image->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT);
          transition_color_buffer(cmd_buffer, image, VK_IMAGE_ASPECT_COLOR_BIT,
@@ -7141,6 +7213,18 @@ genX(cmd_buffer_setup_attachments_dynrender)(struct anv_cmd_buffer *cmd_buffer,
       }
    }
 
+   if (subpass->fsr_attachment) {
+      const VkRenderingFragmentShadingRateAttachmentInfoKHR *fsr_att_info =
+         vk_find_struct_const(info->pNext,
+                              RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR);
+      assert(fsr_att_info);
+
+      struct anv_attachment_state *fsr_att_state =
+         &state->attachments[subpass->fsr_attachment->attachment];
+      fsr_att_state->image_view =
+         anv_image_view_from_handle(fsr_att_info->imageView);
+   }
+
    return VK_SUCCESS;
 }
 
@@ -7251,6 +7335,8 @@ cmd_buffer_begin_rendering(struct anv_cmd_buffer *cmd_buffer,
 #endif
 
    cmd_buffer_emit_depth_stencil(cmd_buffer);
+
+   cmd_buffer_emit_cps_control_buffer(cmd_buffer);
 }
 
 static void
diff --git a/src/intel/vulkan/genX_pipeline.c b/src/intel/vulkan/genX_pipeline.c
index a80435fe3f5..8640d9a1ac2 100644
--- a/src/intel/vulkan/genX_pipeline.c
+++ b/src/intel/vulkan/genX_pipeline.c
@@ -847,22 +847,16 @@ emit_ms_state(struct anv_graphics_pipeline *pipeline,
    anv_batch_emit(&pipeline->base.batch, GENX(3DSTATE_SAMPLE_MASK), sm) {
       sm.SampleMask = sample_mask;
    }
+}
 
-   pipeline->cps_state = ANV_STATE_NULL;
+static void
+emit_3dstate_cps(struct anv_graphics_pipeline *pipeline, uint32_t dynamic_states)
+{
 #if GFX_VER >= 11
    if (!(dynamic_states & ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE) &&
        pipeline->base.device->vk.enabled_extensions.KHR_fragment_shading_rate) {
-#if GFX_VER >= 12
-      struct anv_device *device = pipeline->base.device;
-      const uint32_t num_dwords =
-         GENX(CPS_STATE_length) * 4 * pipeline->dynamic_state.viewport.count;
-      pipeline->cps_state =
-         anv_state_pool_alloc(&device->dynamic_state_pool, num_dwords, 32);
-#endif
-
       genX(emit_shading_rate)(&pipeline->base.batch,
                               pipeline,
-                              pipeline->cps_state,
                               &pipeline->dynamic_state);
    }
 #endif
@@ -2407,6 +2401,12 @@ emit_3dstate_ps_extra(struct anv_graphics_pipeline *pipeline,
       ps.PixelShaderRequiresSourceDepthandorWPlaneCoefficients =
          wm_prog_data->uses_depth_w_coefficients;
       ps.PixelShaderIsPerCoarsePixel = wm_prog_data->per_coarse_pixel_dispatch;
+#endif
+#if GFX_VERx10 >= 125
+      /* TODO: We should only require this when the last geometry shader uses
+       *       a fragment shading rate that is not constant.
+       */
+      ps.EnablePSDependencyOnCPsizeChange = wm_prog_data->per_coarse_pixel_dispatch;
 #endif
    }
 }
@@ -2612,6 +2612,8 @@ genX(graphics_pipeline_create)(
 
       emit_3dstate_vf_statistics(pipeline);
 
+      emit_3dstate_cps(pipeline, dynamic_states);
+
       emit_3dstate_streamout(pipeline, pCreateInfo->pRasterizationState,
                              dynamic_states);
    }
diff --git a/src/intel/vulkan/genX_state.c b/src/intel/vulkan/genX_state.c
index 104d0a8efd8..a91c07418f6 100644
--- a/src/intel/vulkan/genX_state.c
+++ b/src/intel/vulkan/genX_state.c
@@ -358,6 +358,111 @@ genX(init_device_state)(struct anv_device *device)
    return res;
 }
 
+#if GFX_VERx10 >= 125
+#define maybe_for_each_shading_rate_op(name) \
+   for (VkFragmentShadingRateCombinerOpKHR name = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; \
+        name <= VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; \
+        name++)
+#elif GFX_VER >= 12
+#define maybe_for_each_shading_rate_op(name)
+#endif
+
+/* Rather than reemitting the CPS_STATE structure everything those changes and
+ * for as many viewports as needed, we can just prepare all possible cases and
+ * just pick the right offset from the prepacked states when needed.
+ */
+void
+genX(init_cps_device_state)(struct anv_device *device)
+{
+#if GFX_VER >= 12
+   void *cps_state_ptr = device->cps_states.map;
+
+   /* Disabled CPS mode */
+   for (uint32_t __v = 0; __v < MAX_VIEWPORTS; __v++) {
+      struct GENX(CPS_STATE) cps_state = {
+         .CoarsePixelShadingMode = CPS_MODE_CONSTANT,
+         .MinCPSizeX = 1,
+         .MinCPSizeY = 1,
+#if GFX_VERx10 >= 125
+         .Combiner0OpcodeforCPsize = PASSTHROUGH,
+         .Combiner1OpcodeforCPsize = PASSTHROUGH,
+#endif /* GFX_VERx10 >= 125 */
+
+      };
+
+      GENX(CPS_STATE_pack)(NULL, cps_state_ptr, &cps_state);
+      cps_state_ptr += GENX(CPS_STATE_length) * 4;
+   }
+
+   maybe_for_each_shading_rate_op(op0) {
+      maybe_for_each_shading_rate_op(op1) {
+         for (uint32_t x = 1; x <= 4; x *= 2) {
+            for (uint32_t y = 1; y <= 4; y *= 2) {
+               struct GENX(CPS_STATE) cps_state = {
+                  .CoarsePixelShadingMode = CPS_MODE_CONSTANT,
+                  .MinCPSizeX = x,
+                  .MinCPSizeY = y,
+               };
+
+#if GFX_VERx10 >= 125
+               static const uint32_t combiner_ops[] = {
+                  [VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR]    = PASSTHROUGH,
+                  [VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR] = OVERRIDE,
+                  [VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR]     = HIGH_QUALITY,
+                  [VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR]     = LOW_QUALITY,
+                  [VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR]     = RELATIVE,
+               };
+
+               cps_state.Combiner0OpcodeforCPsize = combiner_ops[op0];
+               cps_state.Combiner1OpcodeforCPsize = combiner_ops[op1];
+#endif /* GFX_VERx10 >= 125 */
+
+               for (uint32_t __v = 0; __v < MAX_VIEWPORTS; __v++) {
+                  GENX(CPS_STATE_pack)(NULL, cps_state_ptr, &cps_state);
+                  cps_state_ptr += GENX(CPS_STATE_length) * 4;
+               }
+            }
+         }
+      }
+   }
+#endif /* GFX_VER >= 12 */
+}
+
+#if GFX_VER >= 12
+static uint32_t
+get_cps_state_offset(struct anv_device *device, bool cps_enabled,
+                     const struct anv_dynamic_state *d)
+{
+   if (!cps_enabled)
+      return device->cps_states.offset;
+
+   uint32_t offset;
+   static const uint32_t size_index[] = {
+      [1] = 0,
+      [2] = 1,
+      [4] = 2,
+   };
+
+#if GFX_VERx10 >= 125
+   offset =
+      1 + /* skip disabled */
+      d->fragment_shading_rate.ops[0] * 5 * 3 * 3 +
+      d->fragment_shading_rate.ops[1] * 3 * 3 +
+      size_index[d->fragment_shading_rate.rate.width] * 3 +
+      size_index[d->fragment_shading_rate.rate.height];
+#else
+   offset =
+      1 + /* skip disabled */
+      size_index[d->fragment_shading_rate.rate.width] * 3 +
+      size_index[d->fragment_shading_rate.rate.height];
+#endif
+
+   offset *= MAX_VIEWPORTS * GENX(CPS_STATE_length) * 4;
+
+   return device->cps_states.offset + offset;
+}
+#endif /* GFX_VER >= 12 */
+
 void
 genX(emit_l3_config)(struct anv_batch *batch,
                      const struct anv_device *device,
@@ -602,7 +707,6 @@ genX(emit_sample_pattern)(struct anv_batch *batch, uint32_t samples,
 void
 genX(emit_shading_rate)(struct anv_batch *batch,
                         const struct anv_graphics_pipeline *pipeline,
-                        struct anv_state cps_states,
                         struct anv_dynamic_state *dynamic_state)
 {
    const struct brw_wm_prog_data *wm_prog_data = get_wm_prog_data(pipeline);
@@ -612,28 +716,34 @@ genX(emit_shading_rate)(struct anv_batch *batch,
    anv_batch_emit(batch, GENX(3DSTATE_CPS), cps) {
       cps.CoarsePixelShadingMode = cps_enable ? CPS_MODE_CONSTANT : CPS_MODE_NONE;
       if (cps_enable) {
-         cps.MinCPSizeX = dynamic_state->fragment_shading_rate.width;
-         cps.MinCPSizeY = dynamic_state->fragment_shading_rate.height;
+         cps.MinCPSizeX = dynamic_state->fragment_shading_rate.rate.width;
+         cps.MinCPSizeY = dynamic_state->fragment_shading_rate.rate.height;
       }
    }
-#elif GFX_VER == 12
-   for (uint32_t i = 0; i < dynamic_state->viewport.count; i++) {
-      uint32_t *cps_state_dwords =
-         cps_states.map + GENX(CPS_STATE_length) * 4 * i;
-      struct GENX(CPS_STATE) cps_state = {
-         .CoarsePixelShadingMode = cps_enable ? CPS_MODE_CONSTANT : CPS_MODE_NONE,
-      };
-
-      if (cps_enable) {
-         cps_state.MinCPSizeX = dynamic_state->fragment_shading_rate.width;
-         cps_state.MinCPSizeY = dynamic_state->fragment_shading_rate.height;
-      }
-
-      GENX(CPS_STATE_pack)(NULL, cps_state_dwords, &cps_state);
+#elif GFX_VER >= 12
+   /* TODO: we can optimize this flush in the following cases:
+    *
+    *    In the case where the last geometry shader emits a value that is not
+    *    constant, we can avoid this stall because we can synchronize the
+    *    pixel shader internally with
+    *    3DSTATE_PS::EnablePSDependencyOnCPsizeChange.
+    *
+    *    If we know that the previous pipeline and the current one are using
+    *    the same fragment shading rate.
+    */
+   anv_batch_emit(batch, GENX(PIPE_CONTROL), pc) {
+#if GFX_VERx10 >= 125
+      pc.PSSStallSyncEnable = true;
+#else
+      pc.PSDSyncEnable = true;
+#endif
    }
 
    anv_batch_emit(batch, GENX(3DSTATE_CPS_POINTERS), cps) {
-      cps.CoarsePixelShadingStateArrayPointer = cps_states.offset;
+      struct anv_device *device = pipeline->base.device;
+
+      cps.CoarsePixelShadingStateArrayPointer =
+         get_cps_state_offset(device, cps_enable, dynamic_state);
    }
 #endif
 }
diff --git a/src/intel/vulkan/gfx8_cmd_buffer.c b/src/intel/vulkan/gfx8_cmd_buffer.c
index 94b813c6a78..fa4444971b7 100644
--- a/src/intel/vulkan/gfx8_cmd_buffer.c
+++ b/src/intel/vulkan/gfx8_cmd_buffer.c
@@ -420,6 +420,13 @@ genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer)
    struct anv_graphics_pipeline *pipeline = cmd_buffer->state.gfx.pipeline;
    struct anv_dynamic_state *d = &cmd_buffer->state.gfx.dynamic;
 
+#if GFX_VER >= 11
+   if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE) {
+      genX(emit_shading_rate)(&cmd_buffer->batch, pipeline,
+                              &cmd_buffer->state.gfx.dynamic);
+   }
+#endif /* GFX_VER >= 11 */
+
    if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_DYNAMIC_PRIMITIVE_TOPOLOGY) {
       uint32_t topology;
       if (anv_pipeline_has_stage(pipeline, MESA_SHADER_TESS_EVAL))
@@ -803,23 +810,6 @@ genX(cmd_buffer_flush_dynamic_state)(struct anv_cmd_buffer *cmd_buffer)
       }
    }
 
-#if GFX_VER >= 11
-   if (cmd_buffer->state.gfx.dirty & ANV_CMD_DIRTY_DYNAMIC_SHADING_RATE) {
-      struct anv_state cps_states = ANV_STATE_NULL;
-
-#if GFX_VER >= 12
-      uint32_t count = cmd_buffer->state.gfx.dynamic.viewport.count;
-      cps_states =
-         anv_cmd_buffer_alloc_dynamic_state(cmd_buffer,
-                                            GENX(CPS_STATE_length) * 4 * count,
-                                            32);
-#endif /* GFX_VER >= 12 */
-
-      genX(emit_shading_rate)(&cmd_buffer->batch, pipeline, cps_states,
-                              &cmd_buffer->state.gfx.dynamic);
-   }
-#endif /* GFX_VER >= 11 */
-
    cmd_buffer->state.gfx.dirty = 0;
 }
 



More information about the mesa-commit mailing list