v3dv: always flush draw calls if we are doing sRGB blending

Not quite sure why this is required though. Conversion from/to
sRGB happens on tile loads and stores, with the tile buffer
being always linear, so there should be no difference.

Fixes all test failures in:
dEQP-VK.pipeline.blend.format.r8g8b8a8_srgb.*

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c
index e21eb33..037c4f2 100644
--- a/src/broadcom/vulkan/v3dv_cmd_buffer.c
+++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c
@@ -1719,6 +1719,26 @@
    if (cmd_buffer->state.pipeline == pipeline)
       return;
 
+
+   /* Enable always flush if we are blending to sRGB render targets. This
+    * fixes test failures in:
+    * dEQP-VK.pipeline.blend.format.r8g8b8a8_srgb.*
+    *
+    * FIXME: not sure why we need this. The tile buffer is always linear, with
+    * conversion from/to sRGB happening on tile load/store operations. This
+    * means that when we enable flushing the only difference is that we convert
+    * to sRGB on the store after each draw call and we convert from sRGB on the
+    * load before each draw call, but the blend happens in linear format in the
+    * tile buffer anyway, which is the same scenario as if we didn't flush.
+    */
+   assert(pipeline->subpass);
+   if (pipeline->subpass->has_srgb_rt && pipeline->blend.enables) {
+      assert(cmd_buffer->state.job);
+      cmd_buffer->state.job->always_flush = true;
+      perf_debug("flushing draw calls for subpass %d because bound pipeline "
+                 "uses sRGB blending\n", cmd_buffer->state.subpass_idx);
+   }
+
    cmd_buffer->state.pipeline = pipeline;
 
    cmd_buffer_bind_pipeline_static_state(cmd_buffer, &pipeline->dynamic_state);
diff --git a/src/broadcom/vulkan/v3dv_pass.c b/src/broadcom/vulkan/v3dv_pass.c
index d50ece0..87e08bd 100644
--- a/src/broadcom/vulkan/v3dv_pass.c
+++ b/src/broadcom/vulkan/v3dv_pass.c
@@ -22,6 +22,7 @@
  */
 
 #include "v3dv_private.h"
+#include "vk_format_info.h"
 
 static uint32_t
 num_subpass_attachments(const VkSubpassDescription *desc)
@@ -143,10 +144,16 @@
          p += desc->colorAttachmentCount;
 
          for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) {
+            const uint32_t attachment_idx =
+               desc->pColorAttachments[j].attachment;
             subpass->color_attachments[j] = (struct v3dv_subpass_attachment) {
-               .attachment = desc->pColorAttachments[j].attachment,
+               .attachment = attachment_idx,
                .layout = desc->pColorAttachments[j].layout,
             };
+            if (attachment_idx != VK_ATTACHMENT_UNUSED) {
+               VkFormat format = pass->attachments[attachment_idx].desc.format;
+               subpass->has_srgb_rt |= vk_format_is_srgb(format);
+            }
          }
       }
 
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 823d81c..0040719 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -98,6 +98,11 @@
 #define v3dv_assert(x)
 #endif
 
+#define perf_debug(...) do {                       \
+   if (unlikely(V3D_DEBUG & V3D_DEBUG_PERF))       \
+      fprintf(stderr, __VA_ARGS__);                \
+} while (0)
+
 #define for_each_bit(b, dword)                                               \
    for (uint32_t __dword = (dword);                                          \
         (b) = __builtin_ffs(__dword) - 1, __dword; __dword &= ~(1 << (b)))
@@ -387,6 +392,8 @@
    struct v3dv_subpass_attachment *resolve_attachments;
 
    struct v3dv_subpass_attachment ds_attachment;
+
+   bool has_srgb_rt;
 };
 
 struct v3dv_render_pass_attachment {
diff --git a/src/broadcom/vulkan/vk_format_info.h b/src/broadcom/vulkan/vk_format_info.h
index fee432d..e473e3d 100644
--- a/src/broadcom/vulkan/vk_format_info.h
+++ b/src/broadcom/vulkan/vk_format_info.h
@@ -96,6 +96,12 @@
 }
 
 static inline bool
+vk_format_is_srgb(VkFormat format)
+{
+   return util_format_is_srgb(vk_format_to_pipe_format(format));
+}
+
+static inline bool
 vk_format_is_depth_or_stencil(VkFormat format)
 {
    const VkImageAspectFlags aspects = vk_format_aspects(format);