summaryrefslogtreecommitdiffstats
path: root/thirdparty/libktx/lib/dfdutils/interpretdfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/libktx/lib/dfdutils/interpretdfd.c')
-rw-r--r--thirdparty/libktx/lib/dfdutils/interpretdfd.c113
1 files changed, 84 insertions, 29 deletions
diff --git a/thirdparty/libktx/lib/dfdutils/interpretdfd.c b/thirdparty/libktx/lib/dfdutils/interpretdfd.c
index 6d25f33a1b..b58a79fb43 100644
--- a/thirdparty/libktx/lib/dfdutils/interpretdfd.c
+++ b/thirdparty/libktx/lib/dfdutils/interpretdfd.c
@@ -29,18 +29,37 @@ static uint32_t bit_ceil(uint32_t x) {
* @~English
* @brief Interpret a Data Format Descriptor for a simple format.
*
- * @param 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 Information about the decoded red channel or the depth channel, if any.
- * @param G Information about the decoded green channel or the stencil channel, if any.
- * @param B Information about the decoded blue channel, if any.
- * @param A Information about the decoded alpha channel, if any.
- * @param wordBytes Byte size of the channels (unpacked) or total size (packed).
+ * 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,
@@ -49,14 +68,6 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
InterpretedDFDChannel *A,
uint32_t *wordBytes)
{
- /* We specifically handle "simple" cases that can be translated */
- /* to things a GPU can access. For simplicity, we also ignore */
- /* 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). */
- /* We also just worry about layout and ignore sRGB, since that's */
- /* trivial to extract anyway. */
-
/* 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;
@@ -78,7 +89,7 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
/* First rule out the multiple planes case (trivially) */
/* - that is, we check that only bytesPlane0 is non-zero. */
- /* This means we don't handle YUV even if the API could. */
+ /* 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)
@@ -104,6 +115,8 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
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.
@@ -116,13 +129,23 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
// (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.
- const bool isNormalized = isFloat ?
- *(float*) (void*) &BDFDB[KHR_DF_WORD_SAMPLESTART +
+ 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 :
- KHR_DFDSVAL(BDFDB, i, SAMPLEUPPER) != 1U;
-
+ 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.
@@ -132,9 +155,10 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
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 (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_YUVSDA) {
+ if (model == KHR_DF_MODEL_YUVSDA) {
result |= i_NORMALIZED_FORMAT_BIT;
result |= i_COMPRESSED_FORMAT_BIT;
result |= i_YUVSDA_FORMAT_BIT;
@@ -165,7 +189,7 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
*wordBytes = ((result & i_PACKED_FORMAT_BIT) ? 4 : 1) * bit_ceil(largestSampleSize) / 8;
} else if (KHR_DFDVAL(BDFDB, MODEL) == KHR_DF_MODEL_RGBSDA) {
- /* We only pay attention to sRGB. */
+ /* 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. */
@@ -175,7 +199,11 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
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)) {
@@ -206,6 +234,9 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
}
}
+ /* 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, */
@@ -288,8 +319,20 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
currentByteOffset = sampleByteOffset;
currentBitLength = sampleBitLength;
if (sampleChannelPtr->size) {
- /* Uh-oh, we've seen this channel before. */
- return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS;
+ 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. */
@@ -378,8 +421,20 @@ enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
currentByteOffset = sampleByteOffset;
currentByteLength = sampleByteLength;
if (sampleChannelPtr->size) {
- /* Uh-oh, we've seen this channel before. */
- return i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS;
+ 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. */