Path: blob/master/thirdparty/libktx/external/dfdutils/createdfd.c
9912 views
/* -*- tab-width: 4; -*- */1/* vi: set sw=2 ts=4 expandtab: */23/* Copyright 2019-2020 The Khronos Group Inc.4* SPDX-License-Identifier: Apache-2.05*/67/**8* @file9* @~English10* @brief Utilities for creating data format descriptors.11*/1213/*14* Author: Andrew Garrard15*/1617#include <assert.h>18#include <stdlib.h>19#include <string.h>20#include <KHR/khr_df.h>2122#include "dfd.h"2324typedef enum { i_COLOR, i_NON_COLOR } channels_infotype;2526static uint32_t *writeHeader(int numSamples, int bytes, int suffix,27channels_infotype infotype)28{29uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) *30(1 + KHR_DF_WORD_SAMPLESTART +31numSamples * KHR_DF_WORD_SAMPLEWORDS));32uint32_t* BDFD = DFD+1;33DFD[0] = sizeof(uint32_t) *34(1 + KHR_DF_WORD_SAMPLESTART +35numSamples * KHR_DF_WORD_SAMPLEWORDS);36BDFD[KHR_DF_WORD_VENDORID] =37(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |38(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);39BDFD[KHR_DF_WORD_VERSIONNUMBER] =40(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |41(((uint32_t)sizeof(uint32_t) *42(KHR_DF_WORD_SAMPLESTART +43numSamples * KHR_DF_WORD_SAMPLEWORDS)44<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));45BDFD[KHR_DF_WORD_MODEL] =46((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) | /* Only supported model */47(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));48if (infotype == i_COLOR) {49BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES; /* Assumed */50} else {51BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_UNSPECIFIED << KHR_DF_SHIFT_PRIMARIES;52}53if (suffix == s_SRGB) {54BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;55} else {56BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;57}58BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 0; /* Only 1x1x1x1 texel blocks supported */59BDFD[KHR_DF_WORD_BYTESPLANE0] = bytes; /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */60BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */61return DFD;62}6364static uint32_t setChannelFlags(uint32_t channel, enum VkSuffix suffix)65{66switch (suffix) {67case s_UNORM: break;68case s_SNORM:69channel |=70KHR_DF_SAMPLE_DATATYPE_SIGNED;71break;72case s_USCALED: break;73case s_SSCALED:74channel |=75KHR_DF_SAMPLE_DATATYPE_SIGNED;76break;77case s_UINT: break;78case s_SINT:79channel |=80KHR_DF_SAMPLE_DATATYPE_SIGNED;81break;82case s_SFLOAT:83channel |=84KHR_DF_SAMPLE_DATATYPE_FLOAT |85KHR_DF_SAMPLE_DATATYPE_SIGNED;86break;87case s_UFLOAT:88channel |=89KHR_DF_SAMPLE_DATATYPE_FLOAT;90break;91case s_SRGB:92if (channel == KHR_DF_CHANNEL_RGBSDA_ALPHA) {93channel |= KHR_DF_SAMPLE_DATATYPE_LINEAR;94}95break;96case s_SFIXED5:97channel |=98KHR_DF_SAMPLE_DATATYPE_SIGNED;99break;100}101return channel;102}103104static void writeSample(uint32_t *DFD, int sampleNo, int channel,105int bits, int offset,106int topSample, int bottomSample, enum VkSuffix suffix)107{108// Use this to avoid type-punning complaints from the gcc optimizer109// with -Wall.110union {111uint32_t i;112float f;113} lower, upper;114uint32_t *sample = DFD + 1 + KHR_DF_WORD_SAMPLESTART + sampleNo * KHR_DF_WORD_SAMPLEWORDS;115116if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA;117channel = setChannelFlags(channel, suffix);118119sample[KHR_DF_SAMPLEWORD_BITOFFSET] =120(offset << KHR_DF_SAMPLESHIFT_BITOFFSET) |121((bits - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |122(channel << KHR_DF_SAMPLESHIFT_CHANNELID);123124sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;125126switch (suffix) {127case s_UNORM:128case s_SRGB:129default:130if (bits > 32) {131upper.i = 0xFFFFFFFFU;132} else {133upper.i = (uint32_t)((1U << bits) - 1U);134}135lower.i = 0U;136break;137case s_SNORM:138if (bits > 32) {139upper.i = 0x7FFFFFFF;140} else {141upper.i = topSample ? (1U << (bits - 1)) - 1 : (1U << bits) - 1;142}143lower.i = ~upper.i;144if (bottomSample) lower.i += 1;145break;146case s_USCALED:147case s_UINT:148upper.i = bottomSample ? 1U : 0U;149lower.i = 0U;150break;151case s_SSCALED:152case s_SINT:153upper.i = bottomSample ? 1U : 0U;154lower.i = ~0U;155break;156case s_SFLOAT:157upper.f = 1.0f;158lower.f = -1.0f;159break;160case s_UFLOAT:161upper.f = 1.0f;162lower.f = 0.0f;163break;164case s_SFIXED5:165assert(bits == 16 && "Format with this suffix must be 16 bits per channel.");166upper.i = 32;167lower.i = ~upper.i + 1; // -32168}169sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;170sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;171}172173/**174* @~English175* @brief Create a Data Format Descriptor for an unpacked format.176*177* @param bigEndian Set to 1 for big-endian byte ordering and1780 for little-endian byte ordering.179* @param numChannels The number of color channels.180* @param bytes The number of bytes per channel.181* @param redBlueSwap Normally channels appear in consecutive R, G, B, A order182* in memory; redBlueSwap inverts red and blue, allowing183* B, G, R, A.184* @param suffix Indicates the format suffix for the type.185*186* @return A data format descriptor in malloc'd data. The caller is responsible187* for freeing the descriptor.188**/189uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes,190int redBlueSwap, enum VkSuffix suffix)191{192uint32_t *DFD;193if (bigEndian) {194int channelCounter, channelByte;195/* Number of samples = number of channels * bytes per channel */196DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix, i_COLOR);197/* First loop over the channels */198for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {199int channel = channelCounter;200if (redBlueSwap && (channel == 0 || channel == 2)) {201channel ^= 2;202}203/* Loop over the bytes that constitute a channel */204for (channelByte = 0; channelByte < bytes; ++channelByte) {205writeSample(DFD, channelCounter * bytes + channelByte, channel,2068, 8 * (channelCounter * bytes + bytes - channelByte - 1),207channelByte == bytes-1, channelByte == 0, suffix);208}209}210211} else { /* Little-endian */212213int sampleCounter;214/* One sample per channel */215DFD = writeHeader(numChannels, numChannels * bytes, suffix, i_COLOR);216for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {217int channel = sampleCounter;218if (redBlueSwap && (channel == 0 || channel == 2)) {219channel ^= 2;220}221writeSample(DFD, sampleCounter, channel,2228 * bytes, 8 * sampleCounter * bytes,2231, 1, suffix);224}225}226return DFD;227}228229/**230* @~English231* @brief Create a Data Format Descriptor for a packed format.232*233* @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and234* 0 for little-endian byte ordering.235* @param numChannels The number of color channels.236* @param bits[] An array of length numChannels.237* Each entry is the number of bits composing the channel, in238* order starting at bit 0 of the packed type.239* @param shiftBits[] An array of length numChannels.240* Each entry is the number of bits each channel is shifted241* and thus padded with insignificant bits.242* @param channels[] An array of length numChannels.243* Each entry enumerates the channel type: 0 = red, 1 = green,244* 2 = blue, 15 = alpha, in order starting at bit 0 of the245* packed type. These values match channel IDs for RGBSDA in246* the Khronos Data Format header. To simplify iteration247* through channels, channel id 3 is a synonym for alpha.248* @param suffix Indicates the format suffix for the type.249*250* @return A data format descriptor in malloc'd data. The caller is responsible251* for freeing the descriptor.252**/253uint32_t *createDFDPackedShifted(int bigEndian, int numChannels,254int bits[], int shiftBits[], int channels[],255enum VkSuffix suffix)256{257uint32_t *DFD = 0;258if (numChannels == 6) {259/* Special case E5B9G9R9 */260DFD = writeHeader(numChannels, 4, s_UFLOAT, i_COLOR);261writeSample(DFD, 0, 0,2629, 0,2631, 1, s_UNORM);264KHR_DFDSETSVAL((DFD+1), 0, SAMPLEUPPER, 8448);265writeSample(DFD, 1, 0 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,2665, 27,2671, 1, s_UNORM);268KHR_DFDSETSVAL((DFD+1), 1, SAMPLELOWER, 15);269KHR_DFDSETSVAL((DFD+1), 1, SAMPLEUPPER, 31);270writeSample(DFD, 2, 1,2719, 9,2721, 1, s_UNORM);273KHR_DFDSETSVAL((DFD+1), 2, SAMPLEUPPER, 8448);274writeSample(DFD, 3, 1 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,2755, 27,2761, 1, s_UNORM);277KHR_DFDSETSVAL((DFD+1), 3, SAMPLELOWER, 15);278KHR_DFDSETSVAL((DFD+1), 3, SAMPLEUPPER, 31);279writeSample(DFD, 4, 2,2809, 18,2811, 1, s_UNORM);282KHR_DFDSETSVAL((DFD+1), 4, SAMPLEUPPER, 8448);283writeSample(DFD, 5, 2 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,2845, 27,2851, 1, s_UNORM);286KHR_DFDSETSVAL((DFD+1), 5, SAMPLELOWER, 15);287KHR_DFDSETSVAL((DFD+1), 5, SAMPLEUPPER, 31);288} else if (bigEndian) {289/* No packed format is larger than 32 bits. */290/* No packed channel crosses more than two bytes. */291int totalBits = 0;292int bitChannel[32];293int beChannelStart[4];294int channelCounter;295int bitOffset = 0;296int BEMask;297int numSamples = numChannels;298int sampleCounter;299for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {300beChannelStart[channelCounter] = totalBits;301totalBits += shiftBits[channelCounter] + bits[channelCounter];302}303BEMask = (totalBits - 1) & 0x18;304for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {305bitOffset += shiftBits[channelCounter];306bitChannel[bitOffset ^ BEMask] = channelCounter;307if (((bitOffset + bits[channelCounter] - 1) & ~7) != (bitOffset & ~7)) {308/* Continuation sample */309bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter;310numSamples++;311}312bitOffset += bits[channelCounter];313}314DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR);315316sampleCounter = 0;317for (bitOffset = 0; bitOffset < totalBits;) {318if (bitChannel[bitOffset] == -1) {319/* Done this bit, so this is the lower half of something. */320/* We must therefore jump to the end of the byte and continue. */321bitOffset = (bitOffset + 8) & ~7;322} else {323/* Start of a channel? */324int thisChannel = bitChannel[bitOffset];325if ((beChannelStart[thisChannel] ^ BEMask) == bitOffset) {326/* Must be just one sample if we hit it first. */327writeSample(DFD, sampleCounter++, channels[thisChannel],328bits[thisChannel], bitOffset,3291, 1, suffix);330bitOffset += bits[thisChannel];331} else {332/* Two samples. Move to the end of the first one we hit when we're done. */333int firstSampleBits = 8 - (beChannelStart[thisChannel] & 0x7); /* Rest of the byte */334int secondSampleBits = bits[thisChannel] - firstSampleBits; /* Rest of the bits */335writeSample(DFD, sampleCounter++, channels[thisChannel],336firstSampleBits, beChannelStart[thisChannel] ^ BEMask,3370, 1, suffix);338/* Mark that we've already handled this sample */339bitChannel[beChannelStart[thisChannel] ^ BEMask] = -1;340writeSample(DFD, sampleCounter++, channels[thisChannel],341secondSampleBits, bitOffset,3421, 0, suffix);343bitOffset += secondSampleBits;344}345}346}347348} else { /* Little-endian */349350int sampleCounter;351int totalBits = 0;352int bitOffset = 0;353for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {354totalBits += shiftBits[sampleCounter] + bits[sampleCounter];355}356357/* One sample per channel */358DFD = writeHeader(numChannels, totalBits >> 3, suffix, i_COLOR);359for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {360bitOffset += shiftBits[sampleCounter];361writeSample(DFD, sampleCounter, channels[sampleCounter],362bits[sampleCounter], bitOffset,3631, 1, suffix);364bitOffset += bits[sampleCounter];365}366}367return DFD;368}369370/**371* @~English372* @brief Create a Data Format Descriptor for a packed format.373*374* @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and375* 0 for little-endian byte ordering.376* @param numChannels The number of color channels.377* @param bits[] An array of length numChannels.378* Each entry is the number of bits composing the channel, in379* order starting at bit 0 of the packed type.380* @param channels[] An array of length numChannels.381* Each entry enumerates the channel type: 0 = red, 1 = green,382* 2 = blue, 15 = alpha, in order starting at bit 0 of the383* packed type. These values match channel IDs for RGBSDA in384* the Khronos Data Format header. To simplify iteration385* through channels, channel id 3 is a synonym for alpha.386* @param suffix Indicates the format suffix for the type.387*388* @return A data format descriptor in malloc'd data. The caller is responsible389* for freeing the descriptor.390**/391uint32_t *createDFDPacked(int bigEndian, int numChannels,392int bits[], int channels[],393enum VkSuffix suffix) {394assert(numChannels <= 6);395int shiftBits[] = {0, 0, 0, 0, 0, 0};396return createDFDPackedShifted(bigEndian, numChannels, bits, shiftBits, channels, suffix);397}398399uint32_t *createDFD422(int bigEndian, int numSamples,400int bits[], int shiftBits[], int channels[],401int position_xs[], int position_ys[],402enum VkSuffix suffix) {403assert(!bigEndian); (void) bigEndian;404assert(suffix == s_UNORM); (void) suffix;405406int totalBits = 0;407for (int i = 0; i < numSamples; ++i)408totalBits += shiftBits[i] + bits[i];409assert(totalBits % 8 == 0);410411uint32_t BDFDSize = sizeof(uint32_t) * (KHR_DF_WORD_SAMPLESTART + numSamples * KHR_DF_WORD_SAMPLEWORDS);412uint32_t DFDSize = sizeof(uint32_t) + BDFDSize;413uint32_t *DFD = (uint32_t *) malloc(DFDSize);414memset(DFD, 0, DFDSize);415DFD[0] = DFDSize;416uint32_t *BDFD = DFD + 1;417KHR_DFDSETVAL(BDFD, VENDORID, KHR_DF_VENDORID_KHRONOS);418KHR_DFDSETVAL(BDFD, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT);419KHR_DFDSETVAL(BDFD, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_LATEST);420KHR_DFDSETVAL(BDFD, DESCRIPTORBLOCKSIZE, BDFDSize);421KHR_DFDSETVAL(BDFD, MODEL, KHR_DF_MODEL_YUVSDA);422KHR_DFDSETVAL(BDFD, PRIMARIES, KHR_DF_PRIMARIES_UNSPECIFIED);423KHR_DFDSETVAL(BDFD, TRANSFER, KHR_DF_TRANSFER_LINEAR);424KHR_DFDSETVAL(BDFD, FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT);425KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION0, 2 - 1); // 422 contains 2 x 1 blocks426KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION1, 1 - 1);427KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION2, 1 - 1);428KHR_DFDSETVAL(BDFD, TEXELBLOCKDIMENSION3, 1 - 1);429KHR_DFDSETVAL(BDFD, BYTESPLANE0, totalBits / 8);430KHR_DFDSETVAL(BDFD, BYTESPLANE1, 0);431KHR_DFDSETVAL(BDFD, BYTESPLANE2, 0);432KHR_DFDSETVAL(BDFD, BYTESPLANE3, 0);433KHR_DFDSETVAL(BDFD, BYTESPLANE4, 0);434KHR_DFDSETVAL(BDFD, BYTESPLANE5, 0);435KHR_DFDSETVAL(BDFD, BYTESPLANE6, 0);436KHR_DFDSETVAL(BDFD, BYTESPLANE7, 0);437438int bitOffset = 0;439for (int i = 0; i < numSamples; ++i) {440bitOffset += shiftBits[i];441KHR_DFDSETSVAL(BDFD, i, BITOFFSET, bitOffset);442KHR_DFDSETSVAL(BDFD, i, BITLENGTH, bits[i] - 1);443KHR_DFDSETSVAL(BDFD, i, CHANNELID, channels[i]);444KHR_DFDSETSVAL(BDFD, i, QUALIFIERS, 0); // None of: FLOAT, SIGNED, EXPONENT, LINEAR445KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION0, position_xs[i]);446KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION1, position_ys[i]);447KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION2, 0);448KHR_DFDSETSVAL(BDFD, i, SAMPLEPOSITION3, 0);449KHR_DFDSETSVAL(BDFD, i, SAMPLELOWER, 0);450KHR_DFDSETSVAL(BDFD, i, SAMPLEUPPER, (1u << bits[i]) - 1u);451bitOffset += bits[i];452}453454return DFD;455}456457static khr_df_model_e compModelMapping[] = {458KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, no alpha. */459KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, punch-through alpha. */460KHR_DF_MODEL_BC2, /*!< BC2, aka DXT2 and DXT3. */461KHR_DF_MODEL_BC3, /*!< BC3, aka DXT4 and DXT5. */462KHR_DF_MODEL_BC4, /*!< BC4. */463KHR_DF_MODEL_BC5, /*!< BC5. */464KHR_DF_MODEL_BC6H, /*!< BC6h HDR format. */465KHR_DF_MODEL_BC7, /*!< BC7. */466KHR_DF_MODEL_ETC2, /*!< ETC2 no alpha. */467KHR_DF_MODEL_ETC2, /*!< ETC2 punch-through alpha. */468KHR_DF_MODEL_ETC2, /*!< ETC2 independent alpha. */469KHR_DF_MODEL_ETC2, /*!< R11 ETC2 single-channel. */470KHR_DF_MODEL_ETC2, /*!< R11G11 ETC2 dual-channel. */471KHR_DF_MODEL_ASTC, /*!< ASTC. */472KHR_DF_MODEL_ETC1S, /*!< ETC1S. */473KHR_DF_MODEL_PVRTC, /*!< PVRTC(1). */474KHR_DF_MODEL_PVRTC2 /*!< PVRTC2. */475};476477static uint32_t compSampleCount[] = {4781U, /*!< BC1, aka DXT1, no alpha. */4791U, /*!< BC1, aka DXT1, punch-through alpha. */4802U, /*!< BC2, aka DXT2 and DXT3. */4812U, /*!< BC3, aka DXT4 and DXT5. */4821U, /*!< BC4. */4832U, /*!< BC5. */4841U, /*!< BC6h HDR format. */4851U, /*!< BC7. */4861U, /*!< ETC2 no alpha. */4872U, /*!< ETC2 punch-through alpha. */4882U, /*!< ETC2 independent alpha. */4891U, /*!< R11 ETC2 single-channel. */4902U, /*!< R11G11 ETC2 dual-channel. */4911U, /*!< ASTC. */4921U, /*!< ETC1S. */4931U, /*!< PVRTC. */4941U /*!< PVRTC2. */495};496497static khr_df_model_channels_e compFirstChannel[] = {498KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */499KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */500KHR_DF_CHANNEL_BC2_ALPHA, /*!< BC2, aka DXT2 and DXT3. */501KHR_DF_CHANNEL_BC3_ALPHA, /*!< BC3, aka DXT4 and DXT5. */502KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */503KHR_DF_CHANNEL_BC5_RED, /*!< BC5. */504KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */505KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */506KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */507KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 punch-through alpha. */508KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 independent alpha. */509KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */510KHR_DF_CHANNEL_ETC2_RED, /*!< R11G11 ETC2 dual-channel. */511KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */512KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */513KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */514KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */515};516517static khr_df_model_channels_e compSecondChannel[] = {518KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */519KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */520KHR_DF_CHANNEL_BC2_COLOR, /*!< BC2, aka DXT2 and DXT3. */521KHR_DF_CHANNEL_BC3_COLOR, /*!< BC3, aka DXT4 and DXT5. */522KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */523KHR_DF_CHANNEL_BC5_GREEN, /*!< BC5. */524KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */525KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */526KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */527KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 punch-through alpha. */528KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 independent alpha. */529KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */530KHR_DF_CHANNEL_ETC2_GREEN, /*!< R11G11 ETC2 dual-channel. */531KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */532KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */533KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */534KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */535};536537static uint32_t compSecondChannelOffset[] = {5380U, /*!< BC1, aka DXT1, no alpha. */5390U, /*!< BC1, aka DXT1, punch-through alpha. */54064U, /*!< BC2, aka DXT2 and DXT3. */54164U, /*!< BC3, aka DXT4 and DXT5. */5420U, /*!< BC4. */54364U, /*!< BC5. */5440U, /*!< BC6h HDR format. */5450U, /*!< BC7. */5460U, /*!< ETC2 no alpha. */5470U, /*!< ETC2 punch-through alpha. */54864U, /*!< ETC2 independent alpha. */5490U, /*!< R11 ETC2 single-channel. */55064U, /*!< R11G11 ETC2 dual-channel. */5510U, /*!< ASTC. */5520U, /*!< ETC1S. */5530U, /*!< PVRTC. */5540U /*!< PVRTC2. */555};556557static uint32_t compChannelBits[] = {55864U, /*!< BC1, aka DXT1, no alpha. */55964U, /*!< BC1, aka DXT1, punch-through alpha. */56064U, /*!< BC2, aka DXT2 and DXT3. */56164U, /*!< BC3, aka DXT4 and DXT5. */56264U, /*!< BC4. */56364U, /*!< BC5. */564128U, /*!< BC6h HDR format. */565128U, /*!< BC7. */56664U, /*!< ETC2 no alpha. */56764U, /*!< ETC2 punch-through alpha. */56864U, /*!< ETC2 independent alpha. */56964U, /*!< R11 ETC2 single-channel. */57064U, /*!< R11G11 ETC2 dual-channel. */571128U, /*!< ASTC. */57264U, /*!< ETC1S. */57364U, /*!< PVRTC. */57464U /*!< PVRTC2. */575};576577static uint32_t compBytes[] = {5788U, /*!< BC1, aka DXT1, no alpha. */5798U, /*!< BC1, aka DXT1, punch-through alpha. */58016U, /*!< BC2, aka DXT2 and DXT3. */58116U, /*!< BC3, aka DXT4 and DXT5. */5828U, /*!< BC4. */58316U, /*!< BC5. */58416U, /*!< BC6h HDR format. */58516U, /*!< BC7. */5868U, /*!< ETC2 no alpha. */5878U, /*!< ETC2 punch-through alpha. */58816U, /*!< ETC2 independent alpha. */5898U, /*!< R11 ETC2 single-channel. */59016U, /*!< R11G11 ETC2 dual-channel. */59116U, /*!< ASTC. */5928U, /*!< ETC1S. */5938U, /*!< PVRTC. */5948U /*!< PVRTC2. */595};596597/**598* @~English599* @brief Create a Data Format Descriptor for a compressed format.600*601* @param compScheme Vulkan-style compression scheme enumeration.602* @param bwidth Block width in texel coordinates.603* @param bheight Block height in texel coordinates.604* @param bdepth Block depth in texel coordinates.605* @author Mark Callow, Edgewise Consulting.606* @param suffix Indicates the format suffix for the type.607*608* @return A data format descriptor in malloc'd data. The caller is responsible609* for freeing the descriptor.610**/611uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth,612enum VkSuffix suffix)613{614uint32_t *DFD = 0;615uint32_t numSamples = compSampleCount[compScheme];616uint32_t* BDFD;617uint32_t *sample;618uint32_t channel;619// Use union to avoid type-punning complaints from gcc optimizer620// with -Wall.621union {622uint32_t i;623float f;624} lower, upper;625626DFD = (uint32_t *) malloc(sizeof(uint32_t) *627(1 + KHR_DF_WORD_SAMPLESTART +628numSamples * KHR_DF_WORD_SAMPLEWORDS));629BDFD = DFD+1;630DFD[0] = sizeof(uint32_t) *631(1 + KHR_DF_WORD_SAMPLESTART +632numSamples * KHR_DF_WORD_SAMPLEWORDS);633BDFD[KHR_DF_WORD_VENDORID] =634(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |635(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);636BDFD[KHR_DF_WORD_VERSIONNUMBER] =637(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |638(((uint32_t)sizeof(uint32_t) *639(KHR_DF_WORD_SAMPLESTART +640numSamples * KHR_DF_WORD_SAMPLEWORDS)641<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));642BDFD[KHR_DF_WORD_MODEL] =643((compModelMapping[compScheme] << KHR_DF_SHIFT_MODEL) |644(KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) | /* Assumed */645(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));646647if (suffix == s_SRGB) {648BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;649} else {650BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;651}652BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] =653(bwidth - 1) | ((bheight - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1) | ((bdepth - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION2);654/* bytesPlane0 = bytes, bytesPlane3..1 = 0 */655BDFD[KHR_DF_WORD_BYTESPLANE0] = compBytes[compScheme];656BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */657658sample = BDFD + KHR_DF_WORD_SAMPLESTART;659channel = compFirstChannel[compScheme];660channel = setChannelFlags(channel, suffix);661662sample[KHR_DF_SAMPLEWORD_BITOFFSET] =663(0 << KHR_DF_SAMPLESHIFT_BITOFFSET) |664((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |665(channel << KHR_DF_SAMPLESHIFT_CHANNELID);666667sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;668switch (suffix) {669case s_UNORM:670case s_SRGB:671default:672upper.i = 0xFFFFFFFFU;673lower.i = 0U;674break;675case s_SNORM:676upper.i = 0x7FFFFFFF;677lower.i = ~upper.i;678break;679case s_USCALED:680case s_UINT:681upper.i = 1U;682lower.i = 0U;683break;684case s_SSCALED:685case s_SINT:686upper.i = 1U;687lower.i = ~0U;688break;689case s_SFLOAT:690upper.f = 1.0f;691lower.f = -1.0f;692break;693case s_UFLOAT:694upper.f = 1.0f;695lower.f = 0.0f;696break;697}698sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;699sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;700701if (compSampleCount[compScheme] > 1) {702sample += KHR_DF_WORD_SAMPLEWORDS;703channel = compSecondChannel[compScheme];704channel = setChannelFlags(channel, suffix);705706sample[KHR_DF_SAMPLEWORD_BITOFFSET] =707(compSecondChannelOffset[compScheme] << KHR_DF_SAMPLESHIFT_BITOFFSET) |708((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |709(channel << KHR_DF_SAMPLESHIFT_CHANNELID);710711sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;712713sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;714sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;715}716return DFD;717}718719/**720* @~English721* @brief Create a Data Format Descriptor for a depth-stencil format.722*723* @param depthBits The numeber of bits in the depth channel.724* @param stencilBits The numeber of bits in the stencil channel.725* @param sizeBytes The total byte size of the texel.726*727* @return A data format descriptor in malloc'd data. The caller is responsible728* for freeing the descriptor.729**/730uint32_t *createDFDDepthStencil(int depthBits,731int stencilBits,732int sizeBytes)733{734/* N.B. Little-endian is assumed. */735uint32_t *DFD = 0;736DFD = writeHeader((depthBits > 0) + (stencilBits > 0),737sizeBytes, s_UNORM, i_NON_COLOR);738739/* Handle the special case of D24_UNORM_S8_UINT where the order of the740channels is flipped by putting stencil in the LSBs. */741if (depthBits == 24 && stencilBits == 8) {742writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL,7438, 0,7441, 1, s_UINT);745writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_DEPTH,74624, 8,7471, 1, s_UNORM);748return DFD;749}750751if (depthBits == 32) {752writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,75332, 0,7541, 1, s_SFLOAT);755} else if (depthBits > 0) {756writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,757depthBits, 0,7581, 1, s_UNORM);759}760if (stencilBits > 0) {761if (depthBits > 0) {762writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_STENCIL,763stencilBits, depthBits,7641, 1, s_UINT);765} else {766writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL,767stencilBits, 0,7681, 1, s_UINT);769}770}771return DFD;772}773774/**775* @~English776* @brief Create a Data Format Descriptor for an alpha-only format.777*778* @param bigEndian Set to 1 for big-endian byte ordering and7790 for little-endian byte ordering.780* @param bytes The number of bytes per channel.781* @param suffix Indicates the format suffix for the type.782*783* @return A data format descriptor in malloc'd data. The caller is responsible784* for freeing the descriptor.785**/786uint32_t *createDFDAlpha(int bigEndian, int bytes,787enum VkSuffix suffix) {788uint32_t *DFD;789int channel = 3; /* alpha channel */790if (bigEndian) {791int channelByte;792/* Number of samples = number of channels * bytes per channel */793DFD = writeHeader(bytes, bytes, suffix, i_COLOR);794/* Loop over the bytes that constitute a channel */795for (channelByte = 0; channelByte < bytes; ++channelByte) {796writeSample(DFD, channelByte, channel,7978, 8 * (bytes - channelByte - 1),798channelByte == bytes-1, channelByte == 0, suffix);799}800} else { /* Little-endian */801/* One sample per channel */802DFD = writeHeader(1, bytes, suffix, i_COLOR);803writeSample(DFD, 0, channel,8048 * bytes, 0,8051, 1, suffix);806}807return DFD;808}809810811