From ef2d5744a1e1758b62ea0266a4f61c4faa3d8f6c Mon Sep 17 00:00:00 2001 From: Mark Callow <2244683+MarkCallow@users.noreply.github.com> Date: Sun, 22 May 2022 18:27:11 +0900 Subject: [PATCH] Fix handling of combined depth-stencil textures (#575) Fix required alignment calculations in accordance with the spec. change in KhronosGroup/KTX-Specification#180. Remove creation of DFDs for these from dfdutils' vk2dfd as the layouts defined there are never seen outside Vulkan. Create their dfds, with the texel block sizes specified by KTX, within the KTX library and tools. Fix createDFDDepthStencil to set the primaries to UNSPECIFIED for depth, stencil and depth-stencil formats. Make vk2dfd.inl visible in project. --- CMakeLists.txt | 2 +- lib/dfdutils/createdfd.c | 23 ++++++++++++++-------- lib/dfdutils/makevk2dfd.pl | 32 ++++-------------------------- lib/dfdutils/vk2dfd.inl | 7 ++++--- lib/internalexport.def | 3 ++- lib/internalexport_mingw.def | 3 ++- lib/texture2.c | 38 ++++++++++++++++++++++++++++++++---- 7 files changed, 62 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79a37b1e93..f1d37cf7a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,11 +179,11 @@ set(KTX_MAIN_SRC lib/dfdutils/createdfd.c lib/dfdutils/colourspaces.c lib/dfdutils/dfd.h - lib/dfdutils/dfd2vk.inl lib/dfdutils/interpretdfd.c lib/dfdutils/printdfd.c lib/dfdutils/queries.c lib/dfdutils/vk2dfd.c + lib/dfdutils/vk2dfd.inl lib/dfdutils/vulkan/vk_platform.h lib/dfdutils/vulkan/vulkan_core.h lib/etcdec.cxx diff --git a/lib/dfdutils/createdfd.c b/lib/dfdutils/createdfd.c index 3fc90034a8..ea00d8d745 100644 --- a/lib/dfdutils/createdfd.c +++ b/lib/dfdutils/createdfd.c @@ -20,7 +20,10 @@ #include "dfd.h" -static uint32_t *writeHeader(int numSamples, int bytes, int suffix) +typedef enum { i_COLOR, i_NON_COLOR } channels_infotype; + +static uint32_t *writeHeader(int numSamples, int bytes, int suffix, + channels_infotype infotype) { uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) * (1 + KHR_DF_WORD_SAMPLESTART + @@ -40,8 +43,12 @@ static uint32_t *writeHeader(int numSamples, int bytes, int suffix) << KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE)); BDFD[KHR_DF_WORD_MODEL] = ((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) | /* Only supported model */ - (KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) | /* Assumed */ (KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS)); + if (infotype == i_COLOR) { + BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES; /* Assumed */ + } else { + BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_UNSPECIFIED << KHR_DF_SHIFT_PRIMARIES; + } if (suffix == s_SRGB) { BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER; } else { @@ -178,7 +185,7 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, if (bigEndian) { int channelCounter, channelByte; /* Number of samples = number of channels * bytes per channel */ - DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix); + DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix, i_COLOR); /* First loop over the channels */ for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) { int channel = channelCounter; @@ -197,7 +204,7 @@ uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes, int sampleCounter; /* One sample per channel */ - DFD = writeHeader(numChannels, numChannels * bytes, suffix); + DFD = writeHeader(numChannels, numChannels * bytes, suffix, i_COLOR); for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { int channel = sampleCounter; if (redBlueSwap && (channel == 0 || channel == 2)) { @@ -239,7 +246,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, uint32_t *DFD = 0; if (numChannels == 6) { /* Special case E5B9G9R9 */ - DFD = writeHeader(numChannels, 4, s_UFLOAT); + DFD = writeHeader(numChannels, 4, s_UFLOAT, i_COLOR); writeSample(DFD, 0, 0, 9, 0, 1, 1, s_UNORM); @@ -292,7 +299,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, } bitOffset += bits[channelCounter]; } - DFD = writeHeader(numSamples, totalBits >> 3, suffix); + DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR); sampleCounter = 0; for (bitOffset = 0; bitOffset < totalBits;) { @@ -336,7 +343,7 @@ uint32_t *createDFDPacked(int bigEndian, int numChannels, } /* One sample per channel */ - DFD = writeHeader(numChannels, totalBits >> 3, suffix); + DFD = writeHeader(numChannels, totalBits >> 3, suffix, i_COLOR); for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) { writeSample(DFD, sampleCounter, channels[sampleCounter], bits[sampleCounter], bitOffset, @@ -627,7 +634,7 @@ uint32_t *createDFDDepthStencil(int depthBits, /* N.B. Little-endian is assumed. */ uint32_t *DFD = 0; DFD = writeHeader((depthBits > 0) + (stencilBits > 0), - sizeBytes, s_UNORM); + sizeBytes, s_UNORM, i_NON_COLOR); if (depthBits == 32) { writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH, 32, 0, diff --git a/lib/dfdutils/makevk2dfd.pl b/lib/dfdutils/makevk2dfd.pl index 3f4df13531..3058be76f0 100755 --- a/lib/dfdutils/makevk2dfd.pl +++ b/lib/dfdutils/makevk2dfd.pl @@ -24,7 +24,10 @@ print "/* SPDX-", "License-Identifier: Apache-2.0 */\n\n"; print "/***************************** Do not edit. *****************************\n"; print " Automatically generated by makevk2dfd.pl.\n"; -print " *************************************************************************/\n"; +print " *************************************************************************/\n\n"; +print "/* Vulkan combined depth & stencil formats are not included here\n"; +print " * because they do not exist outside a Vulkan device.\n"; +print " */\n"; # Loop over each line of input while ($line = <>) { @@ -282,15 +285,6 @@ $foundFormats{$format} = 1; print "case $format: return createDFDDepthStencil(24,0,4);\n"; } - } elsif ($line =~ m/(VK_FORMAT_D32_SFLOAT_S8_UINT)/) { - - # Extract the format identifier from the rest of the line - $format = $1; - if (!exists($foundFormats{$format})) { - # Add the format we've processed to our "done" hash - $foundFormats{$format} = 1; - print "case $format: return createDFDDepthStencil(32,8,5);\n"; - } } elsif ($line =~ m/(VK_FORMAT_D32_SFLOAT)/) { # Extract the format identifier from the rest of the line @@ -309,15 +303,6 @@ $foundFormats{$format} = 1; print "case $format: return createDFDDepthStencil(0,8,1);\n"; } - } elsif ($line =~ m/(VK_FORMAT_D16_UNORM_S8_UINT)/) { - - # Extract the format identifier from the rest of the line - $format = $1; - if (!exists($foundFormats{$format})) { - # Add the format we've processed to our "done" hash - $foundFormats{$format} = 1; - print "case $format: return createDFDDepthStencil(16,8,3);\n"; - } } elsif ($line =~ m/(VK_FORMAT_D16_UNORM)/) { # Extract the format identifier from the rest of the line @@ -327,15 +312,6 @@ $foundFormats{$format} = 1; print "case $format: return createDFDDepthStencil(16,0,2);\n"; } - } elsif ($line =~ m/(VK_FORMAT_D24_UNORM_S8_UINT)/) { - - # Extract the format identifier from the rest of the line - $format = $1; - if (!exists($foundFormats{$format})) { - # Add the format we've processed to our "done" hash - $foundFormats{$format} = 1; - print "case $format: return createDFDDepthStencil(24,8,4);\n"; - } } # ...and continue to the next line diff --git a/lib/dfdutils/vk2dfd.inl b/lib/dfdutils/vk2dfd.inl index e396039928..6f9ef7672b 100644 --- a/lib/dfdutils/vk2dfd.inl +++ b/lib/dfdutils/vk2dfd.inl @@ -4,6 +4,10 @@ /***************************** Do not edit. ***************************** Automatically generated by makevk2dfd.pl. *************************************************************************/ + +/* Vulkan combined depth & stencil formats are not included here + * because they do not exist outside a Vulkan device. + */ case VK_FORMAT_R4G4_UNORM_PACK8: { int channels[] = {1,0}; int bits[] = {4,4}; return createDFDPacked(0, 2, bits, channels, s_UNORM); @@ -218,9 +222,6 @@ case VK_FORMAT_D16_UNORM: return createDFDDepthStencil(16,0,2); case VK_FORMAT_X8_D24_UNORM_PACK32: return createDFDDepthStencil(24,0,4); case VK_FORMAT_D32_SFLOAT: return createDFDDepthStencil(32,0,4); case VK_FORMAT_S8_UINT: return createDFDDepthStencil(0,8,1); -case VK_FORMAT_D16_UNORM_S8_UINT: return createDFDDepthStencil(16,8,3); -case VK_FORMAT_D24_UNORM_S8_UINT: return createDFDDepthStencil(24,8,4); -case VK_FORMAT_D32_SFLOAT_S8_UINT: return createDFDDepthStencil(32,8,5); case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_UNORM); case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_SRGB); case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_UNORM); diff --git a/lib/internalexport.def b/lib/internalexport.def index 33cc1399cc..5b22dff647 100644 --- a/lib/internalexport.def +++ b/lib/internalexport.def @@ -18,9 +18,10 @@ EXPORTS ?get_image_level_info@basisu_transcoder@basist@@QEBA_NPEBXIAEAUbasisu_image_level_info@2@II@Z ?start_transcoding@basisu_transcoder@basist@@QEAA_NPEBXI@Z ?transcode_image_level@basisu_transcoder@basist@@QEBA_NPEBXIIIPEAXIW4transcoder_texture_format@2@IIPEAUbasisu_transcoder_state@2@I@Z + createDFDCompressed + createDFDDepthStencil createDFDUnpacked createDFDPacked - createDFDCompressed findMapping interpretDFD isProhibitedFormat diff --git a/lib/internalexport_mingw.def b/lib/internalexport_mingw.def index 0406959794..1a61a2bc89 100644 --- a/lib/internalexport_mingw.def +++ b/lib/internalexport_mingw.def @@ -18,9 +18,10 @@ EXPORTS _ZNK6basist17basisu_transcoder20get_image_level_infoEPKvjRNS_23basisu_image_level_infoEjj _ZN6basist17basisu_transcoder17start_transcodingEPKvj _ZNK6basist17basisu_transcoder21transcode_image_levelEPKvjjjPvjNS_25transcoder_texture_formatEjjPNS_23basisu_transcoder_stateEj + createDFDCompressed + createDFDDepthStencil createDFDUnpacked createDFDPacked - createDFDCompressed findMapping interpretDFD isProhibitedFormat diff --git a/lib/texture2.c b/lib/texture2.c index 7987b9cc75..f9bbfcb95c 100644 --- a/lib/texture2.c +++ b/lib/texture2.c @@ -310,6 +310,37 @@ ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd) return true; } +/** + * @private + * @~English + * @brief Create a DFD for a VkFormat. + * + * This KTX-specific function adds support for combined depth stencil formats + * which are not supported by @e dfdutils' @c vk2dfd function because they + * are not seen outside a Vulkan device. KTX has its own definitions for + * these that enable uploading, with some effort. + * + * @param[in] vkFormat the format for which to create a DFD. + */ +static uint32_t* +ktxVk2dfd(ktx_uint32_t vkFormat) +{ + switch(vkFormat) { + case VK_FORMAT_D16_UNORM_S8_UINT: + // 2 16-bit words. D16 in the first. S8 in the 8 LSBs of the second. + return createDFDDepthStencil(16, 8, 4); + case VK_FORMAT_D24_UNORM_S8_UINT: + // 1 32-bit word. D24 in the MSBs. S8 in the LSBs. + return createDFDDepthStencil(24, 8, 4); + case VK_FORMAT_D32_SFLOAT_S8_UINT: + // 2 32-bit words. D32 float in the first word. S8 in LSBs of the + // second. + return createDFDDepthStencil(32, 8, 8); + default: + return vk2dfd(vkFormat); + } +} + /** * @memberof ktxTexture2 @private * @~English @@ -370,9 +401,10 @@ ktxTexture2_construct(ktxTexture2* This, ktxTextureCreateInfo* createInfo, memset(This, 0, sizeof(*This)); if (createInfo->vkFormat != VK_FORMAT_UNDEFINED) { - This->pDfd = vk2dfd(createInfo->vkFormat); + This->pDfd = ktxVk2dfd(createInfo->vkFormat); if (!This->pDfd) return KTX_INVALID_VALUE; // Format is unknown or unsupported. + #ifdef _DEBUG // If this fires, an unsupported format or incorrect DFD // has crept into vk2dfd. @@ -1528,10 +1560,8 @@ lcm4(uint32_t a) ktx_uint32_t alignment; if (This->supercompressionScheme != KTX_SS_NONE) alignment = 1; - else if (This->vkFormat != VK_FORMAT_UNDEFINED) - alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); else - alignment = 16; + alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8); return alignment; }