317 lines
16 KiB
C
317 lines
16 KiB
C
/* Copyright 2019-2020 The Khronos Group Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <khr_df.h>
|
|
|
|
uint32_t *endSwapDFD(const uint32_t *DFD, size_t wordByteSize)
|
|
{
|
|
/* Provides a DFD for what the buffer described by BDFD would be if it were end-swapped. */
|
|
/* The DFD itself is described in uint32_t terms, so you're on your own for that. */
|
|
/* This does assume that there's only a single location for each channel, and a single plane. */
|
|
|
|
/* Build a representation of the bits of each channel in order, recording whence they came. */
|
|
/* Then end-swap the locations and write a DFD for the result. */
|
|
/* Worst case channel size is the number of bytes in the plane. */
|
|
const uint32_t *BDFD = DFD+1;
|
|
const uint32_t worstCaseBits = 8 * KHR_DFDVAL(BDFD, BYTESPLANE0);
|
|
/* Treat each channel and flag separately. */
|
|
uint32_t *virtualSampleBitLocations[256] = {};
|
|
uint32_t numBitsPerVirtualSample[256] = {};
|
|
uint32_t *lowerValues[256] = {};
|
|
uint32_t *upperValues[256] = {};
|
|
uint32_t lowerSign[256] = {};
|
|
uint32_t upperSign[256] = {};
|
|
uint32_t *samplesPerBit[4] = {};
|
|
uint32_t sampleCounter;
|
|
uint32_t previousChannel = 0x100; /* Impossible value */
|
|
uint32_t channelOffset = 0;
|
|
uint32_t swapMask = ((1U << wordByteSize) - 1U) << 3;
|
|
uint32_t previousSampleStart = 0;
|
|
uint32_t *outdfd;
|
|
uint32_t *outbdb;
|
|
/* Note: We assume that all samples of the same channel
|
|
are the same virtual sample; to be fully general-purpose
|
|
we should extend this to support distinguishing virtual
|
|
samples by qualifier and position. */
|
|
for (sampleCounter = 0; sampleCounter < KHR_DFDSAMPLECOUNT(BDFD); ++sampleCounter) {
|
|
uint32_t thisSampleChannelId =
|
|
KHR_DFDSVAL(BDFD, sampleCounter, CHANNELID) |
|
|
KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS);
|
|
uint32_t bitCounter;
|
|
uint32_t sampleBitBase = KHR_DFDSVAL(BDFD, sampleCounter, BITOFFSET);
|
|
if (numBitsPerVirtualSample[thiSampleChannelId] == 0) {
|
|
/* Need to allocate storage for this virtual sample */
|
|
}
|
|
switch (thisChannel) {
|
|
case KHR_DF_CHANNEL_RGBSDA_RED:
|
|
targetChannelArray = channelR;
|
|
targetBitCount = &channelRBits;
|
|
targetLower = lowerR;
|
|
targetLowerSign = &lowerRSign;
|
|
targetUpper = upperR;
|
|
targetUpperSign = &upperRSign;
|
|
/* Assume all qualifiers are the same. */
|
|
/* N.B. This will break for, e.g., explicit exponent formats. */
|
|
redQualifiers = KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS);
|
|
break;
|
|
case KHR_DF_CHANNEL_RGBSDA_GREEN:
|
|
targetChannelArray = channelG;
|
|
targetBitCount = &channelGBits;
|
|
targetLower = lowerG;
|
|
targetLowerSign = &lowerGSign;
|
|
targetUpper = upperG;
|
|
targetUpperSign = &upperGSign;
|
|
/* Assume all qualifiers are the same. */
|
|
/* N.B. This will break for, e.g., explicit exponent formats. */
|
|
greenQualifiers = KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS);
|
|
break;
|
|
case KHR_DF_CHANNEL_RGBSDA_BLUE:
|
|
targetChannelArray = channelB;
|
|
targetBitCount = &channelBBits;
|
|
targetLower = lowerB;
|
|
targetLowerSign = &lowerBSign;
|
|
targetUpper = upperB;
|
|
targetUpperSign = &upperBSign;
|
|
/* Assume all qualifiers are the same. */
|
|
/* N.B. This will break for, e.g., explicit exponent formats. */
|
|
blueQualifiers = KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS);
|
|
break;
|
|
case KHR_DF_CHANNEL_RGBSDA_ALPHA:
|
|
targetChannelArray = channelA;
|
|
targetBitCount = &channelABits;
|
|
targetLower = lowerA;
|
|
targetLowerSign = &lowerASign;
|
|
targetUpper = upperA;
|
|
targetUpperSign = &upperASign;
|
|
/* Assume all qualifiers are the same. */
|
|
/* N.B. This will break for, e.g., explicit exponent formats. */
|
|
alphaQualifiers = KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS);
|
|
break;
|
|
default: return 0; /* Unknown/unexpected channel */
|
|
}
|
|
*targetBitCount += KHR_DFDSVAL(BDFD, sampleCounter, BITLENGTH) + 1;
|
|
if (thisChannel != previousChannel) channelOffset = 0;
|
|
for (bitCounter = 0; bitCounter < *targetBitCount; ++bitCounter, ++channelOffset) {
|
|
/* Record the bit offset whence this came */
|
|
targetChannelArray[channelOffset] = sampleBitBase + bitCounter;
|
|
/* Also need to build up min and max values. */
|
|
targetLower[channelOffset >> 5] |= (1U << (channelOffset & 0x1F)) * ((KHR_DFDSVAL(BDFD, sampleCounter, SAMPLELOWER) & (1 << bitCounter)) != 0U);
|
|
targetUpper[channelOffset >> 5] |= (1U << (channelOffset & 0x1F)) * ((KHR_DFDSVAL(BDFD, sampleCounter, SAMPLEUPPER) & (1 << bitCounter)) != 0U);
|
|
}
|
|
/* The last sample of a channel ends with any sign bit. */
|
|
/* Note: this does not properly handle exponents. */
|
|
if (KHR_DFDSVAL(BDFD, sampleCounter, QUALIFIERS) & KHR_DF_DATATYPE_SIGNED) {
|
|
*targetLowerSign = ((KHR_DFDSVAL(BDFD, sampleCounter, SAMPLELOWER) & (1 << *targetBitCount-1)) != 0U);
|
|
*targetUpperSign = ((KHR_DFDSVAL(BDFD, sampleCounter, SAMPLEUPPER) & (1 << *targetBitCount-1)) != 0U);
|
|
}
|
|
}
|
|
/* Now we have the target bit corresponding to each channel bit. */
|
|
/* Do a big-endian swap on them and fill in bitChannels. */
|
|
sampleCounter = 0;
|
|
for (previousSampleStart = 0, channelOffset = 0; channelOffset < channelRBits; ++channelOffset) {
|
|
channelR[channelOffset] ^= swapMask;
|
|
bitChannels[channelR[channelOffset]] |= 1;
|
|
/* We're going to need another sample. */
|
|
if (((channelOffset - previousSampleStart) & 0x1F) == 0 || channelR[channelOffset] != channelR[channelOffset-1] + 1) {
|
|
++sampleCounter;
|
|
previousSampleStart = channelOffset;
|
|
}
|
|
}
|
|
for (channelOffset = 0; channelOffset < channelGBits; ++channelOffset) {
|
|
channelG[channelOffset] ^= swapMask;
|
|
bitChannels[channelG[channelOffset]] |= 2;
|
|
/* We're going to need another sample. */
|
|
if (((channelOffset - previousSampleStart) & 0x1F) == 0 || channelG[channelOffset] != channelG[channelOffset-1] + 1) {
|
|
++sampleCounter;
|
|
previousSampleStart = channelOffset;
|
|
}
|
|
}
|
|
for (channelOffset = 0; channelOffset < channelBBits; ++channelOffset) {
|
|
channelB[channelOffset] ^= swapMask;
|
|
bitChannels[channelB[channelOffset]] |= 4;
|
|
/* We're going to need another sample. */
|
|
if (((channelOffset - previousSampleStart) & 0x1F) == 0 || channelB[channelOffset] != channelB[channelOffset-1] + 1) {
|
|
++sampleCounter;
|
|
previousSampleStart = channelOffset;
|
|
}
|
|
}
|
|
for (channelOffset = 0; channelOffset < channelABits; ++channelOffset) {
|
|
channelA[channelOffset] ^= swapMask;
|
|
bitChannels[channelA[channelOffset]] |= 8;
|
|
/* We're going to need another sample. */
|
|
if (((channelOffset - previousSampleStart) & 0x1F) == 0 || channelA[channelOffset] != channelA[channelOffset-1] + 1) {
|
|
++sampleCounter;
|
|
previousSampleStart = channelOffset;
|
|
}
|
|
}
|
|
|
|
/* Now we can create the DFD and populate its header. */
|
|
outdfd = (uint32_t *)malloc(sizeof(uint32_t) * (1 + KHR_DFDSIZEWORDS(sampleCounter)));
|
|
outbdb = outdfd + 1;
|
|
*dfd = sizeof(uint32_t) * (1 + KHR_DFDSIZEWORDS(sampleCounter));
|
|
/* Note that this is a fairly inefficient way of doing things unless */
|
|
/* the compiler is really good at removing redundant bit masking, */
|
|
/* but in the interests of readability it probably doesn't matter. */
|
|
KHR_DFDSETVAL(outbdb, VENDORID, KHR_DF_VENDORID_KHRONOS);
|
|
KHR_DFDSETVAL(outbdb, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT);
|
|
KHR_DFDSETVAL(outbdb, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_1_3);
|
|
KHR_DFDSETVAL(outbdb, DESCRIPTORBLOCKSIZE, (sizeof(uint32_t) * KHR_DFDSIZEWORDS(sampleCounter)));
|
|
KHR_DFDSETVAL(outbdb, MODEL, KHR_DF_MODEL_RGBSDA); /* Or this function won't work. */
|
|
KHR_DFDSETVAL(outbdb, PRIMARIES, KHR_DFDVAL(BDFD, PRIMARIES));
|
|
KHR_DFDSETVAL(outbdb, TRANSFER, KHR_DFDVAL(BDFD, TRANSFER));
|
|
KHR_DFDSETVAL(outbdb, FLAGS, KHR_DFDVAL(BDFD, FLAGS));
|
|
outbdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = KHR_DFDVAL(BDFD, TEXELBLOCKDIMENSION0);
|
|
outbdb[KHR_DF_WORD_BYTESPLANE0] = KHR_DFDVAL(BDFD, BYTESPLANE0);
|
|
outbdb[KHR_DF_WORD_BYTESPLANE4] = 0;
|
|
/* Now iterate through bitChannels, outputting the bits of that channel in order. */
|
|
{
|
|
uint32_t bitCounter;
|
|
sampleCounter = 0;
|
|
for (bitCounter = 0; bitCounter < worstCase; ++bitCounter) {
|
|
/* Note: This is a simplification assuming no overlapping channels. */
|
|
/* Ideally we should determine which channel has the lowes unique bit */
|
|
/* and output that first, rather than relying on channel id. */
|
|
if ((bitChannels[bitCounter] & 1) && channelRBits) {
|
|
/* Output channel R in order */
|
|
uint32_t redBit = 0;
|
|
uint32_t sampleBit = 0;
|
|
while (redBit < channelRBits) {
|
|
if (sampleBit == 0) {
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, BITOFFSET, channelR[0]);
|
|
/* Come back to BITLENGTH */
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, QUALIFIERS, redQualifiers);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLEPOSITION_ALL, 0);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLELOWER, 0);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLEUPPER, 0);
|
|
inSample = 1;
|
|
}
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLELOWER] |=
|
|
((lowerR[redBit >> 5] & (1U << (redBit & 0x1F))) != 0) << sampleBit;
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLEUPPER] |=
|
|
((upperR[redBit >> 5] & (1U << (redBit & 0x1F))) != 0) << sampleBit;
|
|
sampleBit += 1;
|
|
/* End of sample? */
|
|
/* This over-simplifies large samples: */
|
|
/* If a sample is greater than 32 bits and we can describe the lower
|
|
and upper values in fewer samples using the rules for extension,
|
|
we should do so. */
|
|
if (redBit == channelRBits - 1 ||
|
|
channelR[redBit] != channelR[redBit+1] - 1 ||
|
|
sampleBit == 32) {
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, BITLENGTH, sampleBit - 1);
|
|
if (sampleBit < 32 && (redQualifiers & KHR_DF_DATATYPE_SIGNED)) {
|
|
/* Sign extend lower and upper */
|
|
uint32_t lowerSign = lowerR[channelRBits >> 5] & 1U << (channelRBits & 0x1F);
|
|
(KHR_DFDSVAL(outbdb, sampleCounter, SAMPLELOWER) & 0x80000000U) != 0;
|
|
uint32_t upperSign =
|
|
(KHR_DFDSVAL(outbdb, sampleCounter, SAMPLEUPPER) & 0x80000000U) != 0;
|
|
if (lowerSign) lowerSign = ~((1U << sampleBit) - 1);
|
|
if (upperSign) upperSign = ~((1U << sampleBit) - 1);
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLELOWER] |=
|
|
lowerSign;
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLEUPPER] |=
|
|
upperSign;
|
|
}
|
|
sampleBit = 0;
|
|
sampleCounter += 1;
|
|
}
|
|
redBit += 1;
|
|
}
|
|
/* Don't do this channel again */
|
|
channelRBits = 0;
|
|
}
|
|
if ((bitChannels[bitCounter] & 2) && channelGBits) {
|
|
/* Output channel G in order */
|
|
uint32_t greenBit = 0;
|
|
uint32_t sampleBit = 0;
|
|
while (greenBit < channelGBits) {
|
|
if (sampleBit == 0) {
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, BITOFFSET, channelR[0]);
|
|
/* Come back to BITLENGTH */
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, QUALIFIERS, greenQualifiers);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLEPOSITION_ALL, 0);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLELOWER, 0);
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, SAMPLEUPPER, 0);
|
|
inSample = 1;
|
|
}
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLELOWER] |=
|
|
((lowerG[redBit >> 5] & (1U << (redBit & 0x1F))) != 0) << sampleBit;
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLEUPPER] |=
|
|
((upperG[redBit >> 5] & (1U << (redBit & 0x1F))) != 0) << sampleBit;
|
|
sampleBit += 1;
|
|
/* End of sample? */
|
|
/* This over-simplifies large samples: */
|
|
/* If a sample is greater than 32 bits and we can describe the lower
|
|
and upper values in fewer samples using the rules for extension,
|
|
we should do so. */
|
|
if (greenBit == channelGBits - 1 ||
|
|
channelG[greenBit] != channelG[greenBit+1] - 1 ||
|
|
sampleBit == 32) {
|
|
KHR_DFDSETSVAL(outbdb, sampleCounter, BITLENGTH, sampleBit - 1);
|
|
if (sampleBit < 32 && (greenQualifiers & KHR_DF_DATATYPE_SIGNED)) {
|
|
/* Sign extend lower and upper */
|
|
uint32_t lowerSign =
|
|
(KHR_DFDSVAL(outbdb, sampleCounter, SAMPLELOWER) & 0x80000000U) != 0;
|
|
uint32_t upperSign =
|
|
(KHR_DFDSVAL(outbdb, sampleCounter, SAMPLEUPPER) & 0x80000000U) != 0;
|
|
if (lowerSign) lowerSign = ~((1U << sampleBit) - 1);
|
|
if (upperSign) upperSign = ~((1U << sampleBit) - 1);
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLELOWER] |=
|
|
lowerSign;
|
|
outbdb[KHR_DF_WORD_SAMPLESTART +
|
|
sampleCounter * KHR_DF_WORD_SAMPLEWORDS +
|
|
KHR_DF_SAMPLEWORD_SAMPLEUPPER] |=
|
|
upperSign;
|
|
}
|
|
sampleBit = 0;
|
|
sampleCounter += 1;
|
|
}
|
|
redBit += 1;
|
|
}
|
|
/* Don't do this channel again */
|
|
channelGBits = 0;
|
|
}
|
|
if ((bitChannels[bitCounter] & 4) && channelBBits) {
|
|
/* Output channel B in order */
|
|
channelBBits = 0;
|
|
}
|
|
if ((bitChannels[bitCounter] & 8) && channelABits) {
|
|
/* Output channel A in order */
|
|
channelABits = 0;
|
|
}
|
|
}
|
|
}
|
|
/* Clean up allocations */
|
|
free(channelR);
|
|
free(channelG);
|
|
free(channelB);
|
|
free(channelA);
|
|
free(lowerR);
|
|
free(upperR);
|
|
free(lowerG);
|
|
free(upperG);
|
|
free(lowerB);
|
|
free(upperB);
|
|
free(lowerA);
|
|
free(upperA);
|
|
free(bitChannels);
|
|
return dfd;
|
|
}
|