1 | /* -*- tab-width: 4; -*- */ |
2 | /* vi: set sw=2 ts=4 expandtab: */ |
3 | |
4 | /* Copyright 2019-2020 The Khronos Group Inc. |
5 | * SPDX-License-Identifier: Apache-2.0 |
6 | */ |
7 | |
8 | /** |
9 | * @file |
10 | * @~English |
11 | * @brief Utilities for creating data format descriptors. |
12 | */ |
13 | |
14 | /* |
15 | * Author: Andrew Garrard |
16 | */ |
17 | |
18 | #include <stdlib.h> |
19 | #include <KHR/khr_df.h> |
20 | |
21 | #include "dfd.h" |
22 | |
23 | typedef enum { i_COLOR, i_NON_COLOR } channels_infotype; |
24 | |
25 | static uint32_t *(int numSamples, int bytes, int suffix, |
26 | channels_infotype infotype) |
27 | { |
28 | uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) * |
29 | (1 + KHR_DF_WORD_SAMPLESTART + |
30 | numSamples * KHR_DF_WORD_SAMPLEWORDS)); |
31 | uint32_t* BDFD = DFD+1; |
32 | DFD[0] = sizeof(uint32_t) * |
33 | (1 + KHR_DF_WORD_SAMPLESTART + |
34 | numSamples * KHR_DF_WORD_SAMPLEWORDS); |
35 | BDFD[KHR_DF_WORD_VENDORID] = |
36 | (KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) | |
37 | (KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE); |
38 | BDFD[KHR_DF_WORD_VERSIONNUMBER] = |
39 | (KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) | |
40 | (((uint32_t)sizeof(uint32_t) * |
41 | (KHR_DF_WORD_SAMPLESTART + |
42 | numSamples * KHR_DF_WORD_SAMPLEWORDS) |
43 | << KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE)); |
44 | BDFD[KHR_DF_WORD_MODEL] = |
45 | ((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) | /* Only supported model */ |
46 | (KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS)); |
47 | if (infotype == i_COLOR) { |
48 | BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES; /* Assumed */ |
49 | } else { |
50 | BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_UNSPECIFIED << KHR_DF_SHIFT_PRIMARIES; |
51 | } |
52 | if (suffix == s_SRGB) { |
53 | BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER; |
54 | } else { |
55 | BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER; |
56 | } |
57 | BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 0; /* Only 1x1x1x1 texel blocks supported */ |
58 | BDFD[KHR_DF_WORD_BYTESPLANE0] = bytes; /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */ |
59 | BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */ |
60 | return DFD; |
61 | } |
62 | |
63 | static uint32_t setChannelFlags(uint32_t channel, enum VkSuffix suffix) |
64 | { |
65 | switch (suffix) { |
66 | case s_UNORM: break; |
67 | case s_SNORM: |
68 | channel |= |
69 | KHR_DF_SAMPLE_DATATYPE_SIGNED; |
70 | break; |
71 | case s_USCALED: break; |
72 | case s_SSCALED: |
73 | channel |= |
74 | KHR_DF_SAMPLE_DATATYPE_SIGNED; |
75 | break; |
76 | case s_UINT: break; |
77 | case s_SINT: |
78 | channel |= |
79 | KHR_DF_SAMPLE_DATATYPE_SIGNED; |
80 | break; |
81 | case s_SFLOAT: |
82 | channel |= |
83 | KHR_DF_SAMPLE_DATATYPE_FLOAT | |
84 | KHR_DF_SAMPLE_DATATYPE_SIGNED; |
85 | break; |
86 | case s_UFLOAT: |
87 | channel |= |
88 | KHR_DF_SAMPLE_DATATYPE_FLOAT; |
89 | break; |
90 | case s_SRGB: |
91 | if (channel == KHR_DF_CHANNEL_RGBSDA_ALPHA) { |
92 | channel |= KHR_DF_SAMPLE_DATATYPE_LINEAR; |
93 | } |
94 | break; |
95 | } |
96 | return channel; |
97 | } |
98 | |
99 | static void writeSample(uint32_t *DFD, int sampleNo, int channel, |
100 | int bits, int offset, |
101 | int topSample, int bottomSample, enum VkSuffix suffix) |
102 | { |
103 | // Use this to avoid type-punning complaints from the gcc optimizer |
104 | // with -Wall. |
105 | union { |
106 | uint32_t i; |
107 | float f; |
108 | } lower, upper; |
109 | uint32_t *sample = DFD + 1 + KHR_DF_WORD_SAMPLESTART + sampleNo * KHR_DF_WORD_SAMPLEWORDS; |
110 | if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA; |
111 | |
112 | if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA; |
113 | channel = setChannelFlags(channel, suffix); |
114 | |
115 | sample[KHR_DF_SAMPLEWORD_BITOFFSET] = |
116 | (offset << KHR_DF_SAMPLESHIFT_BITOFFSET) | |
117 | ((bits - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | |
118 | (channel << KHR_DF_SAMPLESHIFT_CHANNELID); |
119 | |
120 | sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; |
121 | |
122 | switch (suffix) { |
123 | case s_UNORM: |
124 | case s_SRGB: |
125 | default: |
126 | if (bits > 32) { |
127 | upper.i = 0xFFFFFFFFU; |
128 | } else { |
129 | upper.i = (uint32_t)((1U << bits) - 1U); |
130 | } |
131 | lower.i = 0U; |
132 | break; |
133 | case s_SNORM: |
134 | if (bits > 32) { |
135 | upper.i = 0x7FFFFFFF; |
136 | } else { |
137 | upper.i = topSample ? (1U << (bits - 1)) - 1 : (1U << bits) - 1; |
138 | } |
139 | lower.i = ~upper.i; |
140 | if (bottomSample) lower.i += 1; |
141 | break; |
142 | case s_USCALED: |
143 | case s_UINT: |
144 | upper.i = bottomSample ? 1U : 0U; |
145 | lower.i = 0U; |
146 | break; |
147 | case s_SSCALED: |
148 | case s_SINT: |
149 | upper.i = bottomSample ? 1U : 0U; |
150 | lower.i = ~0U; |
151 | break; |
152 | case s_SFLOAT: |
153 | upper.f = 1.0f; |
154 | lower.f = -1.0f; |
155 | break; |
156 | case s_UFLOAT: |
157 | upper.f = 1.0f; |
158 | lower.f = 0.0f; |
159 | break; |
160 | } |
161 | sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; |
162 | sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; |
163 | } |
164 | |
165 | /** |
166 | * @~English |
167 | * @brief Create a Data Format Descriptor for an unpacked format. |
168 | * |
169 | * @param bigEndian Set to 1 for big-endian byte ordering and |
170 | 0 for little-endian byte ordering. |
171 | * @param numChannels The number of color channels. |
172 | * @param bytes The number of bytes per channel. |
173 | * @param redBlueSwap Normally channels appear in consecutive R, G, B, A order |
174 | * in memory; redBlueSwap inverts red and blue, allowing |
175 | * B, G, R, A. |
176 | * @param suffix Indicates the format suffix for the type. |
177 | * |
178 | * @return A data format descriptor in malloc'd data. The caller is responsible |
179 | * for freeing the descriptor. |
180 | **/ |
181 | uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, |
182 | int redBlueSwap, enum VkSuffix suffix) |
183 | { |
184 | uint32_t *DFD; |
185 | if (bigEndian) { |
186 | int channelCounter, channelByte; |
187 | /* Number of samples = number of channels * bytes per channel */ |
188 | DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix, i_COLOR); |
189 | /* First loop over the channels */ |
190 | for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { |
191 | int channel = channelCounter; |
192 | if (redBlueSwap && (channel == 0 || channel == 2)) { |
193 | channel ^= 2; |
194 | } |
195 | /* Loop over the bytes that constitute a channel */ |
196 | for (channelByte = 0; channelByte < bytes; ++channelByte) { |
197 | writeSample(DFD, channelCounter * bytes + channelByte, channel, |
198 | 8, 8 * (channelCounter * bytes + bytes - channelByte - 1), |
199 | channelByte == bytes-1, channelByte == 0, suffix); |
200 | } |
201 | } |
202 | |
203 | } else { /* Little-endian */ |
204 | |
205 | int sampleCounter; |
206 | /* One sample per channel */ |
207 | DFD = writeHeader(numChannels, numChannels * bytes, suffix, i_COLOR); |
208 | for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { |
209 | int channel = sampleCounter; |
210 | if (redBlueSwap && (channel == 0 || channel == 2)) { |
211 | channel ^= 2; |
212 | } |
213 | writeSample(DFD, sampleCounter, channel, |
214 | 8 * bytes, 8 * sampleCounter * bytes, |
215 | 1, 1, suffix); |
216 | } |
217 | } |
218 | return DFD; |
219 | } |
220 | |
221 | /** |
222 | * @~English |
223 | * @brief Create a Data Format Descriptor for a packed format. |
224 | * |
225 | * @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and |
226 | * 0 for little-endian byte ordering. |
227 | * @param numChannels The number of color channels. |
228 | * @param bits[] An array of length numChannels. |
229 | * Each entry is the number of bits composing the channel, in |
230 | * order starting at bit 0 of the packed type. |
231 | * @param channels[] An array of length numChannels. |
232 | * Each entry enumerates the channel type: 0 = red, 1 = green, |
233 | * 2 = blue, 15 = alpha, in order starting at bit 0 of the |
234 | * packed type. These values match channel IDs for RGBSDA in |
235 | * the Khronos Data Format header. To simplify iteration |
236 | * through channels, channel id 3 is a synonym for alpha. |
237 | * @param suffix Indicates the format suffix for the type. |
238 | * |
239 | * @return A data format descriptor in malloc'd data. The caller is responsible |
240 | * for freeing the descriptor. |
241 | **/ |
242 | uint32_t *createDFDPacked(int bigEndian, int numChannels, |
243 | int bits[], int channels[], |
244 | enum VkSuffix suffix) |
245 | { |
246 | uint32_t *DFD = 0; |
247 | if (numChannels == 6) { |
248 | /* Special case E5B9G9R9 */ |
249 | DFD = writeHeader(numChannels, 4, s_UFLOAT, i_COLOR); |
250 | writeSample(DFD, 0, 0, |
251 | 9, 0, |
252 | 1, 1, s_UNORM); |
253 | KHR_DFDSETSVAL((DFD+1), 0, SAMPLEUPPER, 8448); |
254 | writeSample(DFD, 1, 0 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, |
255 | 5, 27, |
256 | 1, 1, s_UNORM); |
257 | KHR_DFDSETSVAL((DFD+1), 1, SAMPLELOWER, 15); |
258 | KHR_DFDSETSVAL((DFD+1), 1, SAMPLEUPPER, 31); |
259 | writeSample(DFD, 2, 1, |
260 | 9, 9, |
261 | 1, 1, s_UNORM); |
262 | KHR_DFDSETSVAL((DFD+1), 2, SAMPLEUPPER, 8448); |
263 | writeSample(DFD, 3, 1 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, |
264 | 5, 27, |
265 | 1, 1, s_UNORM); |
266 | KHR_DFDSETSVAL((DFD+1), 3, SAMPLELOWER, 15); |
267 | KHR_DFDSETSVAL((DFD+1), 3, SAMPLEUPPER, 31); |
268 | writeSample(DFD, 4, 2, |
269 | 9, 18, |
270 | 1, 1, s_UNORM); |
271 | KHR_DFDSETSVAL((DFD+1), 4, SAMPLEUPPER, 8448); |
272 | writeSample(DFD, 5, 2 | KHR_DF_SAMPLE_DATATYPE_EXPONENT, |
273 | 5, 27, |
274 | 1, 1, s_UNORM); |
275 | KHR_DFDSETSVAL((DFD+1), 5, SAMPLELOWER, 15); |
276 | KHR_DFDSETSVAL((DFD+1), 5, SAMPLEUPPER, 31); |
277 | } else if (bigEndian) { |
278 | /* No packed format is larger than 32 bits. */ |
279 | /* No packed channel crosses more than two bytes. */ |
280 | int totalBits = 0; |
281 | int bitChannel[32]; |
282 | int beChannelStart[4]; |
283 | int channelCounter; |
284 | int bitOffset = 0; |
285 | int BEMask; |
286 | int numSamples = numChannels; |
287 | int sampleCounter; |
288 | for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { |
289 | beChannelStart[channelCounter] = totalBits; |
290 | totalBits += bits[channelCounter]; |
291 | } |
292 | BEMask = (totalBits - 1) & 0x18; |
293 | for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { |
294 | bitChannel[bitOffset ^ BEMask] = channelCounter; |
295 | if (((bitOffset + bits[channelCounter] - 1) & ~7) != (bitOffset & ~7)) { |
296 | /* Continuation sample */ |
297 | bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter; |
298 | numSamples++; |
299 | } |
300 | bitOffset += bits[channelCounter]; |
301 | } |
302 | DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR); |
303 | |
304 | sampleCounter = 0; |
305 | for (bitOffset = 0; bitOffset < totalBits;) { |
306 | if (bitChannel[bitOffset] == -1) { |
307 | /* Done this bit, so this is the lower half of something. */ |
308 | /* We must therefore jump to the end of the byte and continue. */ |
309 | bitOffset = (bitOffset + 8) & ~7; |
310 | } else { |
311 | /* Start of a channel? */ |
312 | int thisChannel = bitChannel[bitOffset]; |
313 | if ((beChannelStart[thisChannel] ^ BEMask) == bitOffset) { |
314 | /* Must be just one sample if we hit it first. */ |
315 | writeSample(DFD, sampleCounter++, channels[thisChannel], |
316 | bits[thisChannel], bitOffset, |
317 | 1, 1, suffix); |
318 | bitOffset += bits[thisChannel]; |
319 | } else { |
320 | /* Two samples. Move to the end of the first one we hit when we're done. */ |
321 | int firstSampleBits = 8 - (beChannelStart[thisChannel] & 0x7); /* Rest of the byte */ |
322 | int secondSampleBits = bits[thisChannel] - firstSampleBits; /* Rest of the bits */ |
323 | writeSample(DFD, sampleCounter++, channels[thisChannel], |
324 | firstSampleBits, beChannelStart[thisChannel] ^ BEMask, |
325 | 0, 1, suffix); |
326 | /* Mark that we've already handled this sample */ |
327 | bitChannel[beChannelStart[thisChannel] ^ BEMask] = -1; |
328 | writeSample(DFD, sampleCounter++, channels[thisChannel], |
329 | secondSampleBits, bitOffset, |
330 | 1, 0, suffix); |
331 | bitOffset += secondSampleBits; |
332 | } |
333 | } |
334 | } |
335 | |
336 | } else { /* Little-endian */ |
337 | |
338 | int sampleCounter; |
339 | int totalBits = 0; |
340 | int bitOffset = 0; |
341 | for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { |
342 | totalBits += bits[sampleCounter]; |
343 | } |
344 | |
345 | /* One sample per channel */ |
346 | DFD = writeHeader(numChannels, totalBits >> 3, suffix, i_COLOR); |
347 | for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { |
348 | writeSample(DFD, sampleCounter, channels[sampleCounter], |
349 | bits[sampleCounter], bitOffset, |
350 | 1, 1, suffix); |
351 | bitOffset += bits[sampleCounter]; |
352 | } |
353 | } |
354 | return DFD; |
355 | } |
356 | |
357 | static khr_df_model_e compModelMapping[] = { |
358 | KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, no alpha. */ |
359 | KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, punch-through alpha. */ |
360 | KHR_DF_MODEL_BC2, /*!< BC2, aka DXT2 and DXT3. */ |
361 | KHR_DF_MODEL_BC3, /*!< BC3, aka DXT4 and DXT5. */ |
362 | KHR_DF_MODEL_BC4, /*!< BC4. */ |
363 | KHR_DF_MODEL_BC5, /*!< BC5. */ |
364 | KHR_DF_MODEL_BC6H, /*!< BC6h HDR format. */ |
365 | KHR_DF_MODEL_BC7, /*!< BC7. */ |
366 | KHR_DF_MODEL_ETC2, /*!< ETC2 no alpha. */ |
367 | KHR_DF_MODEL_ETC2, /*!< ETC2 punch-through alpha. */ |
368 | KHR_DF_MODEL_ETC2, /*!< ETC2 independent alpha. */ |
369 | KHR_DF_MODEL_ETC2, /*!< R11 ETC2 single-channel. */ |
370 | KHR_DF_MODEL_ETC2, /*!< R11G11 ETC2 dual-channel. */ |
371 | KHR_DF_MODEL_ASTC, /*!< ASTC. */ |
372 | KHR_DF_MODEL_ETC1S, /*!< ETC1S. */ |
373 | KHR_DF_MODEL_PVRTC, /*!< PVRTC(1). */ |
374 | KHR_DF_MODEL_PVRTC2 /*!< PVRTC2. */ |
375 | }; |
376 | |
377 | static uint32_t compSampleCount[] = { |
378 | 1U, /*!< BC1, aka DXT1, no alpha. */ |
379 | 1U, /*!< BC1, aka DXT1, punch-through alpha. */ |
380 | 2U, /*!< BC2, aka DXT2 and DXT3. */ |
381 | 2U, /*!< BC3, aka DXT4 and DXT5. */ |
382 | 1U, /*!< BC4. */ |
383 | 2U, /*!< BC5. */ |
384 | 1U, /*!< BC6h HDR format. */ |
385 | 1U, /*!< BC7. */ |
386 | 1U, /*!< ETC2 no alpha. */ |
387 | 2U, /*!< ETC2 punch-through alpha. */ |
388 | 2U, /*!< ETC2 independent alpha. */ |
389 | 1U, /*!< R11 ETC2 single-channel. */ |
390 | 2U, /*!< R11G11 ETC2 dual-channel. */ |
391 | 1U, /*!< ASTC. */ |
392 | 1U, /*!< ETC1S. */ |
393 | 1U, /*!< PVRTC. */ |
394 | 1U /*!< PVRTC2. */ |
395 | }; |
396 | |
397 | static khr_df_model_channels_e compFirstChannel[] = { |
398 | KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */ |
399 | KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */ |
400 | KHR_DF_CHANNEL_BC2_ALPHA, /*!< BC2, aka DXT2 and DXT3. */ |
401 | KHR_DF_CHANNEL_BC3_ALPHA, /*!< BC3, aka DXT4 and DXT5. */ |
402 | KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */ |
403 | KHR_DF_CHANNEL_BC5_RED, /*!< BC5. */ |
404 | KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */ |
405 | KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */ |
406 | KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */ |
407 | KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 punch-through alpha. */ |
408 | KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 independent alpha. */ |
409 | KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */ |
410 | KHR_DF_CHANNEL_ETC2_RED, /*!< R11G11 ETC2 dual-channel. */ |
411 | KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */ |
412 | KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */ |
413 | KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */ |
414 | KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */ |
415 | }; |
416 | |
417 | static khr_df_model_channels_e compSecondChannel[] = { |
418 | KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */ |
419 | KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */ |
420 | KHR_DF_CHANNEL_BC2_COLOR, /*!< BC2, aka DXT2 and DXT3. */ |
421 | KHR_DF_CHANNEL_BC3_COLOR, /*!< BC3, aka DXT4 and DXT5. */ |
422 | KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */ |
423 | KHR_DF_CHANNEL_BC5_GREEN, /*!< BC5. */ |
424 | KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */ |
425 | KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */ |
426 | KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */ |
427 | KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 punch-through alpha. */ |
428 | KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 independent alpha. */ |
429 | KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */ |
430 | KHR_DF_CHANNEL_ETC2_GREEN, /*!< R11G11 ETC2 dual-channel. */ |
431 | KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */ |
432 | KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */ |
433 | KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */ |
434 | KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */ |
435 | }; |
436 | |
437 | static uint32_t compSecondChannelOffset[] = { |
438 | 0U, /*!< BC1, aka DXT1, no alpha. */ |
439 | 0U, /*!< BC1, aka DXT1, punch-through alpha. */ |
440 | 64U, /*!< BC2, aka DXT2 and DXT3. */ |
441 | 64U, /*!< BC3, aka DXT4 and DXT5. */ |
442 | 0U, /*!< BC4. */ |
443 | 64U, /*!< BC5. */ |
444 | 0U, /*!< BC6h HDR format. */ |
445 | 0U, /*!< BC7. */ |
446 | 0U, /*!< ETC2 no alpha. */ |
447 | 0U, /*!< ETC2 punch-through alpha. */ |
448 | 64U, /*!< ETC2 independent alpha. */ |
449 | 0U, /*!< R11 ETC2 single-channel. */ |
450 | 64U, /*!< R11G11 ETC2 dual-channel. */ |
451 | 0U, /*!< ASTC. */ |
452 | 0U, /*!< ETC1S. */ |
453 | 0U, /*!< PVRTC. */ |
454 | 0U /*!< PVRTC2. */ |
455 | }; |
456 | |
457 | static uint32_t compChannelBits[] = { |
458 | 64U, /*!< BC1, aka DXT1, no alpha. */ |
459 | 64U, /*!< BC1, aka DXT1, punch-through alpha. */ |
460 | 64U, /*!< BC2, aka DXT2 and DXT3. */ |
461 | 64U, /*!< BC3, aka DXT4 and DXT5. */ |
462 | 64U, /*!< BC4. */ |
463 | 64U, /*!< BC5. */ |
464 | 128U, /*!< BC6h HDR format. */ |
465 | 128U, /*!< BC7. */ |
466 | 64U, /*!< ETC2 no alpha. */ |
467 | 64U, /*!< ETC2 punch-through alpha. */ |
468 | 64U, /*!< ETC2 independent alpha. */ |
469 | 64U, /*!< R11 ETC2 single-channel. */ |
470 | 64U, /*!< R11G11 ETC2 dual-channel. */ |
471 | 128U, /*!< ASTC. */ |
472 | 64U, /*!< ETC1S. */ |
473 | 64U, /*!< PVRTC. */ |
474 | 64U /*!< PVRTC2. */ |
475 | }; |
476 | |
477 | static uint32_t compBytes[] = { |
478 | 8U, /*!< BC1, aka DXT1, no alpha. */ |
479 | 8U, /*!< BC1, aka DXT1, punch-through alpha. */ |
480 | 16U, /*!< BC2, aka DXT2 and DXT3. */ |
481 | 16U, /*!< BC3, aka DXT4 and DXT5. */ |
482 | 8U, /*!< BC4. */ |
483 | 16U, /*!< BC5. */ |
484 | 16U, /*!< BC6h HDR format. */ |
485 | 16U, /*!< BC7. */ |
486 | 8U, /*!< ETC2 no alpha. */ |
487 | 8U, /*!< ETC2 punch-through alpha. */ |
488 | 16U, /*!< ETC2 independent alpha. */ |
489 | 8U, /*!< R11 ETC2 single-channel. */ |
490 | 16U, /*!< R11G11 ETC2 dual-channel. */ |
491 | 16U, /*!< ASTC. */ |
492 | 8U, /*!< ETC1S. */ |
493 | 8U, /*!< PVRTC. */ |
494 | 8U /*!< PVRTC2. */ |
495 | }; |
496 | |
497 | /** |
498 | * @~English |
499 | * @brief Create a Data Format Descriptor for a compressed format. |
500 | * |
501 | * @param compScheme Vulkan-style compression scheme enumeration. |
502 | * @param bwidth Block width in texel coordinates. |
503 | * @param bheight Block height in texel coordinates. |
504 | * @param bdepth Block depth in texel coordinates. |
505 | * @author Mark Callow, Edgewise Consulting. |
506 | * @param suffix Indicates the format suffix for the type. |
507 | * |
508 | * @return A data format descriptor in malloc'd data. The caller is responsible |
509 | * for freeing the descriptor. |
510 | **/ |
511 | uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth, |
512 | enum VkSuffix suffix) |
513 | { |
514 | uint32_t *DFD = 0; |
515 | uint32_t numSamples = compSampleCount[compScheme]; |
516 | uint32_t* BDFD; |
517 | uint32_t *sample; |
518 | uint32_t channel; |
519 | // Use union to avoid type-punning complaints from gcc optimizer |
520 | // with -Wall. |
521 | union { |
522 | uint32_t i; |
523 | float f; |
524 | } lower, upper; |
525 | |
526 | DFD = (uint32_t *) malloc(sizeof(uint32_t) * |
527 | (1 + KHR_DF_WORD_SAMPLESTART + |
528 | numSamples * KHR_DF_WORD_SAMPLEWORDS)); |
529 | BDFD = DFD+1; |
530 | DFD[0] = sizeof(uint32_t) * |
531 | (1 + KHR_DF_WORD_SAMPLESTART + |
532 | numSamples * KHR_DF_WORD_SAMPLEWORDS); |
533 | BDFD[KHR_DF_WORD_VENDORID] = |
534 | (KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) | |
535 | (KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE); |
536 | BDFD[KHR_DF_WORD_VERSIONNUMBER] = |
537 | (KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) | |
538 | (((uint32_t)sizeof(uint32_t) * |
539 | (KHR_DF_WORD_SAMPLESTART + |
540 | numSamples * KHR_DF_WORD_SAMPLEWORDS) |
541 | << KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE)); |
542 | BDFD[KHR_DF_WORD_MODEL] = |
543 | ((compModelMapping[compScheme] << KHR_DF_SHIFT_MODEL) | |
544 | (KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) | /* Assumed */ |
545 | (KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS)); |
546 | |
547 | if (suffix == s_SRGB) { |
548 | BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER; |
549 | } else { |
550 | BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER; |
551 | } |
552 | BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = |
553 | (bwidth - 1) | ((bheight - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1) | ((bdepth - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION2); |
554 | /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */ |
555 | BDFD[KHR_DF_WORD_BYTESPLANE0] = compBytes[compScheme]; |
556 | BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */ |
557 | |
558 | sample = BDFD + KHR_DF_WORD_SAMPLESTART; |
559 | channel = compFirstChannel[compScheme]; |
560 | channel = setChannelFlags(channel, suffix); |
561 | |
562 | sample[KHR_DF_SAMPLEWORD_BITOFFSET] = |
563 | (0 << KHR_DF_SAMPLESHIFT_BITOFFSET) | |
564 | ((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | |
565 | (channel << KHR_DF_SAMPLESHIFT_CHANNELID); |
566 | |
567 | sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; |
568 | switch (suffix) { |
569 | case s_UNORM: |
570 | case s_SRGB: |
571 | default: |
572 | upper.i = 0xFFFFFFFFU; |
573 | lower.i = 0U; |
574 | break; |
575 | case s_SNORM: |
576 | upper.i = 0x7FFFFFFF; |
577 | lower.i = ~upper.i; |
578 | break; |
579 | case s_USCALED: |
580 | case s_UINT: |
581 | upper.i = 1U; |
582 | lower.i = 0U; |
583 | break; |
584 | case s_SSCALED: |
585 | case s_SINT: |
586 | upper.i = 1U; |
587 | lower.i = ~0U; |
588 | break; |
589 | case s_SFLOAT: |
590 | upper.f = 1.0f; |
591 | lower.f = -1.0f; |
592 | break; |
593 | case s_UFLOAT: |
594 | upper.f = 1.0f; |
595 | lower.f = 0.0f; |
596 | break; |
597 | } |
598 | sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; |
599 | sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; |
600 | |
601 | if (compSampleCount[compScheme] > 1) { |
602 | sample += KHR_DF_WORD_SAMPLEWORDS; |
603 | channel = compSecondChannel[compScheme]; |
604 | channel = setChannelFlags(channel, suffix); |
605 | |
606 | sample[KHR_DF_SAMPLEWORD_BITOFFSET] = |
607 | (compSecondChannelOffset[compScheme] << KHR_DF_SAMPLESHIFT_BITOFFSET) | |
608 | ((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) | |
609 | (channel << KHR_DF_SAMPLESHIFT_CHANNELID); |
610 | |
611 | sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0; |
612 | |
613 | sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i; |
614 | sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i; |
615 | } |
616 | return DFD; |
617 | } |
618 | |
619 | /** |
620 | * @~English |
621 | * @brief Create a Data Format Descriptor for a depth-stencil format. |
622 | * |
623 | * @param depthBits The numeber of bits in the depth channel. |
624 | * @param stencilBits The numeber of bits in the stencil channel. |
625 | * @param sizeBytes The total byte size of the texel. |
626 | * |
627 | * @return A data format descriptor in malloc'd data. The caller is responsible |
628 | * for freeing the descriptor. |
629 | **/ |
630 | uint32_t *createDFDDepthStencil(int depthBits, |
631 | int stencilBits, |
632 | int sizeBytes) |
633 | { |
634 | /* N.B. Little-endian is assumed. */ |
635 | uint32_t *DFD = 0; |
636 | DFD = writeHeader((depthBits > 0) + (stencilBits > 0), |
637 | sizeBytes, s_UNORM, i_NON_COLOR); |
638 | if (depthBits == 32) { |
639 | writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH, |
640 | 32, 0, |
641 | 1, 1, s_SFLOAT); |
642 | } else if (depthBits > 0) { |
643 | writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH, |
644 | depthBits, 0, |
645 | 1, 1, s_UNORM); |
646 | } |
647 | if (stencilBits > 0) { |
648 | if (depthBits > 0) { |
649 | writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_STENCIL, |
650 | stencilBits, depthBits, |
651 | 1, 1, s_UINT); |
652 | } else { |
653 | writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL, |
654 | stencilBits, 0, |
655 | 1, 1, s_UINT); |
656 | } |
657 | } |
658 | return DFD; |
659 | } |
660 | |