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_descriptor_table.h"
8
9 #include "hk_device.h"
10 #include "hk_physical_device.h"
11
12 #include "asahi/lib/agx_bo.h"
13 #include <sys/mman.h>
14
15 static VkResult
hk_descriptor_table_grow_locked(struct hk_device * dev,struct hk_descriptor_table * table,uint32_t new_alloc)16 hk_descriptor_table_grow_locked(struct hk_device *dev,
17 struct hk_descriptor_table *table,
18 uint32_t new_alloc)
19 {
20 struct agx_bo *new_bo;
21 uint32_t *new_free_table;
22
23 assert(new_alloc > table->alloc && new_alloc <= table->max_alloc);
24
25 const uint32_t new_bo_size = new_alloc * table->desc_size;
26 new_bo = agx_bo_create(&dev->dev, new_bo_size, 0, 0, "Descriptor table");
27
28 if (new_bo == NULL) {
29 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
30 "Failed to allocate the descriptor table");
31 }
32
33 void *new_map = new_bo->map;
34
35 assert(table->bo == NULL && "not yet implemented sparse binding");
36 table->bo = new_bo;
37 table->map = new_map;
38
39 const size_t new_free_table_size = new_alloc * sizeof(uint32_t);
40 new_free_table =
41 vk_realloc(&dev->vk.alloc, table->free_table, new_free_table_size, 4,
42 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
43 if (new_free_table == NULL) {
44 return vk_errorf(dev, VK_ERROR_OUT_OF_HOST_MEMORY,
45 "Failed to allocate image descriptor free table");
46 }
47 table->free_table = new_free_table;
48
49 table->alloc = new_alloc;
50
51 return VK_SUCCESS;
52 }
53
54 VkResult
hk_descriptor_table_init(struct hk_device * dev,struct hk_descriptor_table * table,uint32_t descriptor_size,uint32_t min_descriptor_count,uint32_t max_descriptor_count)55 hk_descriptor_table_init(struct hk_device *dev,
56 struct hk_descriptor_table *table,
57 uint32_t descriptor_size,
58 uint32_t min_descriptor_count,
59 uint32_t max_descriptor_count)
60 {
61 memset(table, 0, sizeof(*table));
62 VkResult result;
63
64 simple_mtx_init(&table->mutex, mtx_plain);
65
66 assert(util_is_power_of_two_nonzero(min_descriptor_count));
67 assert(util_is_power_of_two_nonzero(max_descriptor_count));
68
69 /* TODO: sparse binding for stable gpu va */
70 min_descriptor_count = max_descriptor_count;
71
72 table->desc_size = descriptor_size;
73 table->alloc = 0;
74 table->max_alloc = max_descriptor_count;
75 table->next_desc = 0;
76 table->free_count = 0;
77
78 result = hk_descriptor_table_grow_locked(dev, table, min_descriptor_count);
79 if (result != VK_SUCCESS) {
80 hk_descriptor_table_finish(dev, table);
81 return result;
82 }
83
84 return VK_SUCCESS;
85 }
86
87 void
hk_descriptor_table_finish(struct hk_device * dev,struct hk_descriptor_table * table)88 hk_descriptor_table_finish(struct hk_device *dev,
89 struct hk_descriptor_table *table)
90 {
91 agx_bo_unreference(&dev->dev, table->bo);
92 vk_free(&dev->vk.alloc, table->free_table);
93 simple_mtx_destroy(&table->mutex);
94 }
95
96 #define HK_IMAGE_DESC_INVALID
97
98 static VkResult
hk_descriptor_table_alloc_locked(struct hk_device * dev,struct hk_descriptor_table * table,uint32_t * index_out)99 hk_descriptor_table_alloc_locked(struct hk_device *dev,
100 struct hk_descriptor_table *table,
101 uint32_t *index_out)
102 {
103 VkResult result;
104
105 if (table->free_count > 0) {
106 *index_out = table->free_table[--table->free_count];
107 return VK_SUCCESS;
108 }
109
110 if (table->next_desc < table->alloc) {
111 *index_out = table->next_desc++;
112 return VK_SUCCESS;
113 }
114
115 if (table->next_desc >= table->max_alloc) {
116 return vk_errorf(dev, VK_ERROR_OUT_OF_HOST_MEMORY,
117 "Descriptor table not large enough");
118 }
119
120 result = hk_descriptor_table_grow_locked(dev, table, table->alloc * 2);
121 if (result != VK_SUCCESS)
122 return result;
123
124 assert(table->next_desc < table->alloc);
125 *index_out = table->next_desc++;
126
127 return VK_SUCCESS;
128 }
129
130 static VkResult
hk_descriptor_table_add_locked(struct hk_device * dev,struct hk_descriptor_table * table,const void * desc_data,size_t desc_size,uint32_t * index_out)131 hk_descriptor_table_add_locked(struct hk_device *dev,
132 struct hk_descriptor_table *table,
133 const void *desc_data, size_t desc_size,
134 uint32_t *index_out)
135 {
136 VkResult result = hk_descriptor_table_alloc_locked(dev, table, index_out);
137 if (result != VK_SUCCESS)
138 return result;
139
140 void *map = (char *)table->map + (*index_out * table->desc_size);
141
142 assert(desc_size == table->desc_size);
143 memcpy(map, desc_data, table->desc_size);
144
145 return VK_SUCCESS;
146 }
147
148 VkResult
hk_descriptor_table_add(struct hk_device * dev,struct hk_descriptor_table * table,const void * desc_data,size_t desc_size,uint32_t * index_out)149 hk_descriptor_table_add(struct hk_device *dev,
150 struct hk_descriptor_table *table,
151 const void *desc_data, size_t desc_size,
152 uint32_t *index_out)
153 {
154 simple_mtx_lock(&table->mutex);
155 VkResult result = hk_descriptor_table_add_locked(dev, table, desc_data,
156 desc_size, index_out);
157 simple_mtx_unlock(&table->mutex);
158
159 return result;
160 }
161
162 void
hk_descriptor_table_remove(struct hk_device * dev,struct hk_descriptor_table * table,uint32_t index)163 hk_descriptor_table_remove(struct hk_device *dev,
164 struct hk_descriptor_table *table, uint32_t index)
165 {
166 simple_mtx_lock(&table->mutex);
167
168 void *map = (char *)table->map + (index * table->desc_size);
169 memset(map, 0, table->desc_size);
170
171 /* Sanity check for double-free */
172 assert(table->free_count < table->alloc);
173 for (uint32_t i = 0; i < table->free_count; i++)
174 assert(table->free_table[i] != index);
175
176 table->free_table[table->free_count++] = index;
177
178 simple_mtx_unlock(&table->mutex);
179 }
180