xref: /aosp_15_r20/external/mesa3d/src/asahi/vulkan/hk_buffer_view.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Valve Corporation
3  * Copyright 2024 Alyssa Rosenzweig
4  * Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
5  * SPDX-License-Identifier: MIT
6  */
7 #include "hk_buffer_view.h"
8 #include "asahi/layout/layout.h"
9 #include "asahi/lib/agx_nir_lower_vbo.h"
10 #include "util/bitscan.h"
11 #include "util/format/u_format.h"
12 #include "util/format/u_formats.h"
13 
14 #include "agx_helpers.h"
15 #include "agx_nir_passes.h"
16 #include "agx_pack.h"
17 #include "hk_buffer.h"
18 #include "hk_device.h"
19 #include "hk_entrypoints.h"
20 #include "hk_physical_device.h"
21 
22 #include "vk_format.h"
23 
24 VkFormatFeatureFlags2
hk_get_buffer_format_features(struct hk_physical_device * pdev,VkFormat vk_format)25 hk_get_buffer_format_features(struct hk_physical_device *pdev,
26                               VkFormat vk_format)
27 {
28    VkFormatFeatureFlags2 features = 0;
29    enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
30 
31    if (p_format == PIPE_FORMAT_NONE)
32       return 0;
33 
34    if (agx_vbo_supports_format(p_format))
35       features |= VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT;
36 
37    if (ail_pixel_format[p_format].texturable &&
38        !util_format_is_depth_or_stencil(p_format)) {
39 
40       features |= VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT;
41 
42       /* RGB32 specially supported for uniform texel buffers only. */
43       if (util_is_power_of_two_nonzero(util_format_get_blocksize(p_format))) {
44          features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT |
45                      VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
46       }
47 
48       if (p_format == PIPE_FORMAT_R32_UINT || p_format == PIPE_FORMAT_R32_SINT)
49          features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
50    }
51 
52    return features;
53 }
54 
55 VKAPI_ATTR VkResult VKAPI_CALL
hk_CreateBufferView(VkDevice _device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pBufferView)56 hk_CreateBufferView(VkDevice _device, const VkBufferViewCreateInfo *pCreateInfo,
57                     const VkAllocationCallbacks *pAllocator,
58                     VkBufferView *pBufferView)
59 {
60    VK_FROM_HANDLE(hk_device, device, _device);
61    VK_FROM_HANDLE(hk_buffer, buffer, pCreateInfo->buffer);
62    struct hk_buffer_view *view;
63    VkResult result;
64 
65    view = vk_buffer_view_create(&device->vk, pCreateInfo, pAllocator,
66                                 sizeof(*view));
67    if (!view)
68       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
69 
70    enum pipe_format format = vk_format_to_pipe_format(view->vk.format);
71    const struct util_format_description *desc = util_format_description(format);
72 
73    uint8_t format_swizzle[4] = {
74       desc->swizzle[0],
75       desc->swizzle[1],
76       desc->swizzle[2],
77       desc->swizzle[3],
78    };
79 
80    if (util_format_is_depth_or_stencil(format)) {
81       assert(!util_format_is_depth_and_stencil(format) &&
82              "separate stencil always used");
83 
84       /* Broadcast depth and stencil */
85       format_swizzle[0] = 0;
86       format_swizzle[1] = 0;
87       format_swizzle[2] = 0;
88       format_swizzle[3] = 0;
89    }
90 
91    /* Decompose the offset into a multiple of 16-bytes (which we can include in
92     * the address) and an extra texel-aligned tail offset of up to 15 bytes.
93     *
94     * This lets us offset partially in the shader instead, getting
95     * around alignment restrictions on the base address pointer.
96     */
97    uint64_t base = hk_buffer_address(buffer, 0) + (view->vk.offset & ~0xf);
98    uint32_t tail_offset_B = view->vk.offset & 0xf;
99    uint32_t tail_offset_el = tail_offset_B / util_format_get_blocksize(format);
100    assert(tail_offset_el * util_format_get_blocksize(format) == tail_offset_B &&
101           "must be texel aligned");
102 
103    struct agx_texture_packed tex;
104    agx_pack(&tex, TEXTURE, cfg) {
105       cfg.dimension = AGX_TEXTURE_DIMENSION_2D;
106       cfg.layout = AGX_LAYOUT_LINEAR;
107       cfg.channels = ail_pixel_format[format].channels;
108       cfg.type = ail_pixel_format[format].type;
109       cfg.swizzle_r = agx_channel_from_pipe(format_swizzle[0]);
110       cfg.swizzle_g = agx_channel_from_pipe(format_swizzle[1]);
111       cfg.swizzle_b = agx_channel_from_pipe(format_swizzle[2]);
112       cfg.swizzle_a = agx_channel_from_pipe(format_swizzle[3]);
113 
114       cfg.width = AGX_TEXTURE_BUFFER_WIDTH;
115       cfg.height = DIV_ROUND_UP(view->vk.elements, cfg.width);
116       cfg.first_level = cfg.last_level = 0;
117 
118       cfg.address = base;
119       cfg.buffer_size_sw = view->vk.elements;
120       cfg.buffer_offset_sw = tail_offset_el;
121 
122       cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
123       cfg.srgb_2_channel = cfg.srgb && util_format_colormask(desc) == 0x3;
124 
125       cfg.depth = 1;
126       cfg.stride = (cfg.width * util_format_get_blocksize(format)) - 16;
127    }
128 
129    struct agx_pbe_packed pbe;
130    agx_pack(&pbe, PBE, cfg) {
131       cfg.dimension = AGX_TEXTURE_DIMENSION_2D;
132       cfg.layout = AGX_LAYOUT_LINEAR;
133       cfg.channels = ail_pixel_format[format].channels;
134       cfg.type = ail_pixel_format[format].type;
135       cfg.srgb = util_format_is_srgb(format);
136 
137       assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);
138 
139       for (unsigned i = 0; i < desc->nr_channels; ++i) {
140          if (desc->swizzle[i] == 0)
141             cfg.swizzle_r = i;
142          else if (desc->swizzle[i] == 1)
143             cfg.swizzle_g = i;
144          else if (desc->swizzle[i] == 2)
145             cfg.swizzle_b = i;
146          else if (desc->swizzle[i] == 3)
147             cfg.swizzle_a = i;
148       }
149 
150       cfg.buffer = base;
151       cfg.buffer_offset_sw = tail_offset_el;
152 
153       cfg.width = AGX_TEXTURE_BUFFER_WIDTH;
154       cfg.height = DIV_ROUND_UP(view->vk.elements, cfg.width);
155       cfg.level = 0;
156       cfg.stride = (cfg.width * util_format_get_blocksize(format)) - 4;
157       cfg.layers = 1;
158       cfg.levels = 1;
159    };
160 
161    result = hk_descriptor_table_add(device, &device->images, &tex, sizeof(tex),
162                                     &view->tex_desc_index);
163    if (result != VK_SUCCESS) {
164       vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
165       return result;
166    }
167 
168    result = hk_descriptor_table_add(device, &device->images, &pbe, sizeof(pbe),
169                                     &view->pbe_desc_index);
170    if (result != VK_SUCCESS) {
171       hk_descriptor_table_remove(device, &device->images, view->tex_desc_index);
172       vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
173       return result;
174    }
175 
176    *pBufferView = hk_buffer_view_to_handle(view);
177 
178    return VK_SUCCESS;
179 }
180 
181 VKAPI_ATTR void VKAPI_CALL
hk_DestroyBufferView(VkDevice _device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator)182 hk_DestroyBufferView(VkDevice _device, VkBufferView bufferView,
183                      const VkAllocationCallbacks *pAllocator)
184 {
185    VK_FROM_HANDLE(hk_device, device, _device);
186    VK_FROM_HANDLE(hk_buffer_view, view, bufferView);
187 
188    if (!view)
189       return;
190 
191    hk_descriptor_table_remove(device, &device->images, view->tex_desc_index);
192    hk_descriptor_table_remove(device, &device->images, view->pbe_desc_index);
193 
194    vk_buffer_view_destroy(&device->vk, pAllocator, &view->vk);
195 }
196