/* -*- 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 Utilities for querying info from a data format descriptor. * @author Mark Callow */ #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <KHR/khr_df.h> #include "dfd.h" /** * @~English * @brief Get the number and size of the image components from a DFD. * * This simplified function is for use only with the DFDs for unpacked * formats which means all components have the same size. * * @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 numComponents pointer to a 32-bit word in which the number of components will be written. * @param componentByteLength pointer to a 32-bit word in which the size of a component in bytes will be written. */ void getDFDComponentInfoUnpacked(const uint32_t* DFD, uint32_t* numComponents, uint32_t* componentByteLength) { const uint32_t *BDFDB = DFD+1; uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); uint32_t sampleNumber; uint32_t currentChannel = ~0U; /* Don't start matched. */ /* This is specifically for unpacked formats which means the size of */ /* each component is the same. */ *numComponents = 0; for (sampleNumber = 0; sampleNumber < numSamples; ++sampleNumber) { uint32_t sampleByteLength = (KHR_DFDSVAL(BDFDB, sampleNumber, BITLENGTH) + 1) >> 3U; uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleNumber, CHANNELID); if (sampleChannel == currentChannel) { /* Continuation of the same channel. */ /* Accumulate the byte length. */ *componentByteLength += sampleByteLength; } else { /* Everything is new. Hopefully. */ currentChannel = sampleChannel; (*numComponents)++; *componentByteLength = sampleByteLength; } } } /** * @~English * @brief Return the number of "components" in the data. * * Calculates the number of uniques samples in the DFD by combining * multiple samples for the same channel. For uncompressed colorModels * this is the same as the number of components in the image data. For * block-compressed color models this is the number of samples in * the color model, typically 1 and in a few cases 2. * * @param DFD Pointer to a Data Format Descriptor for which, * described as 32-bit words in native endianness. * Note that this is the whole descriptor, not just * the basic descriptor block. */ uint32_t getDFDNumComponents(const uint32_t* DFD) { const uint32_t *BDFDB = DFD+1; uint32_t currentChannel = ~0U; /* Don't start matched. */ uint32_t numComponents = 0; uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); uint32_t sampleNumber; for (sampleNumber = 0; sampleNumber < numSamples; ++sampleNumber) { uint32_t sampleChannel = KHR_DFDSVAL(BDFDB, sampleNumber, CHANNELID); if (sampleChannel != currentChannel) { numComponents++; currentChannel = sampleChannel; } } return numComponents; } /** * @~English * @brief Reconstruct the value of bytesPlane0 from sample info. * * Reconstruct the value for data that has been variable-rate compressed so * has bytesPlane0 = 0. For DFDs that are valid for KTX files. Little-endian * data only and no multi-plane formats. * * @param DFD Pointer to a Data Format Descriptor for which, * described as 32-bit words in native endianness. * Note that this is the whole descriptor, not just * the basic descriptor block. */ uint32_t reconstructDFDBytesPlane0FromSamples(const uint32_t* DFD) { const uint32_t *BDFDB = DFD+1; uint32_t numSamples = KHR_DFDSAMPLECOUNT(BDFDB); uint32_t sampleNumber; uint32_t bitsPlane0 = 0; int32_t largestOffset = 0; uint32_t sampleNumberWithLargestOffset = 0; // Special case these depth{,-stencil} formats. The unused bits are // in the MSBs so have no visibility in the DFD therefore the max offset // algorithm below returns a value that is too small. if (KHR_DFDSVAL(BDFDB, 0, CHANNELID) == KHR_DF_CHANNEL_COMMON_DEPTH) { if (numSamples == 1) { if (KHR_DFDSVAL(BDFDB, 0, BITLENGTH) + 1 == 24) { // X8_D24_UNORM_PACK32, return 4; } } else if (numSamples == 2) { if (KHR_DFDSVAL(BDFDB, 0, BITLENGTH) + 1 == 16) { // D16_UNORM_S8_UINT return 4; } if (KHR_DFDSVAL(BDFDB, 0, BITLENGTH) + 1 == 32 && KHR_DFDSVAL(BDFDB, 1, CHANNELID) == KHR_DF_CHANNEL_COMMON_STENCIL) { // D32_SFLOAT_S8_UINT return 8; } } } for (sampleNumber = 0; sampleNumber < numSamples; ++sampleNumber) { int32_t sampleBitOffset = KHR_DFDSVAL(BDFDB, sampleNumber, BITOFFSET); if (sampleBitOffset > largestOffset) { largestOffset = sampleBitOffset; sampleNumberWithLargestOffset = sampleNumber; } } /* The sample bitLength field stores the bit length - 1. */ uint32_t sampleBitLength = KHR_DFDSVAL(BDFDB, sampleNumberWithLargestOffset, BITLENGTH) + 1; bitsPlane0 = largestOffset + sampleBitLength; return bitsPlane0 >> 3U; } /** * @~English * @brief Reconstruct the value of bytesPlane0 from sample info. * * @see reconstructDFDBytesPlane0FromSamples for details. * @deprecated For backward comparibility only. Use * reconstructDFDBytesPlane0FromSamples. * * @param DFD Pointer to a Data Format Descriptor for which, * described as 32-bit words in native endianness. * Note that this is the whole descriptor, not just * the basic descriptor block. * @param bytesPlane0 pointer to a 32-bit word in which the recreated * value of bytesPlane0 will be written. */ void recreateBytesPlane0FromSampleInfo(const uint32_t* DFD, uint32_t* bytesPlane0) { *bytesPlane0 = reconstructDFDBytesPlane0FromSamples(DFD); }