Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include "formats.h"
19 : :
20 : : #define FMT(_name, num, size, ftype, bits, idx) \
21 : : (struct pl_fmt_t) { \
22 : : .name = _name, \
23 : : .type = PL_FMT_##ftype, \
24 : : .num_components = num, \
25 : : .component_depth = bits, \
26 : : .internal_size = size, \
27 : : .opaque = false, \
28 : : .texel_size = size, \
29 : : .texel_align = size, \
30 : : .host_bits = bits, \
31 : : .sample_order = idx, \
32 : : }
33 : :
34 : : #define IDX(...) {__VA_ARGS__}
35 : : #define BITS(...) {__VA_ARGS__}
36 : :
37 : : #define REGFMT(name, num, bits, type) \
38 : : FMT(name, num, (num) * (bits) / 8, type, \
39 : : BITS(bits, bits, bits, bits), \
40 : : IDX(0, 1, 2, 3))
41 : :
42 : : #define EMUFMT(_name, in, en, ib, eb, ftype) \
43 : : (struct pl_fmt_t) { \
44 : : .name = _name, \
45 : : .type = PL_FMT_##ftype, \
46 : : .num_components = en, \
47 : : .component_depth = BITS(ib, ib, ib, ib),\
48 : : .internal_size = (in) * (ib) / 8, \
49 : : .opaque = false, \
50 : : .emulated = true, \
51 : : .texel_size = (en) * (eb) / 8, \
52 : : .texel_align = (eb) / 8, \
53 : : .host_bits = BITS(eb, eb, eb, eb),\
54 : : .sample_order = IDX(0, 1, 2, 3), \
55 : : }
56 : :
57 : : #define PACKED16FMT(_name, num, b) \
58 : : (struct pl_fmt_t) { \
59 : : .name = _name, \
60 : : .type = PL_FMT_UNORM, \
61 : : .num_components = num, \
62 : : .component_depth = BITS(b, b, b, b), \
63 : : .internal_size = (num) * 2, \
64 : : .texel_size = (num) * 2, \
65 : : .texel_align = (num) * 2, \
66 : : .host_bits = BITS(16, 16, 16, 16),\
67 : : .sample_order = IDX(0, 1, 2, 3), \
68 : : }
69 : :
70 : : #define PLANARFMT(_name, planes, size, bits) \
71 : : (struct pl_fmt_t) { \
72 : : .name = _name, \
73 : : .type = PL_FMT_UNORM, \
74 : : .num_planes = planes, \
75 : : .num_components = 3, \
76 : : .component_depth = {bits, bits, bits}, \
77 : : .internal_size = size, \
78 : : .opaque = true, \
79 : : }
80 : :
81 : : static const struct vk_format rgb8e = {
82 : : .tfmt = VK_FORMAT_R8G8B8A8_UNORM,
83 : : .bfmt = VK_FORMAT_R8G8B8_UNORM,
84 : : .icomps = 4,
85 : : .fmt = EMUFMT("rgb8", 4, 3, 8, 8, UNORM),
86 : : };
87 : :
88 : : static const struct vk_format rgb16e = {
89 : : .tfmt = VK_FORMAT_R16G16B16A16_UNORM,
90 : : .bfmt = VK_FORMAT_R16G16B16_UNORM,
91 : : .icomps = 4,
92 : : .fmt = EMUFMT("rgb16", 4, 3, 16, 16, UNORM),
93 : : };
94 : :
95 : : static const struct vk_format vk_formats[] = {
96 : : // Regular, byte-aligned integer formats
97 : : {VK_FORMAT_R8_UNORM, REGFMT("r8", 1, 8, UNORM)},
98 : : {VK_FORMAT_R8G8_UNORM, REGFMT("rg8", 2, 8, UNORM)},
99 : : {VK_FORMAT_R8G8B8_UNORM, REGFMT("rgb8", 3, 8, UNORM), .emufmt = &rgb8e},
100 : : {VK_FORMAT_R8G8B8A8_UNORM, REGFMT("rgba8", 4, 8, UNORM)},
101 : : {VK_FORMAT_R16_UNORM, REGFMT("r16", 1, 16, UNORM)},
102 : : {VK_FORMAT_R16G16_UNORM, REGFMT("rg16", 2, 16, UNORM)},
103 : : {VK_FORMAT_R16G16B16_UNORM, REGFMT("rgb16", 3, 16, UNORM), .emufmt = &rgb16e},
104 : : {VK_FORMAT_R16G16B16A16_UNORM, REGFMT("rgba16", 4, 16, UNORM)},
105 : :
106 : : {VK_FORMAT_R8_SNORM, REGFMT("r8s", 1, 8, SNORM)},
107 : : {VK_FORMAT_R8G8_SNORM, REGFMT("rg8s", 2, 8, SNORM)},
108 : : {VK_FORMAT_R8G8B8_SNORM, REGFMT("rgb8s", 3, 8, SNORM)},
109 : : {VK_FORMAT_R8G8B8A8_SNORM, REGFMT("rgba8s", 4, 8, SNORM)},
110 : : {VK_FORMAT_R16_SNORM, REGFMT("r16s", 1, 16, SNORM)},
111 : : {VK_FORMAT_R16G16_SNORM, REGFMT("rg16s", 2, 16, SNORM)},
112 : : {VK_FORMAT_R16G16B16_SNORM, REGFMT("rgb16s", 3, 16, SNORM)},
113 : : {VK_FORMAT_R16G16B16A16_SNORM, REGFMT("rgba16s", 4, 16, SNORM)},
114 : :
115 : : // Float formats (native formats: hf = half float, df = double float)
116 : : {VK_FORMAT_R16_SFLOAT, REGFMT("r16hf", 1, 16, FLOAT)},
117 : : {VK_FORMAT_R16G16_SFLOAT, REGFMT("rg16hf", 2, 16, FLOAT)},
118 : : {VK_FORMAT_R16G16B16_SFLOAT, REGFMT("rgb16hf", 3, 16, FLOAT)},
119 : : {VK_FORMAT_R16G16B16A16_SFLOAT, REGFMT("rgba16hf", 4, 16, FLOAT)},
120 : : {VK_FORMAT_R32_SFLOAT, REGFMT("r32f", 1, 32, FLOAT)},
121 : : {VK_FORMAT_R32G32_SFLOAT, REGFMT("rg32f", 2, 32, FLOAT)},
122 : : {VK_FORMAT_R32G32B32_SFLOAT, REGFMT("rgb32f", 3, 32, FLOAT)},
123 : : {VK_FORMAT_R32G32B32A32_SFLOAT, REGFMT("rgba32f", 4, 32, FLOAT)},
124 : :
125 : : // Float formats (emulated upload/download)
126 : : {VK_FORMAT_R16_SFLOAT, EMUFMT("r16f", 1, 1, 16, 32, FLOAT)},
127 : : {VK_FORMAT_R16G16_SFLOAT, EMUFMT("rg16f", 2, 2, 16, 32, FLOAT)},
128 : : {VK_FORMAT_R16G16B16_SFLOAT, EMUFMT("rgb16f", 3, 3, 16, 32, FLOAT)},
129 : : {VK_FORMAT_R16G16B16A16_SFLOAT, EMUFMT("rgba16f", 4, 4, 16, 32, FLOAT)},
130 : :
131 : : // Integer-sampled formats
132 : : {VK_FORMAT_R8_UINT, REGFMT("r8u", 1, 8, UINT)},
133 : : {VK_FORMAT_R8G8_UINT, REGFMT("rg8u", 2, 8, UINT)},
134 : : {VK_FORMAT_R8G8B8_UINT, REGFMT("rgb8u", 3, 8, UINT)},
135 : : {VK_FORMAT_R8G8B8A8_UINT, REGFMT("rgba8u", 4, 8, UINT)},
136 : : {VK_FORMAT_R16_UINT, REGFMT("r16u", 1, 16, UINT)},
137 : : {VK_FORMAT_R16G16_UINT, REGFMT("rg16u", 2, 16, UINT)},
138 : : {VK_FORMAT_R16G16B16_UINT, REGFMT("rgb16u", 3, 16, UINT)},
139 : : {VK_FORMAT_R16G16B16A16_UINT, REGFMT("rgba16u", 4, 16, UINT)},
140 : : {VK_FORMAT_R32_UINT, REGFMT("r32u", 1, 32, UINT)},
141 : : {VK_FORMAT_R32G32_UINT, REGFMT("rg32u", 2, 32, UINT)},
142 : : {VK_FORMAT_R32G32B32_UINT, REGFMT("rgb32u", 3, 32, UINT)},
143 : : {VK_FORMAT_R32G32B32A32_UINT, REGFMT("rgba32u", 4, 32, UINT)},
144 : :
145 : : {VK_FORMAT_R8_SINT, REGFMT("r8i", 1, 8, SINT)},
146 : : {VK_FORMAT_R8G8_SINT, REGFMT("rg8i", 2, 8, SINT)},
147 : : {VK_FORMAT_R8G8B8_SINT, REGFMT("rgb8i", 3, 8, SINT)},
148 : : {VK_FORMAT_R8G8B8A8_SINT, REGFMT("rgba8i", 4, 8, SINT)},
149 : : {VK_FORMAT_R16_SINT, REGFMT("r16i", 1, 16, SINT)},
150 : : {VK_FORMAT_R16G16_SINT, REGFMT("rg16i", 2, 16, SINT)},
151 : : {VK_FORMAT_R16G16B16_SINT, REGFMT("rgb16i", 3, 16, SINT)},
152 : : {VK_FORMAT_R16G16B16A16_SINT, REGFMT("rgba16i", 4, 16, SINT)},
153 : : {VK_FORMAT_R32_SINT, REGFMT("r32i", 1, 32, SINT)},
154 : : {VK_FORMAT_R32G32_SINT, REGFMT("rg32i", 2, 32, SINT)},
155 : : {VK_FORMAT_R32G32B32_SINT, REGFMT("rgb32i", 3, 32, SINT)},
156 : : {VK_FORMAT_R32G32B32A32_SINT, REGFMT("rgba32i", 4, 32, SINT)},
157 : :
158 : : // "Swapped" component order formats
159 : : {VK_FORMAT_B8G8R8_UNORM, FMT("bgr8", 3, 3, UNORM, BITS(8, 8, 8), IDX(2, 1, 0))},
160 : : {VK_FORMAT_B8G8R8A8_UNORM, FMT("bgra8", 4, 4, UNORM, BITS(8, 8, 8, 8), IDX(2, 1, 0, 3))},
161 : :
162 : : {VK_FORMAT_B8G8R8_UINT, FMT("bgr8u", 3, 3, UINT, BITS(8, 8, 8), IDX(2, 1, 0))},
163 : : {VK_FORMAT_B8G8R8A8_UINT, FMT("bgra8u", 4, 4, UINT, BITS(8, 8, 8, 8), IDX(2, 1, 0, 3))},
164 : :
165 : : {VK_FORMAT_B8G8R8_SINT, FMT("bgr8i", 3, 3, SINT, BITS(8, 8, 8), IDX(2, 1, 0))},
166 : : {VK_FORMAT_B8G8R8A8_SINT, FMT("bgra8i", 4, 4, SINT, BITS(8, 8, 8, 8), IDX(2, 1, 0, 3))},
167 : :
168 : : // "Packed" integer formats
169 : : //
170 : : // Note: These have the component order reversed from what the vulkan name
171 : : // implies, because we order our IDX from LSB to MSB (consistent with the
172 : : // usual ordering from lowest byte to highest byte, on little endian
173 : : // platforms), but Vulkan names them from MSB to LSB.
174 : : {VK_FORMAT_R4G4_UNORM_PACK8, FMT("gr4", 2, 1, UNORM, BITS(4, 4), IDX(1, 0))},
175 : : {VK_FORMAT_B4G4R4A4_UNORM_PACK16, FMT("argb4", 4, 2, UNORM, BITS(4, 4, 4, 4), IDX(3, 0, 1, 2))},
176 : : {VK_FORMAT_R4G4B4A4_UNORM_PACK16, FMT("abgr4", 4, 2, UNORM, BITS(4, 4, 4, 4), IDX(3, 2, 1, 0))},
177 : :
178 : : {VK_FORMAT_R5G6B5_UNORM_PACK16, FMT("bgr565", 3, 2, UNORM, BITS(5, 6, 5), IDX(2, 1, 0))},
179 : : {VK_FORMAT_B5G6R5_UNORM_PACK16, FMT("rgb565", 3, 2, UNORM, BITS(5, 6, 5), IDX(0, 1, 2))},
180 : :
181 : : {VK_FORMAT_R5G5B5A1_UNORM_PACK16, FMT("a1bgr5", 4, 2, UNORM, BITS(1, 5, 5, 5), IDX(3, 2, 1, 0))},
182 : : {VK_FORMAT_B5G5R5A1_UNORM_PACK16, FMT("a1rgb5", 4, 2, UNORM, BITS(1, 5, 5, 5), IDX(3, 0, 1, 2))},
183 : : {VK_FORMAT_A1R5G5B5_UNORM_PACK16, FMT("bgr5a1", 4, 2, UNORM, BITS(5, 5, 5, 1), IDX(2, 1, 0, 3))},
184 : :
185 : : {VK_FORMAT_A2B10G10R10_UNORM_PACK32, FMT("rgb10a2", 4, 4, UNORM, BITS(10, 10, 10, 2), IDX(0, 1, 2, 3))},
186 : : {VK_FORMAT_A2R10G10B10_UNORM_PACK32, FMT("bgr10a2", 4, 4, UNORM, BITS(10, 10, 10, 2), IDX(2, 1, 0, 3))},
187 : : {VK_FORMAT_A2B10G10R10_SNORM_PACK32, FMT("rgb10a2s", 4, 4, SNORM, BITS(10, 10, 10, 2), IDX(0, 1, 2, 3))},
188 : : {VK_FORMAT_A2R10G10B10_SNORM_PACK32, FMT("bgr10a2s", 4, 4, SNORM, BITS(10, 10, 10, 2), IDX(2, 1, 0, 3))},
189 : : {VK_FORMAT_A2B10G10R10_UINT_PACK32, FMT("rgb10a2u", 4, 4, UINT, BITS(10, 10, 10, 2), IDX(0, 1, 2, 3))},
190 : : {VK_FORMAT_A2R10G10B10_UINT_PACK32, FMT("bgr10a2u", 4, 4, UINT, BITS(10, 10, 10, 2), IDX(2, 1, 0, 3))},
191 : : {VK_FORMAT_A2B10G10R10_SINT_PACK32, FMT("rgb10a2i", 4, 4, SINT, BITS(10, 10, 10, 2), IDX(0, 1, 2, 3))},
192 : : {VK_FORMAT_A2R10G10B10_SINT_PACK32, FMT("bgr10a2i", 4, 4, SINT, BITS(10, 10, 10, 2), IDX(2, 1, 0, 3))},
193 : :
194 : :
195 : : // Packed 16 bit formats
196 : : {VK_FORMAT_R10X6_UNORM_PACK16, PACKED16FMT("rx10", 1, 10)},
197 : : {VK_FORMAT_R10X6G10X6_UNORM_2PACK16, PACKED16FMT("rxgx10", 2, 10)},
198 : : {VK_FORMAT_R12X4_UNORM_PACK16, PACKED16FMT("rx12", 1, 12)},
199 : : {VK_FORMAT_R12X4G12X4_UNORM_2PACK16, PACKED16FMT("rxgx12", 2, 12)},
200 : :
201 : : // FIXME: enabling these requires VK_EXT_rgba10x6_formats or equivalent
202 : : // {VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, PACKED16FMT("rxgxbxax10", 4, 10)},
203 : : // {VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, PACKED16FMT("rxgxbxax12", 4, 12)},
204 : :
205 : : // Planar formats
206 : : {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, PLANARFMT("g8_b8_r8_420", 3, 12, 8),
207 : : .pfmt = {
208 : : {VK_FORMAT_R8_UNORM},
209 : : {VK_FORMAT_R8_UNORM, .sx = 1, .sy = 1},
210 : : {VK_FORMAT_R8_UNORM, .sx = 1, .sy = 1},
211 : : },
212 : : },
213 : : {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, PLANARFMT("g8_b8_r8_422", 3, 16, 8),
214 : : .pfmt = {
215 : : {VK_FORMAT_R8_UNORM},
216 : : {VK_FORMAT_R8_UNORM, .sx = 1},
217 : : {VK_FORMAT_R8_UNORM, .sx = 1},
218 : : },
219 : : },
220 : : {VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, PLANARFMT("g8_b8_r8_444", 3, 24, 8),
221 : : .pfmt = {
222 : : {VK_FORMAT_R8_UNORM},
223 : : {VK_FORMAT_R8_UNORM},
224 : : {VK_FORMAT_R8_UNORM},
225 : : },
226 : : },
227 : :
228 : : {VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, PLANARFMT("g16_b16_r16_420", 3, 24, 16),
229 : : .pfmt = {
230 : : {VK_FORMAT_R16_UNORM},
231 : : {VK_FORMAT_R16_UNORM, .sx = 1, .sy = 1},
232 : : {VK_FORMAT_R16_UNORM, .sx = 1, .sy = 1},
233 : : },
234 : : },
235 : : {VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, PLANARFMT("g16_b16_r16_422", 3, 32, 16),
236 : : .pfmt = {
237 : : {VK_FORMAT_R16_UNORM},
238 : : {VK_FORMAT_R16_UNORM, .sx = 1},
239 : : {VK_FORMAT_R16_UNORM, .sx = 1},
240 : : },
241 : : },
242 : : {VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, PLANARFMT("g16_b16_r16_444", 3, 48, 16),
243 : : .pfmt = {
244 : : {VK_FORMAT_R16_UNORM},
245 : : {VK_FORMAT_R16_UNORM},
246 : : {VK_FORMAT_R16_UNORM},
247 : : },
248 : : },
249 : :
250 : : {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, PLANARFMT("gx10_bx10_rx10_420", 3, 24, 10),
251 : : .pfmt = {
252 : : {VK_FORMAT_R10X6_UNORM_PACK16},
253 : : {VK_FORMAT_R10X6_UNORM_PACK16, .sx = 1, .sy = 1},
254 : : {VK_FORMAT_R10X6_UNORM_PACK16, .sx = 1, .sy = 1},
255 : : },
256 : : },
257 : : {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, PLANARFMT("gx10_bx10_rx10_422", 3, 32, 10),
258 : : .pfmt = {
259 : : {VK_FORMAT_R10X6_UNORM_PACK16},
260 : : {VK_FORMAT_R10X6_UNORM_PACK16, .sx = 1},
261 : : {VK_FORMAT_R10X6_UNORM_PACK16, .sx = 1},
262 : : },
263 : : },
264 : : {VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, PLANARFMT("gx10_bx10_rx10_444", 3, 48, 10),
265 : : .pfmt = {
266 : : {VK_FORMAT_R10X6_UNORM_PACK16},
267 : : {VK_FORMAT_R10X6_UNORM_PACK16},
268 : : {VK_FORMAT_R10X6_UNORM_PACK16},
269 : : },
270 : : },
271 : :
272 : : {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, PLANARFMT("gx12_bx12_rx12_420", 3, 24, 12),
273 : : .pfmt = {
274 : : {VK_FORMAT_R12X4_UNORM_PACK16},
275 : : {VK_FORMAT_R12X4_UNORM_PACK16, .sx = 1, .sy = 1},
276 : : {VK_FORMAT_R12X4_UNORM_PACK16, .sx = 1, .sy = 1},
277 : : },
278 : : },
279 : : {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, PLANARFMT("gx12_bx12_rx12_422", 3, 32, 12),
280 : : .pfmt = {
281 : : {VK_FORMAT_R12X4_UNORM_PACK16},
282 : : {VK_FORMAT_R12X4_UNORM_PACK16, .sx = 1},
283 : : {VK_FORMAT_R12X4_UNORM_PACK16, .sx = 1},
284 : : },
285 : : },
286 : : {VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, PLANARFMT("gx12_bx12_rx12_444", 3, 48, 12),
287 : : .pfmt = {
288 : : {VK_FORMAT_R12X4_UNORM_PACK16},
289 : : {VK_FORMAT_R12X4_UNORM_PACK16},
290 : : {VK_FORMAT_R12X4_UNORM_PACK16},
291 : : },
292 : : },
293 : :
294 : : {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, PLANARFMT("g8_br8_420", 2, 12, 8),
295 : : .pfmt = {
296 : : {VK_FORMAT_R8_UNORM},
297 : : {VK_FORMAT_R8G8_UNORM, .sx = 1, .sy = 1},
298 : : },
299 : : },
300 : : {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, PLANARFMT("g8_br8_422", 2, 16, 8),
301 : : .pfmt = {
302 : : {VK_FORMAT_R8_UNORM},
303 : : {VK_FORMAT_R8G8_UNORM, .sx = 1},
304 : : },
305 : : },
306 : : {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, PLANARFMT("g8_br8_444", 2, 24, 8),
307 : : .min_ver = VK_API_VERSION_1_3,
308 : : .pfmt = {
309 : : {VK_FORMAT_R8_UNORM},
310 : : {VK_FORMAT_R8G8_UNORM},
311 : : },
312 : : },
313 : :
314 : : {VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, PLANARFMT("g16_br16_420", 2, 24, 16),
315 : : .pfmt = {
316 : : {VK_FORMAT_R16_UNORM},
317 : : {VK_FORMAT_R16G16_UNORM, .sx = 1, .sy = 1},
318 : : },
319 : : },
320 : : {VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, PLANARFMT("g16_br16_422", 2, 32, 16),
321 : : .pfmt = {
322 : : {VK_FORMAT_R16_UNORM},
323 : : {VK_FORMAT_R16G16_UNORM, .sx = 1},
324 : : },
325 : : },
326 : : {VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, PLANARFMT("g16_br16_444", 2, 48, 16),
327 : : .min_ver = VK_API_VERSION_1_3,
328 : : .pfmt = {
329 : : {VK_FORMAT_R16_UNORM},
330 : : {VK_FORMAT_R16G16_UNORM},
331 : : },
332 : : },
333 : :
334 : : {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, PLANARFMT("gx10_bxrx10_420", 2, 24, 10),
335 : : .pfmt = {
336 : : {VK_FORMAT_R10X6_UNORM_PACK16},
337 : : {VK_FORMAT_R10X6G10X6_UNORM_2PACK16, .sx = 1, .sy = 1},
338 : : },
339 : : },
340 : : {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, PLANARFMT("gx10_bxrx10_422", 2, 32, 10),
341 : : .pfmt = {
342 : : {VK_FORMAT_R10X6_UNORM_PACK16},
343 : : {VK_FORMAT_R10X6G10X6_UNORM_2PACK16, .sx = 1},
344 : : },
345 : : },
346 : : {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, PLANARFMT("gx10_bxrx10_444", 2, 48, 10),
347 : : .min_ver = VK_API_VERSION_1_3,
348 : : .pfmt = {
349 : : {VK_FORMAT_R10X6_UNORM_PACK16},
350 : : {VK_FORMAT_R10X6G10X6_UNORM_2PACK16},
351 : : },
352 : : },
353 : :
354 : : {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, PLANARFMT("gx12_bxrx12_420", 2, 24, 12),
355 : : .pfmt = {
356 : : {VK_FORMAT_R12X4_UNORM_PACK16},
357 : : {VK_FORMAT_R12X4G12X4_UNORM_2PACK16, .sx = 1, .sy = 1},
358 : : },
359 : : },
360 : : {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, PLANARFMT("gx12_bxrx12_422", 2, 32, 12),
361 : : .pfmt = {
362 : : {VK_FORMAT_R12X4_UNORM_PACK16},
363 : : {VK_FORMAT_R12X4G12X4_UNORM_2PACK16, .sx = 1},
364 : : },
365 : : },
366 : : {VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, PLANARFMT("gx12_bxrx12_444", 2, 48, 12),
367 : : .min_ver = VK_API_VERSION_1_3,
368 : : .pfmt = {
369 : : {VK_FORMAT_R12X4_UNORM_PACK16},
370 : : {VK_FORMAT_R12X4G12X4_UNORM_2PACK16},
371 : : },
372 : : },
373 : :
374 : : {0}
375 : : };
376 : :
377 : : #undef BITS
378 : : #undef IDX
379 : : #undef REGFMT
380 : : #undef FMT
381 : :
382 : 3 : void vk_setup_formats(struct pl_gpu_t *gpu)
383 : : {
384 : 3 : struct pl_vk *p = PL_PRIV(gpu);
385 : 3 : struct vk_ctx *vk = p->vk;
386 : : PL_ARRAY(pl_fmt) formats = {0};
387 : :
388 : : // Texture format emulation requires at least support for texel buffers
389 [ + - - + ]: 3 : bool has_emu = gpu->glsl.compute && gpu->limits.max_buffer_texels;
390 : :
391 [ + + ]: 309 : for (const struct vk_format *pvk_fmt = vk_formats; pvk_fmt->tfmt; pvk_fmt++) {
392 : : const struct vk_format *vk_fmt = pvk_fmt;
393 : :
394 : : // Skip formats that require a too new version of Vulkan
395 [ - + ]: 306 : if (vk_fmt->min_ver > vk->api_ver)
396 : 0 : continue;
397 : :
398 : : // Skip formats with innately emulated representation if unsupported
399 [ + + - + ]: 306 : if (vk_fmt->fmt.emulated && !has_emu)
400 : 0 : continue;
401 : :
402 : : // Suppress some errors/warnings spit out by the format probing code
403 : 306 : pl_log_level_cap(vk->log, PL_LOG_INFO);
404 : :
405 : 306 : bool has_drm_mods = vk->GetImageDrmFormatModifierPropertiesEXT;
406 : 306 : VkDrmFormatModifierPropertiesEXT modifiers[16] = {0};
407 : 306 : VkDrmFormatModifierPropertiesListEXT drm_props = {
408 : : .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
409 : : .drmFormatModifierCount = PL_ARRAY_SIZE(modifiers),
410 : : .pDrmFormatModifierProperties = modifiers,
411 : : };
412 : :
413 : 612 : VkFormatProperties2KHR prop2 = {
414 : : .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
415 [ - + ]: 306 : .pNext = has_drm_mods ? &drm_props : NULL,
416 : : };
417 : :
418 : 306 : vk->GetPhysicalDeviceFormatProperties2KHR(vk->physd, vk_fmt->tfmt, &prop2);
419 : :
420 : : // If wholly unsupported, try falling back to the emulation formats
421 : : // for texture operations
422 : : VkFormatProperties *prop = &prop2.formatProperties;
423 [ + - + + : 306 : while (has_emu && !prop->optimalTilingFeatures && vk_fmt->emufmt) {
- + ]
424 : : vk_fmt = vk_fmt->emufmt;
425 : 0 : vk->GetPhysicalDeviceFormatProperties2KHR(vk->physd, vk_fmt->tfmt, &prop2);
426 : : }
427 : :
428 : 306 : VkFormatFeatureFlags texflags = prop->optimalTilingFeatures;
429 : 306 : VkFormatFeatureFlags bufflags = prop->bufferFeatures;
430 [ + + ]: 306 : if (vk_fmt->fmt.emulated) {
431 : : // Emulated formats might have a different buffer representation
432 : : // than their texture representation. If they don't, assume their
433 : : // buffer representation is nonsensical (e.g. r16f)
434 [ - + ]: 12 : if (vk_fmt->bfmt) {
435 : 0 : vk->GetPhysicalDeviceFormatProperties(vk->physd, vk_fmt->bfmt, prop);
436 : 0 : bufflags = prop->bufferFeatures;
437 : : } else {
438 : : bufflags = 0;
439 : : }
440 [ + + ]: 294 : } else if (vk_fmt->fmt.num_planes) {
441 : : // Planar textures cannot be used directly
442 : : texflags = bufflags = 0;
443 : : }
444 : :
445 : 306 : pl_log_level_cap(vk->log, PL_LOG_NONE);
446 : :
447 : 306 : struct pl_fmt_t *fmt = pl_alloc_obj(gpu, fmt, struct pl_fmt_vk);
448 : 306 : struct pl_fmt_vk *fmtp = PL_PRIV(fmt);
449 : 306 : *fmt = vk_fmt->fmt;
450 : 306 : *fmtp = (struct pl_fmt_vk) {
451 : : .vk_fmt = vk_fmt
452 : : };
453 : :
454 : : // Always set the signature to the actual texture format, so we can use
455 : : // it to guarantee renderpass compatibility.
456 : 306 : fmt->signature = (uint64_t) vk_fmt->tfmt;
457 : :
458 : : // For sanity, clear the superfluous fields
459 [ + + ]: 663 : for (int i = fmt->num_components; i < 4; i++) {
460 : 357 : fmt->component_depth[i] = 0;
461 : 357 : fmt->sample_order[i] = 0;
462 : 357 : fmt->host_bits[i] = 0;
463 : : }
464 : :
465 : : // We can set this universally
466 : 306 : fmt->fourcc = pl_fmt_fourcc(fmt);
467 : :
468 [ + - ]: 306 : if (has_drm_mods) {
469 : :
470 [ - + ]: 306 : if (drm_props.drmFormatModifierCount == PL_ARRAY_SIZE(modifiers)) {
471 : 0 : PL_WARN(gpu, "DRM modifier list for format %s possibly truncated",
472 : : fmt->name);
473 : : }
474 : :
475 : : // Query the list of supported DRM modifiers from the driver
476 : : PL_ARRAY(uint64_t) modlist = {0};
477 [ + + ]: 564 : for (int i = 0; i < drm_props.drmFormatModifierCount; i++) {
478 [ + + ]: 309 : if (modifiers[i].drmFormatModifierPlaneCount > 1) {
479 : 51 : PL_TRACE(gpu, "Ignoring format modifier %s of "
480 : : "format %s because its plane count %d > 1",
481 : : PRINT_DRM_MOD(modifiers[i].drmFormatModifier),
482 : : fmt->name, modifiers[i].drmFormatModifierPlaneCount);
483 : : continue;
484 : : }
485 : :
486 : : // Only warn about texture format features relevant to us
487 : : const VkFormatFeatureFlags flag_mask =
488 : : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT |
489 : : VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
490 : : VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
491 : : VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
492 : : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
493 : : VK_FORMAT_FEATURE_BLIT_SRC_BIT |
494 : : VK_FORMAT_FEATURE_BLIT_DST_BIT;
495 : :
496 : :
497 : 207 : VkFormatFeatureFlags flags = modifiers[i].drmFormatModifierTilingFeatures;
498 [ - + ]: 207 : if ((flags & flag_mask) != (texflags & flag_mask)) {
499 : 0 : PL_DEBUG(gpu, "DRM format modifier %s of format %s "
500 : : "supports fewer caps (0x%"PRIx32") than optimal tiling "
501 : : "(0x%"PRIx32"), may result in limited capability!",
502 : : PRINT_DRM_MOD(modifiers[i].drmFormatModifier),
503 : : fmt->name, flags, texflags);
504 : : }
505 : :
506 [ + + - + : 207 : PL_ARRAY_APPEND(fmt, modlist, modifiers[i].drmFormatModifier);
- + ]
507 : : }
508 : :
509 : 306 : fmt->num_modifiers = modlist.num;
510 : 306 : fmt->modifiers = modlist.elem;
511 : :
512 [ # # ]: 0 : } else if (gpu->export_caps.tex & PL_HANDLE_DMA_BUF) {
513 : :
514 : : // Hard-code a list of static mods that we're likely to support
515 : : static const uint64_t static_mods[2] = {
516 : : DRM_FORMAT_MOD_INVALID,
517 : : DRM_FORMAT_MOD_LINEAR,
518 : : };
519 : :
520 : 0 : fmt->num_modifiers = PL_ARRAY_SIZE(static_mods);
521 : 0 : fmt->modifiers = static_mods;
522 : :
523 : : }
524 : :
525 : 306 : struct { VkFormatFeatureFlags flags; enum pl_fmt_caps caps; } bufbits[] = {
526 : : {VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT, PL_FMT_CAP_VERTEX},
527 : : {VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT, PL_FMT_CAP_TEXEL_UNIFORM},
528 : : {VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, PL_FMT_CAP_TEXEL_STORAGE},
529 : : };
530 : :
531 [ + + ]: 1224 : for (int i = 0; i < PL_ARRAY_SIZE(bufbits); i++) {
532 [ + + ]: 918 : if ((bufflags & bufbits[i].flags) == bufbits[i].flags)
533 : 456 : fmt->caps |= bufbits[i].caps;
534 : : }
535 : :
536 [ + + ]: 306 : if (fmt->caps) {
537 : 186 : fmt->glsl_type = pl_var_glsl_type_name(pl_var_from_fmt(fmt, ""));
538 [ - + ]: 186 : pl_assert(fmt->glsl_type);
539 : : }
540 : :
541 : 306 : struct { VkFormatFeatureFlags flags; enum pl_fmt_caps caps; } bits[] = {
542 : : {VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT, PL_FMT_CAP_BLENDABLE},
543 : : {VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, PL_FMT_CAP_LINEAR},
544 : : {VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, PL_FMT_CAP_SAMPLEABLE},
545 : : {VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, PL_FMT_CAP_STORABLE},
546 : : {VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, PL_FMT_CAP_RENDERABLE},
547 : :
548 : : // We don't distinguish between the two blit modes for pl_fmt_caps
549 : : {VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT,
550 : : PL_FMT_CAP_BLITTABLE},
551 : : };
552 : :
553 [ + + ]: 2142 : for (int i = 0; i < PL_ARRAY_SIZE(bits); i++) {
554 [ + + ]: 1836 : if ((texflags & bits[i].flags) == bits[i].flags)
555 : 822 : fmt->caps |= bits[i].caps;
556 : : }
557 : :
558 : : // For blit emulation via compute shaders
559 [ - + ]: 306 : if (!(fmt->caps & PL_FMT_CAP_BLITTABLE) && (fmt->caps & PL_FMT_CAP_STORABLE)) {
560 : 0 : fmt->caps |= PL_FMT_CAP_BLITTABLE;
561 : 0 : fmtp->blit_emulated = true;
562 : : }
563 : :
564 : : // This is technically supported for all textures, but the semantics
565 : : // of pl_gpu require it only be listed for non-opaque ones
566 [ + + ]: 306 : if (!fmt->opaque)
567 : 234 : fmt->caps |= PL_FMT_CAP_HOST_READABLE;
568 : :
569 : : // Vulkan requires a minimum GLSL version that supports textureGather()
570 [ + + ]: 306 : if (fmt->caps & PL_FMT_CAP_SAMPLEABLE)
571 : 183 : fmt->gatherable = true;
572 : :
573 : : // Disable implied capabilities where the dependencies are unavailable
574 : : enum pl_fmt_caps storable = PL_FMT_CAP_STORABLE | PL_FMT_CAP_TEXEL_STORAGE;
575 [ + + ]: 306 : if (!(fmt->caps & PL_FMT_CAP_SAMPLEABLE))
576 : 123 : fmt->caps &= ~PL_FMT_CAP_LINEAR;
577 [ - + ]: 306 : if (!gpu->glsl.compute)
578 : 0 : fmt->caps &= ~storable;
579 : :
580 [ - + ]: 306 : bool has_nofmt = vk->features.features.shaderStorageImageReadWithoutFormat &&
581 [ # # ]: 0 : vk->features.features.shaderStorageImageWriteWithoutFormat;
582 : :
583 [ + + ]: 306 : if (fmt->caps & storable) {
584 [ + - ]: 138 : int real_comps = PL_DEF(vk_fmt->icomps, fmt->num_components);
585 : 138 : fmt->glsl_format = pl_fmt_glsl_format(fmt, real_comps);
586 [ + + + - ]: 138 : if (!fmt->glsl_format && !has_nofmt) {
587 : 9 : PL_DEBUG(gpu, "Storable format '%s' has no matching GLSL "
588 : : "format qualifier but read/write without format "
589 : : "is not supported.. disabling", fmt->name);
590 : 9 : fmt->caps &= ~storable;
591 : : }
592 : : }
593 : :
594 [ + + ]: 306 : if (fmt->caps & storable)
595 : 129 : fmt->caps |= PL_FMT_CAP_READWRITE;
596 : :
597 : : // Pick sub-plane formats for planar formats
598 [ + + ]: 486 : for (int n = 0; n < fmt->num_planes; n++) {
599 [ + - ]: 7146 : for (int i = 0; i < formats.num; i++) {
600 [ + + ]: 7146 : if (formats.elem[i]->signature == vk_fmt->pfmt[n].fmt) {
601 : 180 : fmt->planes[n].format = formats.elem[i];
602 : 180 : fmt->planes[n].shift_x = vk_fmt->pfmt[n].sx;
603 : 180 : fmt->planes[n].shift_y = vk_fmt->pfmt[n].sy;
604 : 180 : break;
605 : : }
606 : : }
607 : :
608 [ - + ]: 180 : pl_assert(fmt->planes[n].format);
609 : : }
610 : :
611 [ + + + + : 306 : PL_ARRAY_APPEND(gpu, formats, fmt);
- + ]
612 : : }
613 : :
614 : 3 : gpu->formats = formats.elem;
615 : 3 : gpu->num_formats = formats.num;
616 : 3 : }
|