#include <stdlib.h>
#include <KHR/khr_df.h>
#include "dfd.h"
static uint32_t *writeHeader(int numSamples, int bytes, int suffix)
{
uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS));
uint32_t* BDFD = DFD+1;
DFD[0] = sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS);
BDFD[KHR_DF_WORD_VENDORID] =
(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |
(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);
BDFD[KHR_DF_WORD_VERSIONNUMBER] =
(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |
(((uint32_t)sizeof(uint32_t) *
(KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS)
<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));
BDFD[KHR_DF_WORD_MODEL] =
((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) |
(KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) |
(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));
if (suffix == s_SRGB) {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;
} else {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;
}
BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 0;
BDFD[KHR_DF_WORD_BYTESPLANE0] = bytes;
BDFD[KHR_DF_WORD_BYTESPLANE4] = 0;
return DFD;
}
static uint32_t setChannelFlags(uint32_t channel, enum VkSuffix suffix)
{
switch (suffix) {
case s_UNORM: break;
case s_SNORM:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_USCALED: break;
case s_SSCALED:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_UINT: break;
case s_SINT:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_SFLOAT:
channel |=
KHR_DF_SAMPLE_DATATYPE_FLOAT |
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_UFLOAT:
channel |=
KHR_DF_SAMPLE_DATATYPE_FLOAT;
break;
case s_SRGB:
if (channel == KHR_DF_CHANNEL_RGBSDA_ALPHA) {
channel |= KHR_DF_SAMPLE_DATATYPE_LINEAR;
}
break;
}
return channel;
}
static void writeSample(uint32_t *DFD, int sampleNo, int channel,
int bits, int offset,
int topSample, int bottomSample, enum VkSuffix suffix)
{
union {
uint32_t i;
float f;
} lower, upper;
uint32_t *sample = DFD + 1 + KHR_DF_WORD_SAMPLESTART + sampleNo * KHR_DF_WORD_SAMPLEWORDS;
if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA;
if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA;
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(offset << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((bits - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
switch (suffix) {
case s_UNORM:
case s_SRGB:
default:
if (bits > 32) {
upper.i = 0xFFFFFFFFU;
} else {
upper.i = (uint32_t)((1U << bits) - 1U);
}
lower.i = 0U;
break;
case s_SNORM:
if (bits > 32) {
upper.i = 0x7FFFFFFF;
} else {
upper.i = topSample ? (1U << (bits - 1)) - 1 : (1U << bits) - 1;
}
lower.i = ~upper.i;
if (bottomSample) lower.i += 1;
break;
case s_USCALED:
case s_UINT:
upper.i = bottomSample ? 1U : 0U;
lower.i = 0U;
break;
case s_SSCALED:
case s_SINT:
upper.i = bottomSample ? 1U : 0U;
lower.i = ~0U;
break;
case s_SFLOAT:
upper.f = 1.0f;
lower.f = -1.0f;
break;
case s_UFLOAT:
upper.f = 1.0f;
lower.f = 0.0f;
break;
}
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
}
uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes,
int redBlueSwap, enum VkSuffix suffix)
{
uint32_t *DFD;
if (bigEndian) {
int channelCounter, channelByte;
DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix);
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
int channel = channelCounter;
if (redBlueSwap && (channel == 0 || channel == 2)) {
channel ^= 2;
}
for (channelByte = 0; channelByte < bytes; ++channelByte) {
writeSample(DFD, channelCounter * bytes + channelByte, channel,
8, 8 * (channelCounter * bytes + bytes - channelByte - 1),
channelByte == bytes-1, channelByte == 0, suffix);
}
}
} else {
int sampleCounter;
DFD = writeHeader(numChannels, numChannels * bytes, suffix);
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
int channel = sampleCounter;
if (redBlueSwap && (channel == 0 || channel == 2)) {
channel ^= 2;
}
writeSample(DFD, sampleCounter, channel,
8 * bytes, 8 * sampleCounter * bytes,
1, 1, suffix);
}
}
return DFD;
}
uint32_t *createDFDPacked(int bigEndian, int numChannels,
int bits[], int channels[],
enum VkSuffix suffix)
{
uint32_t *DFD = 0;
if (numChannels == 6) {
DFD = writeHeader(numChannels, 4, s_UFLOAT);
writeSample(DFD, 0, 0,
9, 0,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 0, SAMPLEUPPER, 8448);
writeSample(DFD, 1, 0 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 1, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 1, SAMPLEUPPER, 31);
writeSample(DFD, 2, 1,
9, 9,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 2, SAMPLEUPPER, 8448);
writeSample(DFD, 3, 1 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 3, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 3, SAMPLEUPPER, 31);
writeSample(DFD, 4, 2,
9, 18,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 4, SAMPLEUPPER, 8448);
writeSample(DFD, 5, 2 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 5, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 5, SAMPLEUPPER, 31);
} else if (bigEndian) {
int totalBits = 0;
int bitChannel[32];
int beChannelStart[4];
int channelCounter;
int bitOffset = 0;
int BEMask;
int numSamples = numChannels;
int sampleCounter;
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
beChannelStart[channelCounter] = totalBits;
totalBits += bits[channelCounter];
}
BEMask = (totalBits - 1) & 0x18;
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
bitChannel[bitOffset ^ BEMask] = channelCounter;
if (((bitOffset + bits[channelCounter] - 1) & ~7) != (bitOffset & ~7)) {
bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter;
numSamples++;
}
bitOffset += bits[channelCounter];
}
DFD = writeHeader(numSamples, totalBits >> 3, suffix);
sampleCounter = 0;
for (bitOffset = 0; bitOffset < totalBits;) {
if (bitChannel[bitOffset] == -1) {
bitOffset = (bitOffset + 8) & ~7;
} else {
int thisChannel = bitChannel[bitOffset];
if ((beChannelStart[thisChannel] ^ BEMask) == bitOffset) {
writeSample(DFD, sampleCounter++, channels[thisChannel],
bits[thisChannel], bitOffset,
1, 1, suffix);
bitOffset += bits[thisChannel];
} else {
int firstSampleBits = 8 - (beChannelStart[thisChannel] & 0x7);
int secondSampleBits = bits[thisChannel] - firstSampleBits;
writeSample(DFD, sampleCounter++, channels[thisChannel],
firstSampleBits, beChannelStart[thisChannel] ^ BEMask,
0, 1, suffix);
bitChannel[beChannelStart[thisChannel] ^ BEMask] = -1;
writeSample(DFD, sampleCounter++, channels[thisChannel],
secondSampleBits, bitOffset,
1, 0, suffix);
bitOffset += secondSampleBits;
}
}
}
} else {
int sampleCounter;
int totalBits = 0;
int bitOffset = 0;
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
totalBits += bits[sampleCounter];
}
DFD = writeHeader(numChannels, totalBits >> 3, suffix);
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
writeSample(DFD, sampleCounter, channels[sampleCounter],
bits[sampleCounter], bitOffset,
1, 1, suffix);
bitOffset += bits[sampleCounter];
}
}
return DFD;
}
static khr_df_model_e compModelMapping[] = {
KHR_DF_MODEL_BC1A,
KHR_DF_MODEL_BC1A,
KHR_DF_MODEL_BC2,
KHR_DF_MODEL_BC3,
KHR_DF_MODEL_BC4,
KHR_DF_MODEL_BC5,
KHR_DF_MODEL_BC6H,
KHR_DF_MODEL_BC7,
KHR_DF_MODEL_ETC2,
KHR_DF_MODEL_ETC2,
KHR_DF_MODEL_ETC2,
KHR_DF_MODEL_ETC2,
KHR_DF_MODEL_ETC2,
KHR_DF_MODEL_ASTC,
KHR_DF_MODEL_ETC1S,
KHR_DF_MODEL_PVRTC,
KHR_DF_MODEL_PVRTC2
};
static uint32_t compSampleCount[] = {
1U,
1U,
2U,
2U,
1U,
2U,
1U,
1U,
1U,
2U,
2U,
1U,
2U,
1U,
1U,
1U,
1U
};
static khr_df_model_channels_e compFirstChannel[] = {
KHR_DF_CHANNEL_BC1A_COLOR,
KHR_DF_CHANNEL_BC1A_ALPHAPRESENT,
KHR_DF_CHANNEL_BC2_ALPHA,
KHR_DF_CHANNEL_BC3_ALPHA,
KHR_DF_CHANNEL_BC4_DATA,
KHR_DF_CHANNEL_BC5_RED,
KHR_DF_CHANNEL_BC6H_COLOR,
KHR_DF_CHANNEL_BC7_COLOR,
KHR_DF_CHANNEL_ETC2_COLOR,
KHR_DF_CHANNEL_ETC2_COLOR,
KHR_DF_CHANNEL_ETC2_ALPHA,
KHR_DF_CHANNEL_ETC2_RED,
KHR_DF_CHANNEL_ETC2_RED,
KHR_DF_CHANNEL_ASTC_DATA,
KHR_DF_CHANNEL_ETC1S_RGB,
KHR_DF_CHANNEL_PVRTC_COLOR,
KHR_DF_CHANNEL_PVRTC2_COLOR
};
static khr_df_model_channels_e compSecondChannel[] = {
KHR_DF_CHANNEL_BC1A_COLOR,
KHR_DF_CHANNEL_BC1A_ALPHAPRESENT,
KHR_DF_CHANNEL_BC2_COLOR,
KHR_DF_CHANNEL_BC3_COLOR,
KHR_DF_CHANNEL_BC4_DATA,
KHR_DF_CHANNEL_BC5_GREEN,
KHR_DF_CHANNEL_BC6H_COLOR,
KHR_DF_CHANNEL_BC7_COLOR,
KHR_DF_CHANNEL_ETC2_COLOR,
KHR_DF_CHANNEL_ETC2_ALPHA,
KHR_DF_CHANNEL_ETC2_COLOR,
KHR_DF_CHANNEL_ETC2_RED,
KHR_DF_CHANNEL_ETC2_GREEN,
KHR_DF_CHANNEL_ASTC_DATA,
KHR_DF_CHANNEL_ETC1S_RGB,
KHR_DF_CHANNEL_PVRTC_COLOR,
KHR_DF_CHANNEL_PVRTC2_COLOR
};
static uint32_t compSecondChannelOffset[] = {
0U,
0U,
64U,
64U,
0U,
64U,
0U,
0U,
0U,
0U,
64U,
0U,
64U,
0U,
0U,
0U,
0U
};
static uint32_t compChannelBits[] = {
64U,
64U,
64U,
64U,
64U,
64U,
128U,
128U,
64U,
64U,
64U,
64U,
64U,
128U,
64U,
64U,
64U
};
static uint32_t compBytes[] = {
8U,
8U,
16U,
16U,
8U,
16U,
16U,
16U,
8U,
8U,
16U,
8U,
16U,
16U,
8U,
8U,
8U
};
uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth,
enum VkSuffix suffix)
{
uint32_t *DFD = 0;
uint32_t numSamples = compSampleCount[compScheme];
uint32_t* BDFD;
uint32_t *sample;
uint32_t channel;
union {
uint32_t i;
float f;
} lower, upper;
DFD = (uint32_t *) malloc(sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS));
BDFD = DFD+1;
DFD[0] = sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS);
BDFD[KHR_DF_WORD_VENDORID] =
(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |
(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);
BDFD[KHR_DF_WORD_VERSIONNUMBER] =
(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |
(((uint32_t)sizeof(uint32_t) *
(KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS)
<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));
BDFD[KHR_DF_WORD_MODEL] =
((compModelMapping[compScheme] << KHR_DF_SHIFT_MODEL) |
(KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) |
(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));
if (suffix == s_SRGB) {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;
} else {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;
}
BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] =
(bwidth - 1) | ((bheight - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1) | ((bdepth - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION2);
BDFD[KHR_DF_WORD_BYTESPLANE0] = compBytes[compScheme];
BDFD[KHR_DF_WORD_BYTESPLANE4] = 0;
sample = BDFD + KHR_DF_WORD_SAMPLESTART;
channel = compFirstChannel[compScheme];
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(0 << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
switch (suffix) {
case s_UNORM:
case s_SRGB:
default:
upper.i = 0xFFFFFFFFU;
lower.i = 0U;
break;
case s_SNORM:
upper.i = 0x7FFFFFFF;
lower.i = ~upper.i;
break;
case s_USCALED:
case s_UINT:
upper.i = 1U;
lower.i = 0U;
break;
case s_SSCALED:
case s_SINT:
upper.i = 1U;
lower.i = ~0U;
break;
case s_SFLOAT:
upper.f = 1.0f;
lower.f = -1.0f;
break;
case s_UFLOAT:
upper.f = 1.0f;
lower.f = 0.0f;
break;
}
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
if (compSampleCount[compScheme] > 1) {
sample += KHR_DF_WORD_SAMPLEWORDS;
channel = compSecondChannel[compScheme];
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(compSecondChannelOffset[compScheme] << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
}
return DFD;
}
uint32_t *createDFDDepthStencil(int depthBits,
int stencilBits,
int sizeBytes)
{
uint32_t *DFD = 0;
DFD = writeHeader((depthBits > 0) + (stencilBits > 0),
sizeBytes, s_UNORM);
if (depthBits == 32) {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,
32, 0,
1, 1, s_SFLOAT);
} else if (depthBits > 0) {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,
depthBits, 0,
1, 1, s_UNORM);
}
if (stencilBits > 0) {
if (depthBits > 0) {
writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_STENCIL,
stencilBits, depthBits,
1, 1, s_UINT);
} else {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL,
stencilBits, 0,
1, 1, s_UINT);
}
}
return DFD;
}