Download third_party/ktx-src/external/dfdutils/interpretdfd.c from kimjunhan/vkgs-sim: direct link, hf CLI and curl.
- Browser
- Download file 22.4 kB
-
https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/third_party/ktx-src/external/dfdutils/interpretdfd.c
- Command line
-
hf download hf://kimjunhan/vkgs-sim/third_party/ktx-src/external/dfdutils/interpretdfd.c
-
curl -L -o interpretdfd.c https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/third_party/ktx-src/external/dfdutils/interpretdfd.c
22.4 kB
| /* -*- tab-width: 4; -*- */ | |
| /* vi: set sw=2 ts=4 expandtab: */ | |
| /* Copyright 2019-2020 The Khronos Group Inc. | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| /** | |
| * @file | |
| * @~English | |
| * @brief Utility for interpreting a data format descriptor. | |
| * @author Andrew Garrard | |
| */ | |
| static uint32_t bit_ceil(uint32_t x) { | |
| x -= 1; | |
| for (uint32_t i = 0; i < sizeof(x) * 8; ++i) | |
| if (1u << i > x) | |
| return 1u << i; | |
| return 0; | |
| } | |
| /** | |
| * @~English | |
| * @brief Interpret a Data Format Descriptor for a simple format. | |
| * | |
| * Handles "simple" cases that can be translated to things a GPU can access. | |
| * For simplicity, it ignores the compressed formats, which are generally a | |
| * single sample (and I believe are all defined to be little-endian in their | |
| * in-memory layout, even if some documentation confuses this). Focuses on | |
| * the layout and ignores sRGB except for reporting if that is the transfer | |
| * function by way of a bit in the returned value. | |
| * | |
| * @param[in] DFD Pointer to a Data Format Descriptor to interpret, | |
| * described as 32-bit words in native endianness. | |
| * Note that this is the whole descriptor, not just | |
| * the basic descriptor block. | |
| * @param R[in,out] Pointer to struct to receive information about the decoded | |
| * red channel, the Y channel, if YUV, or the depth channel, | |
| * if any. | |
| * @param G[in,out] Pointer to struct to receive information about the decoded | |
| * green channel, the U (Cb) channel, if YUV, or the stencil | |
| * channel, if any. | |
| * @param B[in,out] Pointer to struct to receive information about the decoded | |
| * blue channel, if any or the V (Cr) channel, if YUV. | |
| * @param A[in,out] Pointer to struct to receive information about the decoded | |
| * alpha channel, if any or the second Y channel, if YUV and | |
| * any. | |
| * @param wordBytes[in,out] Pointer to a uint32_t to receive the byte size of | |
| * the channels (unpacked) or total size (packed). | |
| * | |
| * @return An enumerant describing the decoded value, | |
| * or an error code in case of failure. | |
| * | |
| * The mapping of YUV channels to the parameter names used here is based on | |
| * the channel ids in @c khr_df.h and is different from the convention used | |
| * in format names in the Vulkan specification where G == Y, R = Cr and B = Cb. | |
| **/ | |
| enum InterpretDFDResult interpretDFD(const uint32_t *DFD, | |
| InterpretedDFDChannel *R, | |
| InterpretedDFDChannel *G, | |
| InterpretedDFDChannel *B, | |
| InterpretedDFDChannel *A, | |
| uint32_t *wordBytes) | |
| { | |
| /* DFD points to the whole descriptor, not the basic descriptor block. */ | |
| /* Make everything else relative to the basic descriptor block. */ | |
| const uint32_t *BDFDB = DFD+1; | |
| uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); | |
| if (numSamples == 0) | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| int determinedEndianness = 0; | |
| enum InterpretDFDResult result = 0; /* Build this up incrementally. */ | |
| bool isDepthStencil = false; | |
| /* Clear these so following code doesn't get confused. */ | |
| R->offset = R->size = 0; | |
| G->offset = G->size = 0; | |
| B->offset = B->size = 0; | |
| A->offset = A->size = 0; | |
| /* First rule out the multiple planes case (trivially) */ | |
| /* - that is, we check that only bytesPlane0 is non-zero. */ | |
| /* This means we don't handle multi-plane YUV, even if the API could. */ | |
| /* (We rely on KHR_DF_WORD_BYTESPLANE0..3 being the same and */ | |
| /* KHR_DF_WORD_BYTESPLANE4..7 being the same as a short cut.) */ | |
| if ((BDFDB[KHR_DF_WORD_BYTESPLANE0] & ~KHR_DF_MASK_BYTESPLANE0) | |
| || BDFDB[KHR_DF_WORD_BYTESPLANE4]) return i_UNSUPPORTED_MULTIPLE_PLANES; | |
| /* If this is a packed format, we work out our offsets differently. */ | |
| /* We assume a packed format has channels that aren't byte-aligned. */ | |
| /* If we have a format in which every channel is byte-aligned *and* packed, */ | |
| /* we have the RGBA/ABGR ambiguity; we *probably* don't want the packed */ | |
| /* version in this case, and if hardware has to pack it and swizzle, */ | |
| /* that's up to the hardware to special-case. */ | |
| for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { | |
| uint32_t offset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); | |
| uint32_t length = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; | |
| if ((offset & 0x7U) || ((offset + length) & 0x7U)) { | |
| result |= i_PACKED_FORMAT_BIT; | |
| /* Once we're packed, we're packed, no need to keep checking. */ | |
| break; | |
| } | |
| } | |
| // Check data types. | |
| bool hasSigned = false; | |
| bool hasFloat = false; | |
| bool hasNormalized = false; | |
| bool hasFixed = false; | |
| khr_df_model_e model = KHR_DFDVAL(BDFDB, MODEL); | |
| // Note: We're ignoring 9995, which is weird and worth special-casing | |
| // rather than trying to generalise to all float formats. | |
| for (uint32_t i = 0; i < numSamples; ++i) { | |
| const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; | |
| const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; | |
| // We define "unnormalized" as "sample_upper = 1" or "sample_upper = 1.0f". | |
| // We don't check whether any non-1 normalization value is correct | |
| // (i.e. set to the maximum bit value, and check min value) on | |
| // the assumption that we're looking at a format which *came* from | |
| // an API we can support. | |
| bool isFixed; | |
| bool isNormalized; | |
| if (isFloat) { | |
| isNormalized = *(float*) (void*) &BDFDB[KHR_DF_WORD_SAMPLESTART + | |
| KHR_DF_WORD_SAMPLEWORDS * i + | |
| KHR_DF_SAMPLEWORD_SAMPLEUPPER] != 1.0f; | |
| isFixed = false; | |
| } else { | |
| uint32_t sampleUpper = KHR_DFDSVAL(BDFDB, i, SAMPLEUPPER); | |
| uint32_t maxVal = 1U << KHR_DFDSVAL(BDFDB, i, BITLENGTH); | |
| if (!isSigned) maxVal <<= 1; | |
| maxVal--; | |
| isFixed = 1U < sampleUpper && sampleUpper < maxVal; | |
| isNormalized = !isFixed && sampleUpper != 1U; | |
| } | |
| hasSigned |= isSigned; | |
| hasFixed |= isFixed; | |
| hasFloat |= isFloat; | |
| // By our definition the normalizedness of a single bit channel (like in RGBA 5:5:5:1) | |
| // is ambiguous. Ignore these during normalized checks. | |
| if (KHR_DFDSVAL(BDFDB, i, BITLENGTH) > 0) | |
| hasNormalized |= isNormalized; | |
| } | |
| result |= hasSigned ? i_SIGNED_FORMAT_BIT : 0; | |
| result |= hasFloat ? i_FLOAT_FORMAT_BIT : 0; | |
| result |= hasNormalized ? i_NORMALIZED_FORMAT_BIT : 0; | |
| result |= hasFixed ? i_FIXED_FORMAT_BIT : 0; | |
| // Checks based on color model | |
| if (model == KHR_DF_MODEL_YUVSDA) { | |
| result |= i_NORMALIZED_FORMAT_BIT; | |
| result |= i_COMPRESSED_FORMAT_BIT; | |
| result |= i_YUVSDA_FORMAT_BIT; | |
| for (uint32_t i = 0; i < numSamples; ++i) { | |
| switch (KHR_DFDSVAL(BDFDB, i, CHANNELID)) { | |
| case KHR_DF_CHANNEL_YUVSDA_Y: | |
| case KHR_DF_CHANNEL_YUVSDA_U: | |
| case KHR_DF_CHANNEL_YUVSDA_V: | |
| case KHR_DF_CHANNEL_YUVSDA_A: | |
| break; | |
| case KHR_DF_CHANNEL_YUVSDA_DEPTH: | |
| case KHR_DF_CHANNEL_YUVSDA_STENCIL: | |
| isDepthStencil = true; | |
| break; | |
| default: | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| } | |
| // Determine wordBytes | |
| uint32_t largestSampleSize = 0; | |
| for (uint32_t i = 0; i < numSamples; ++i) { | |
| uint32_t length = KHR_DFDSVAL(BDFDB, i, BITLENGTH) + 1; | |
| if (largestSampleSize < length) | |
| largestSampleSize = length; | |
| } | |
| *wordBytes = ((result & i_PACKED_FORMAT_BIT) ? 4 : 1) * bit_ceil(largestSampleSize) / 8; | |
| } else if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_RGBSDA) { | |
| /* Check if transfer is sRGB. */ | |
| if (KHR_DFDVAL(BDFDB, TRANSFER) == KHR_DF_TRANSFER_SRGB) result |= i_SRGB_FORMAT_BIT; | |
| /* We only support samples at coordinate 0,0,0,0. */ | |
| /* (We could confirm this from texel_block_dimensions in 1.2, but */ | |
| /* the interpretation might change in later versions.) */ | |
| for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { | |
| if (KHR_DFDSVAL(BDFDB, sampleCounter, SAMPLEPOSITION_ALL)) | |
| return i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS; | |
| } | |
| } | |
| if (model == KHR_DF_MODEL_RGBSDA || model == KHR_DF_MODEL_YUVSDA) { | |
| /* The values of the DEPTH and STENCIL tokens are the same for */ | |
| /* RGBSDA and YUVSDA. */ | |
| /* For Depth/Stencil formats mixed channels are allowed */ | |
| for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { | |
| switch (KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID)) { | |
| case KHR_DF_CHANNEL_RGBSDA_DEPTH: | |
| case KHR_DF_CHANNEL_RGBSDA_STENCIL: | |
| isDepthStencil = true; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| // Check for mixed channels | |
| if (!isDepthStencil) { | |
| for (uint32_t i = 0; i < numSamples; ++i) { | |
| const bool isSigned = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED) != 0; | |
| const bool isFloat = (KHR_DFDSVAL(BDFDB, i, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT) != 0; | |
| if (isSigned != hasSigned) | |
| return i_UNSUPPORTED_MIXED_CHANNELS; | |
| if (isFloat != hasFloat) | |
| return i_UNSUPPORTED_MIXED_CHANNELS; | |
| // Note: We don't check for inconsistent normalization, because | |
| // channels composed of multiple samples will have 0 in the | |
| // lower/upper range. Single bit channels are also ambiguous. | |
| // This heuristic should handle 64-bit integers, too. | |
| } | |
| } | |
| /* This all relies on the channel id values for RGB being equal to */ | |
| /* those for YUV. */ | |
| /* Remember: the canonical ordering of samples is to start with */ | |
| /* the lowest bit of the channel/location which touches bit 0 of */ | |
| /* the data, when the latter is concatenated in little-endian order, */ | |
| /* and then progress until all the bits of that channel/location */ | |
| /* have been processed. Multiple channels sharing the same source */ | |
| /* bits are processed in channel ID order. (I should clarify this */ | |
| /* for partially-shared data, but it doesn't really matter so long */ | |
| /* as everything is consecutive, except to make things canonical.) */ | |
| /* Note: For standard formats we could determine big/little-endianness */ | |
| /* simply from whether the first sample starts in bit 0; technically */ | |
| /* it's possible to have a format with unaligned channels wherein the */ | |
| /* first channel starts at bit 0 and is one byte, yet other channels */ | |
| /* take more bytes or aren't aligned (e.g. D24S8), but this should be */ | |
| /* irrelevant for the formats that we support. */ | |
| if ((result & i_PACKED_FORMAT_BIT)) { | |
| /* A packed format. */ | |
| uint32_t currentChannel = ~0U; /* Don't start matched. */ | |
| uint32_t currentBitOffset = 0; | |
| uint32_t currentByteOffset = 0; | |
| uint32_t currentBitLength = 0; | |
| *wordBytes = (BDFDB[KHR_DF_WORD_BYTESPLANE0] & 0xFFU); | |
| for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { | |
| uint32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET); | |
| uint32_t sampleByteOffset = sampleBitOffset >> 3U; | |
| /* The sample bitLength field stores the bit length - 1. */ | |
| uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1; | |
| uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); | |
| InterpretedDFDChannel *sampleChannelPtr; | |
| switch (sampleChannel) { | |
| case KHR_DF_CHANNEL_RGBSDA_RED: | |
| sampleChannelPtr = R; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_GREEN: | |
| sampleChannelPtr = G; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_BLUE: | |
| sampleChannelPtr = B; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_DEPTH: | |
| sampleChannelPtr = R; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_STENCIL: | |
| sampleChannelPtr = G; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_ALPHA: | |
| sampleChannelPtr = A; | |
| break; | |
| default: | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| if (sampleChannel == currentChannel) { | |
| /* Continuation of the same channel. */ | |
| /* Since a big (>32-bit) channel isn't "packed", */ | |
| /* this should only happen in big-endian, or if */ | |
| /* we have a wacky format that we won't support. */ | |
| if (sampleByteOffset == currentByteOffset - 1U && /* One byte earlier */ | |
| ((currentBitOffset + currentBitLength) & 7U) == 0 && /* Already at the end of a byte */ | |
| (sampleBitOffset & 7U) == 0) { /* Start at the beginning of the byte */ | |
| /* All is good, continue big-endian. */ | |
| /* N.B. We shouldn't be here if we decided we were little-endian, */ | |
| /* so we don't bother to check that disagreement. */ | |
| result |= i_BIG_ENDIAN_FORMAT_BIT; | |
| determinedEndianness = 1; | |
| } else { | |
| /* Oh dear. */ | |
| /* We could be little-endian, but not with any standard format. */ | |
| /* More likely we've got something weird that we can't support. */ | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| /* Remember where we are. */ | |
| currentBitOffset = sampleBitOffset; | |
| currentByteOffset = sampleByteOffset; | |
| currentBitLength = sampleBitLength; | |
| /* Accumulate the bit length. */ | |
| sampleChannelPtr->size += sampleBitLength; | |
| } else { | |
| /* Everything is new. Hopefully. */ | |
| currentChannel = sampleChannel; | |
| currentBitOffset = sampleBitOffset; | |
| currentByteOffset = sampleByteOffset; | |
| currentBitLength = sampleBitLength; | |
| if (sampleChannelPtr->size) { | |
| if (model == KHR_DF_MODEL_YUVSDA && sampleChannel == KHR_DF_CHANNEL_YUVSDA_Y) { | |
| if (sampleChannelPtr == R) { | |
| /* We've got another Y channel. Record details in A. */ | |
| if (A->size == 0) { | |
| sampleChannelPtr = A; | |
| } else { | |
| /* Uh-oh, we've already got a second Y or an alpha channel. */ | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| } | |
| } else { | |
| /* Uh-oh, we've seen this channel before. */ | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| } | |
| /* For now, record the bit offset in little-endian terms, */ | |
| /* because we may not know to reverse it yet. */ | |
| sampleChannelPtr->offset = sampleBitOffset; | |
| sampleChannelPtr->size = sampleBitLength; | |
| } | |
| } | |
| if ((result & i_BIG_ENDIAN_FORMAT_BIT)) { | |
| /* Our bit offsets to bit 0 of each channel are in little-endian terms. */ | |
| /* We need to do a byte swap to work out where they should be. */ | |
| /* We assume, for sanity, that byte sizes are a power of two for this. */ | |
| uint32_t offsetMask = (*wordBytes - 1U) << 3U; | |
| R->offset ^= offsetMask; | |
| G->offset ^= offsetMask; | |
| B->offset ^= offsetMask; | |
| A->offset ^= offsetMask; | |
| } | |
| } else { | |
| /* Not a packed format. */ | |
| /* Everything is byte-aligned. */ | |
| /* Question is whether there multiple samples per channel. */ | |
| uint32_t currentChannel = ~0U; /* Don't start matched. */ | |
| uint32_t currentByteOffset = 0; | |
| uint32_t currentByteLength = 0; | |
| for (uint32_t sampleCounter = 0; sampleCounter < numSamples; ++sampleCounter) { | |
| uint32_t sampleByteOffset = KHR_DFDSVAL(BDFDB, sampleCounter, BITOFFSET) >> 3U; | |
| uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleCounter, BITLENGTH) + 1) >> 3U; | |
| uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleCounter, CHANNELID); | |
| InterpretedDFDChannel *sampleChannelPtr; | |
| switch (sampleChannel) { | |
| case KHR_DF_CHANNEL_RGBSDA_RED: | |
| sampleChannelPtr = R; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_GREEN: | |
| sampleChannelPtr = G; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_BLUE: | |
| sampleChannelPtr = B; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_DEPTH: | |
| sampleChannelPtr = R; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_STENCIL: | |
| sampleChannelPtr = G; | |
| break; | |
| case KHR_DF_CHANNEL_RGBSDA_ALPHA: | |
| sampleChannelPtr = A; | |
| break; | |
| default: | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| if (sampleChannel == currentChannel) { | |
| /* Continuation of the same channel. */ | |
| /* Either big-endian, or little-endian with a very large channel. */ | |
| if (sampleByteOffset == currentByteOffset - 1) { /* One byte earlier */ | |
| if (determinedEndianness && !(result & i_BIG_ENDIAN_FORMAT_BIT)) { | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| /* All is good, continue big-endian. */ | |
| result |= i_BIG_ENDIAN_FORMAT_BIT; | |
| determinedEndianness = 1; | |
| /* Update the start */ | |
| sampleChannelPtr->offset = sampleByteOffset; | |
| } else if (sampleByteOffset == currentByteOffset + currentByteLength) { | |
| if (determinedEndianness && (result & i_BIG_ENDIAN_FORMAT_BIT)) { | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| /* All is good, continue little-endian. */ | |
| determinedEndianness = 1; | |
| } else { | |
| /* Oh dear. */ | |
| /* We could be little-endian, but not with any standard format. */ | |
| /* More likely we've got something weird that we can't support. */ | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| /* Remember where we are. */ | |
| currentByteOffset = sampleByteOffset; | |
| currentByteLength = sampleByteLength; | |
| /* Accumulate the byte length. */ | |
| sampleChannelPtr->size += sampleByteLength; | |
| /* Assume these are all the same. */ | |
| *wordBytes = sampleChannelPtr->size; | |
| } else { | |
| /* Everything is new. Hopefully. */ | |
| currentChannel = sampleChannel; | |
| currentByteOffset = sampleByteOffset; | |
| currentByteLength = sampleByteLength; | |
| if (sampleChannelPtr->size) { | |
| if (model == KHR_DF_MODEL_YUVSDA && sampleChannel == KHR_DF_CHANNEL_YUVSDA_Y) { | |
| if (sampleChannelPtr == R) { | |
| /* We've got another Y channel. Record details in A. */ | |
| if (A->size == 0) { | |
| sampleChannelPtr = A; | |
| } else { | |
| /* Uh-oh, we've already got a second Y or an alpha channel. */ | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| } | |
| } else { | |
| /* Uh-oh, we've seen this channel before. */ | |
| return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS; | |
| } | |
| } | |
| /* For now, record the byte offset in little-endian terms, */ | |
| /* because we may not know to reverse it yet. */ | |
| sampleChannelPtr->offset = sampleByteOffset; | |
| sampleChannelPtr->size = sampleByteLength; | |
| /* Assume these are all the same. */ | |
| *wordBytes = sampleByteLength; | |
| } | |
| } | |
| } | |
| } else { | |
| return i_UNSUPPORTED_CHANNEL_TYPES; | |
| } | |
| if (isDepthStencil) { | |
| /* For Depth/Stencil formats wordBytes is determined by the required alignment of */ | |
| /* the larger channel. */ | |
| uint32_t largerSize = R->size > G->size ? R->size : G->size; | |
| *wordBytes = bit_ceil(largerSize); | |
| } | |
| return result; | |
| } | |