xref: /aosp_15_r20/external/mesa3d/src/imagination/vulkan/pvr_border.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2023 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <vulkan/vulkan_core.h>
29 
30 #include "hwdef/rogue_hw_utils.h"
31 #include "pvr_bo.h"
32 #include "pvr_border.h"
33 #include "pvr_device_info.h"
34 #include "pvr_formats.h"
35 #include "pvr_private.h"
36 #include "util/bitset.h"
37 #include "util/format/u_format.h"
38 #include "util/format/u_formats.h"
39 #include "util/log.h"
40 #include "util/macros.h"
41 #include "vk_format.h"
42 #include "vk_log.h"
43 #include "vk_sampler.h"
44 
45 struct pvr_border_color_table_value {
46    uint8_t value[16];
47 } PACKED;
48 static_assert(sizeof(struct pvr_border_color_table_value) ==
49                  4 * sizeof(uint32_t),
50               "struct pvr_border_color_table_value must be 4 x u32");
51 
52 struct pvr_border_color_table_entry {
53    struct pvr_border_color_table_value values[PVR_TEX_FORMAT_COUNT * 2];
54 } PACKED;
55 
pvr_border_color_table_pack_single(struct pvr_border_color_table_value * const dst,const union pipe_color_union * const color,const struct pvr_tex_format_description * const format,const bool is_int)56 static inline void pvr_border_color_table_pack_single(
57    struct pvr_border_color_table_value *const dst,
58    const union pipe_color_union *const color,
59    const struct pvr_tex_format_description *const format,
60    const bool is_int)
61 {
62    const enum pipe_format pipe_format = is_int ? format->pipe_format_int
63                                                : format->pipe_format_float;
64 
65    if (pipe_format == PIPE_FORMAT_NONE)
66       return;
67 
68    memset(dst->value, 0, sizeof(dst->value));
69 
70    if (util_format_is_depth_or_stencil(pipe_format)) {
71       if (is_int) {
72          const uint8_t s_color[4] = {
73             color->ui[0],
74             color->ui[1],
75             color->ui[2],
76             color->ui[3],
77          };
78 
79          util_format_pack_s_8uint(pipe_format, dst->value, s_color, 1);
80       } else {
81          util_format_pack_z_float(pipe_format, dst->value, color->f, 1);
82       }
83    } else {
84       util_format_pack_rgba(pipe_format, dst->value, color, 1);
85    }
86 }
87 
pvr_border_color_table_pack_single_compressed(struct pvr_border_color_table_value * const dst,const union pipe_color_union * const color,const struct pvr_tex_format_compressed_description * const format,const struct pvr_device_info * const dev_info)88 static inline void pvr_border_color_table_pack_single_compressed(
89    struct pvr_border_color_table_value *const dst,
90    const union pipe_color_union *const color,
91    const struct pvr_tex_format_compressed_description *const format,
92    const struct pvr_device_info *const dev_info)
93 {
94    if (PVR_HAS_FEATURE(dev_info, tpu_border_colour_enhanced)) {
95       const struct pvr_tex_format_description *format_simple =
96          pvr_get_tex_format_description(format->tex_format_simple);
97 
98       pvr_border_color_table_pack_single(dst, color, format_simple, false);
99       return;
100    }
101 
102    memset(dst->value, 0, sizeof(dst->value));
103 
104    pvr_finishme("Devices without tpu_border_colour_enhanced require entries "
105                 "for compressed formats to be stored in the table "
106                 "pre-compressed.");
107 }
108 
109 static int32_t
pvr_border_color_table_alloc_entry(struct pvr_border_color_table * const table)110 pvr_border_color_table_alloc_entry(struct pvr_border_color_table *const table)
111 {
112    /* BITSET_FFS() returns a 1-indexed position or 0 if no bits are set. */
113    int32_t index = BITSET_FFS(table->unused_entries);
114    if (!index--)
115       return -1;
116 
117    BITSET_CLEAR(table->unused_entries, index);
118 
119    return index;
120 }
121 
122 static void
pvr_border_color_table_free_entry(struct pvr_border_color_table * const table,const uint32_t index)123 pvr_border_color_table_free_entry(struct pvr_border_color_table *const table,
124                                   const uint32_t index)
125 {
126    assert(pvr_border_color_table_is_index_valid(table, index));
127    BITSET_SET(table->unused_entries, index);
128 }
129 
130 static void
pvr_border_color_table_fill_entry(struct pvr_border_color_table * const table,const uint32_t index,const union pipe_color_union * const color,const bool is_int,const struct pvr_device_info * const dev_info)131 pvr_border_color_table_fill_entry(struct pvr_border_color_table *const table,
132                                   const uint32_t index,
133                                   const union pipe_color_union *const color,
134                                   const bool is_int,
135                                   const struct pvr_device_info *const dev_info)
136 {
137    struct pvr_border_color_table_entry *const entries = table->table->bo->map;
138    struct pvr_border_color_table_entry *const entry = &entries[index];
139    uint32_t tex_format = 0;
140 
141    for (; tex_format < PVR_TEX_FORMAT_COUNT; tex_format++) {
142       if (!pvr_tex_format_is_supported(tex_format))
143          continue;
144 
145       pvr_border_color_table_pack_single(
146          &entry->values[tex_format],
147          color,
148          pvr_get_tex_format_description(tex_format),
149          is_int);
150    }
151 
152    for (; tex_format < PVR_TEX_FORMAT_COUNT * 2; tex_format++) {
153       if (!pvr_tex_format_compressed_is_supported(tex_format))
154          continue;
155 
156       pvr_border_color_table_pack_single_compressed(
157          &entry->values[tex_format],
158          color,
159          pvr_get_tex_format_compressed_description(tex_format),
160          dev_info);
161    }
162 }
163 
pvr_border_color_table_init(struct pvr_border_color_table * const table,struct pvr_device * const device)164 VkResult pvr_border_color_table_init(struct pvr_border_color_table *const table,
165                                      struct pvr_device *const device)
166 {
167    const struct pvr_device_info *const dev_info = &device->pdevice->dev_info;
168    const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
169    const uint32_t table_size = sizeof(struct pvr_border_color_table_entry) *
170                                PVR_BORDER_COLOR_TABLE_NR_ENTRIES;
171 
172    VkResult result;
173 
174    /* Initialize to ones so ffs can be used to find unused entries. */
175    BITSET_ONES(table->unused_entries);
176 
177    result = pvr_bo_alloc(device,
178                          device->heaps.general_heap,
179                          table_size,
180                          cache_line_size,
181                          PVR_BO_ALLOC_FLAG_CPU_MAPPED,
182                          &table->table);
183    if (result != VK_SUCCESS)
184       goto err_out;
185 
186    BITSET_CLEAR_RANGE_INSIDE_WORD(table->unused_entries,
187                                   0,
188                                   PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES -
189                                      1);
190 
191    for (uint32_t i = 0; i < PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES; i++) {
192       const VkClearColorValue color = vk_border_color_value(i);
193       const bool is_int = vk_border_color_is_int(i);
194 
195       pvr_border_color_table_fill_entry(table,
196                                         i,
197                                         (const union pipe_color_union *)&color,
198                                         is_int,
199                                         dev_info);
200    }
201 
202    pvr_bo_cpu_unmap(device, table->table);
203 
204    return VK_SUCCESS;
205 
206 err_out:
207    return result;
208 }
209 
pvr_border_color_table_finish(struct pvr_border_color_table * const table,struct pvr_device * const device)210 void pvr_border_color_table_finish(struct pvr_border_color_table *const table,
211                                    struct pvr_device *const device)
212 {
213 #if MESA_DEBUG
214    BITSET_SET_RANGE_INSIDE_WORD(table->unused_entries,
215                                 0,
216                                 PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES - 1);
217    BITSET_NOT(table->unused_entries);
218    assert(BITSET_IS_EMPTY(table->unused_entries));
219 #endif
220 
221    pvr_bo_free(device, table->table);
222 }
223 
pvr_border_color_table_get_or_create_entry(UNUSED struct pvr_border_color_table * const table,const struct pvr_sampler * const sampler,uint32_t * const index_out)224 VkResult pvr_border_color_table_get_or_create_entry(
225    UNUSED struct pvr_border_color_table *const table,
226    const struct pvr_sampler *const sampler,
227    uint32_t *const index_out)
228 {
229    const VkBorderColor vk_type = sampler->vk.border_color;
230 
231    if (vk_type <= PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES) {
232       *index_out = vk_type;
233       return VK_SUCCESS;
234    }
235 
236    pvr_finishme("VK_EXT_custom_border_color is currently unsupported.");
237    return vk_error(sampler, VK_ERROR_EXTENSION_NOT_PRESENT);
238 }
239