zink: implement ARB_texture_buffer_object

the pipe cap for this was enabled for some reason, but the actual functionality
was never implemented

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7132>
diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
index 47971cf..f8c1f34 100644
--- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
+++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c
@@ -446,6 +446,7 @@
          return stage_offset + index;
 
       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+      case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
          assert(index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
          return stage_offset + PIPE_MAX_CONSTANT_BUFFERS + index;
 
@@ -500,7 +501,7 @@
 
          spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0);
          int binding = zink_binding(ctx->stage,
-                                    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                    zink_sampler_type(glsl_without_array(var->type)),
                                     var->data.binding + i);
          spirv_builder_emit_binding(&ctx->builder, var_id, binding);
       }
@@ -520,7 +521,7 @@
 
       spirv_builder_emit_descriptor_set(&ctx->builder, var_id, 0);
       int binding = zink_binding(ctx->stage,
-                                 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                 zink_sampler_type(var->type),
                                  var->data.binding);
       spirv_builder_emit_binding(&ctx->builder, var_id, binding);
    }
@@ -2166,6 +2167,8 @@
    case MESA_SHADER_FRAGMENT:
    case MESA_SHADER_COMPUTE:
       spirv_builder_emit_cap(&ctx.builder, SpvCapabilityShader);
+      spirv_builder_emit_cap(&ctx.builder, SpvCapabilityImageBuffer);
+      spirv_builder_emit_cap(&ctx.builder, SpvCapabilitySampledBuffer);
       break;
 
    case MESA_SHADER_TESS_CTRL:
diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.h b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.h
index 04543c3..ec170a7 100644
--- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.h
+++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.h
@@ -28,6 +28,7 @@
 #include <stdint.h>
 #include <vulkan/vulkan.h>
 
+#include "compiler/nir/nir.h"
 #include "compiler/shader_enums.h"
 #include "pipe/p_state.h"
 
@@ -51,6 +52,18 @@
 uint32_t
 zink_binding(gl_shader_stage stage, VkDescriptorType type, int index);
 
+static inline VkDescriptorType
+zink_sampler_type(const struct glsl_type *type)
+{
+   assert(glsl_type_is_sampler(type));
+   if (glsl_get_sampler_dim(type) < GLSL_SAMPLER_DIM_BUF || glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_MS)
+      return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+   if (glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_BUF)
+      return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+   unreachable("unimplemented");
+   return 0;
+}
+
 struct nir_shader;
 
 bool
diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c
index ad2e6b0..77297d5 100644
--- a/src/gallium/drivers/zink/zink_compiler.c
+++ b/src/gallium/drivers/zink/zink_compiler.c
@@ -311,12 +311,13 @@
          } else {
             assert(var->data.mode == nir_var_uniform);
             if (glsl_type_is_sampler(var->type)) {
+               VkDescriptorType vktype = zink_sampler_type(var->type);
                int binding = zink_binding(nir->info.stage,
-                                          VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                          vktype,
                                           var->data.binding);
                ret->bindings[ret->num_bindings].index = var->data.binding;
                ret->bindings[ret->num_bindings].binding = binding;
-               ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+               ret->bindings[ret->num_bindings].type = vktype;
                ret->num_bindings++;
             } else if (glsl_type_is_array(var->type)) {
                /* need to unroll possible arrays of arrays before checking type
@@ -325,15 +326,16 @@
                const struct glsl_type *type = glsl_without_array(var->type);
                if (!glsl_type_is_sampler(type))
                   continue;
+               VkDescriptorType vktype = zink_sampler_type(type);
 
                unsigned size = glsl_get_aoa_size(var->type);
                for (int i = 0; i < size; ++i) {
                   int binding = zink_binding(nir->info.stage,
-                                             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                                             vktype,
                                              var->data.binding + i);
                   ret->bindings[ret->num_bindings].index = var->data.binding + i;
                   ret->bindings[ret->num_bindings].binding = binding;
-                  ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+                  ret->bindings[ret->num_bindings].type = vktype;
                   ret->num_bindings++;
                }
             }
diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c
index 514f705..1b0aaf5 100644
--- a/src/gallium/drivers/zink/zink_context.c
+++ b/src/gallium/drivers/zink/zink_context.c
@@ -252,6 +252,7 @@
    struct zink_screen *screen = zink_screen(pctx->screen);
    struct zink_resource *res = zink_resource(pres);
    struct zink_sampler_view *sampler_view = CALLOC_STRUCT(zink_sampler_view);
+   VkResult err;
 
    sampler_view->base = *state;
    sampler_view->base.texture = NULL;
@@ -259,28 +260,38 @@
    sampler_view->base.reference.count = 1;
    sampler_view->base.context = pctx;
 
-   VkImageViewCreateInfo ivci = {};
-   ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-   ivci.image = res->image;
-   ivci.viewType = image_view_type(state->target);
-   ivci.format = zink_get_format(screen, state->format);
-   ivci.components.r = component_mapping(state->swizzle_r);
-   ivci.components.g = component_mapping(state->swizzle_g);
-   ivci.components.b = component_mapping(state->swizzle_b);
-   ivci.components.a = component_mapping(state->swizzle_a);
+   if (state->target != PIPE_BUFFER) {
+      VkImageViewCreateInfo ivci = {};
+      ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+      ivci.image = res->image;
+      ivci.viewType = image_view_type(state->target);
+      ivci.format = zink_get_format(screen, state->format);
+      ivci.components.r = component_mapping(state->swizzle_r);
+      ivci.components.g = component_mapping(state->swizzle_g);
+      ivci.components.b = component_mapping(state->swizzle_b);
+      ivci.components.a = component_mapping(state->swizzle_a);
 
-   ivci.subresourceRange.aspectMask = sampler_aspect_from_format(state->format);
-   ivci.subresourceRange.baseMipLevel = state->u.tex.first_level;
-   ivci.subresourceRange.baseArrayLayer = state->u.tex.first_layer;
-   ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1;
-   ivci.subresourceRange.layerCount = state->u.tex.last_layer - state->u.tex.first_layer + 1;
+      ivci.subresourceRange.aspectMask = sampler_aspect_from_format(state->format);
+      ivci.subresourceRange.baseMipLevel = state->u.tex.first_level;
+      ivci.subresourceRange.baseArrayLayer = state->u.tex.first_layer;
+      ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1;
+      ivci.subresourceRange.layerCount = state->u.tex.last_layer - state->u.tex.first_layer + 1;
 
-   VkResult err = vkCreateImageView(screen->dev, &ivci, NULL, &sampler_view->image_view);
+      err = vkCreateImageView(screen->dev, &ivci, NULL, &sampler_view->image_view);
+   } else {
+      VkBufferViewCreateInfo bvci = {};
+      bvci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
+      bvci.buffer = res->buffer;
+      bvci.format = zink_get_format(screen, state->format);
+      bvci.offset = state->u.buf.offset;
+      bvci.range = state->u.buf.size;
+
+      err = vkCreateBufferView(screen->dev, &bvci, NULL, &sampler_view->buffer_view);
+   }
    if (err != VK_SUCCESS) {
       FREE(sampler_view);
       return NULL;
    }
-
    return &sampler_view->base;
 }
 
@@ -289,7 +300,10 @@
                           struct pipe_sampler_view *pview)
 {
    struct zink_sampler_view *view = zink_sampler_view(pview);
-   vkDestroyImageView(zink_screen(pctx->screen)->dev, view->image_view, NULL);
+   if (pview->texture->target == PIPE_BUFFER)
+      vkDestroyBufferView(zink_screen(pctx->screen)->dev, view->buffer_view, NULL);
+   else
+      vkDestroyImageView(zink_screen(pctx->screen)->dev, view->image_view, NULL);
    pipe_resource_reference(&pview->texture, NULL);
    FREE(view);
 }
diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h
index e76e256..52c5459 100644
--- a/src/gallium/drivers/zink/zink_context.h
+++ b/src/gallium/drivers/zink/zink_context.h
@@ -48,7 +48,10 @@
 
 struct zink_sampler_view {
    struct pipe_sampler_view base;
-   VkImageView image_view;
+   union {
+      VkImageView image_view;
+      VkBufferView buffer_view;
+   };
 };
 
 static inline struct zink_sampler_view *
diff --git a/src/gallium/drivers/zink/zink_draw.c b/src/gallium/drivers/zink/zink_draw.c
index 6302436..ad5d6fa 100644
--- a/src/gallium/drivers/zink/zink_draw.c
+++ b/src/gallium/drivers/zink/zink_draw.c
@@ -320,18 +320,22 @@
             struct zink_sampler_view *sampler_view = zink_sampler_view(psampler_view);
 
             struct zink_resource *res = zink_resource(psampler_view->texture);
-            VkImageLayout layout = res->layout;
-            if (layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
-                layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
-                layout != VK_IMAGE_LAYOUT_GENERAL) {
-               transitions[num_transitions++] = res;
-               layout = VK_IMAGE_LAYOUT_GENERAL;
+            if (res->base.target == PIPE_BUFFER)
+                wds[num_wds].pTexelBufferView = &sampler_view->buffer_view;
+            else {
+               VkImageLayout layout = res->layout;
+               if (layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
+                   layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
+                   layout != VK_IMAGE_LAYOUT_GENERAL) {
+                  transitions[num_transitions++] = res;
+                  layout = VK_IMAGE_LAYOUT_GENERAL;
+               }
+               image_infos[num_image_info].imageLayout = layout;
+               image_infos[num_image_info].imageView = sampler_view->image_view;
+               image_infos[num_image_info].sampler = ctx->samplers[i][index];
+               wds[num_wds].pImageInfo = image_infos + num_image_info;
+               ++num_image_info;
             }
-            image_infos[num_image_info].imageLayout = layout;
-            image_infos[num_image_info].imageView = sampler_view->image_view;
-            image_infos[num_image_info].sampler = ctx->samplers[i][index];
-            wds[num_wds].pImageInfo = image_infos + num_image_info;
-            ++num_image_info;
          }
 
          wds[num_wds].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c
index eab65c6..06041e7 100644
--- a/src/gallium/drivers/zink/zink_resource.c
+++ b/src/gallium/drivers/zink/zink_resource.c
@@ -110,8 +110,12 @@
       bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
                   VK_BUFFER_USAGE_TRANSFER_DST_BIT;
 
+      if (templ->bind & PIPE_BIND_SAMPLER_VIEW)
+         bci.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+
       if (templ->bind & PIPE_BIND_VERTEX_BUFFER)
-         bci.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+         bci.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
+                      VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
 
       if (templ->bind & PIPE_BIND_INDEX_BUFFER)
          bci.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;