Skip to content

Commit

Permalink
Support for A8 and A1B5G5R5 formats (KhronosGroup#785)
Browse files Browse the repository at this point in the history
The change contains various general enhancements
including performance optimizations for PNG exports.
  • Loading branch information
aqnuep authored Oct 20, 2023
1 parent b05e976 commit 11c5acf
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 0 deletions.
36 changes: 36 additions & 0 deletions lib/dfdutils/createdfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,3 +747,39 @@ uint32_t *createDFDDepthStencil(int depthBits,
}
return DFD;
}

/**
* @~English
* @brief Create a Data Format Descriptor for an alpha-only format.
*
* @param bigEndian Set to 1 for big-endian byte ordering and
0 for little-endian byte ordering.
* @param bytes The number of bytes per channel.
* @param suffix Indicates the format suffix for the type.
*
* @return A data format descriptor in malloc'd data. The caller is responsible
* for freeing the descriptor.
**/
uint32_t *createDFDAlpha(int bigEndian, int bytes,
enum VkSuffix suffix) {
uint32_t *DFD;
int channel = 3; /* alpha channel */
if (bigEndian) {
int channelByte;
/* Number of samples = number of channels * bytes per channel */
DFD = writeHeader(bytes, bytes, suffix, i_COLOR);
/* Loop over the bytes that constitute a channel */
for (channelByte = 0; channelByte < bytes; ++channelByte) {
writeSample(DFD, channelByte, channel,
8, 8 * (bytes - channelByte - 1),
channelByte == bytes-1, channelByte == 0, suffix);
}
} else { /* Little-endian */
/* One sample per channel */
DFD = writeHeader(1, bytes, suffix, i_COLOR);
writeSample(DFD, 0, channel,
8 * bytes, 0,
1, 1, suffix);
}
return DFD;
}
4 changes: 4 additions & 0 deletions lib/dfdutils/dfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ uint32_t *createDFDDepthStencil(int depthBits,
int stencilBits,
int sizeBytes);

/* Create a Data Format Descriptor for an alpha-only format */
uint32_t *createDFDAlpha(int bigEndian, int bytes,
enum VkSuffix suffix);

/** @brief Result of interpreting the data format descriptor. */
enum InterpretDFDResult {
i_LITTLE_ENDIAN_FORMAT_BIT = 0, /*!< Confirmed little-endian (default for 8bpc). */
Expand Down
4 changes: 4 additions & 0 deletions lib/dfdutils/dfd2vk.inl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) {
} else { /* Four channels, one-bit alpha */
if (B.offset == 0) return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
if (B.offset == 1) return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
if (B.offset == 10) return VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR;
return VK_FORMAT_B5G5R5A1_UNORM_PACK16;
}
} else if (wordBytes == 4) { /* PACK32 */
Expand All @@ -74,6 +75,9 @@ if (KHR_DFDVAL(dfd + 1, MODEL) == KHR_DF_MODEL_RGBSDA) {
}
} else { /* Not a packed format */
if (wordBytes == 1) {
if (A.size > 8 && R.size == 0 && G.size == 0 && B.size == 0 && (r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) {
return VK_FORMAT_A8_UNORM_KHR;
}
if (A.size > 0) { /* 4 channels */
if (R.offset == 0) { /* RGBA */
if ((r & i_SRGB_FORMAT_BIT)) return VK_FORMAT_R8G8B8A8_SRGB;
Expand Down
6 changes: 6 additions & 0 deletions lib/dfdutils/makedfd2vk.pl
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ sub checkSuffices {
} else { /* Four channels, one-bit alpha */
if (B.offset == 0) return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
if (B.offset == 1) return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
if (B.offset == 10) return VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR;
return VK_FORMAT_B5G5R5A1_UNORM_PACK16;
}
} else if (wordBytes == 4) { /* PACK32 */
Expand All @@ -315,6 +316,11 @@ sub checkSuffices {
for ($byteSize = 1; $byteSize <= 8; $byteSize <<= 1) {
if ($byteSize == 1) {
print " if (wordBytes == $byteSize) {\n";

# Handle the single alpha-only format (unfortunately, the rest of the script could not handle this)
print " if (A.size > 8 && R.size == 0 && G.size == 0 && B.size == 0 && (r & i_NORMALIZED_FORMAT_BIT) && !(r & i_SIGNED_FORMAT_BIT)) {\n";
print " return VK_FORMAT_A8_UNORM_KHR;\n";
print " }\n";
} else {
print " } else if (wordBytes == $byteSize) {\n";
}
Expand Down
9 changes: 9 additions & 0 deletions lib/dfdutils/makevk2dfd.pl
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,15 @@
# If we're not packed, do we have a simple RGBA channel size list with a suffix?
# N.B. We don't want to pick up downsampled or planar formats, which have more _-separated fields
# - "$" matches the end of the format identifier
} elsif ($format =~ m/VK_FORMAT_A([0-9]+)_([^_]+)(_[^_]+)?$/) {
# Special case for alpha-only formats

# Extract our "suffix" (e.g. "UNORM") and bytes per channel
$suffix = $2;
$bytesPerChannel = $1 / 8;

# Output the case entry
print "case $format: return createDFDAlpha($bigEndian, $bytesPerChannel, s_$suffix);\n";
} elsif ($format =~ m/VK_FORMAT_([RGBA0-9]+)_([^_]+)$/) {

# Extract our "channels" (e.g. "B8G8R8") and "suffix" (e.g. "UNORM")
Expand Down
5 changes: 5 additions & 0 deletions lib/dfdutils/vk2dfd.inl
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,8 @@ case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: {
int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: {
int channels[] = {0,1,2,3}; int bits[] = {5,5,5,1};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A8_UNORM_KHR: return createDFDAlpha(0, 1, s_UNORM);
2 changes: 2 additions & 0 deletions lib/dfdutils/vulkan/vulkan_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,8 @@ typedef enum VkFormat {
VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000,
VK_FORMAT_A8_UNORM_KHR = 1000470001,
VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
} VkFormat;

Expand Down
2 changes: 2 additions & 0 deletions lib/vkformat_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ isValidFormat(VkFormat format)
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT:
case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:
case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
case VK_FORMAT_A8_UNORM_KHR:
return true;
default:
return false;
Expand Down
2 changes: 2 additions & 0 deletions lib/vkformat_enum.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ typedef enum VkFormat {
VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT = 1000288029,
VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000,
VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001,
VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000,
VK_FORMAT_A8_UNORM_KHR = 1000470001,
VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
} VkFormat;

Expand Down
8 changes: 8 additions & 0 deletions lib/vkformat_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ vkFormatString(VkFormat format)
return "VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT";
case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
return "VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT";
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
return "VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR";
case VK_FORMAT_A8_UNORM_KHR:
return "VK_FORMAT_A8_UNORM_KHR";
default:
return "VK_UNKNOWN_FORMAT";
}
Expand Down Expand Up @@ -1152,5 +1156,9 @@ stringToVkFormat(const char* str)
return VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT;
if (ktx_strcasecmp(str, "A4B4G4R4_UNORM_PACK16_EXT") == 0)
return VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT;
if (ktx_strcasecmp(str, "A1B5G5R5_UNORM_PACK16_KHR") == 0)
return VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR;
if (ktx_strcasecmp(str, "A8_UNORM_KHR") == 0)
return VK_FORMAT_A8_UNORM_KHR;
return VK_FORMAT_UNDEFINED;
}

0 comments on commit 11c5acf

Please sign in to comment.