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