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
23typedef enum { i_COLOR, i_NON_COLOR } channels_infotype;
24
25static uint32_t *writeHeader(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
63static 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
99static 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 **/
181uint32_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 **/
242uint32_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
357static 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
377static 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
397static 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
417static 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
437static 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
457static 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
477static 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 **/
511uint32_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 **/
630uint32_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