ISPCTextureCompressor.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/std/function/function_template.h>
  9. #include <Atom/ImageProcessing/ImageObject.h>
  10. #include <Processing/ImageToProcess.h>
  11. #include <Processing/PixelFormatInfo.h>
  12. #include <Compressors/ISPCTextureCompressor.h>
  13. #include <ISPC/ispc_texcomp.h>
  14. namespace ImageProcessingAtom
  15. {
  16. // Class used to store functions to specific quality profiles.
  17. class CompressionProfile
  18. {
  19. public:
  20. AZStd::function<void(bc6h_enc_settings*)> GetBC6() const
  21. {
  22. return m_bc6;
  23. }
  24. AZStd::function<void(bc7_enc_settings*)> GetBC7(bool discardAlpha) const
  25. {
  26. if (discardAlpha)
  27. {
  28. return m_bc7;
  29. }
  30. return m_bc7Alpha;
  31. }
  32. AZStd::function<void(astc_enc_settings*, int block_width, int block_height)> GetASTC(bool discardAlpha) const
  33. {
  34. if (discardAlpha)
  35. {
  36. return m_astc;
  37. }
  38. return m_astcAlpha;
  39. }
  40. AZStd::function<void(bc6h_enc_settings*)> m_bc6;
  41. AZStd::function<void(bc7_enc_settings*)> m_bc7;
  42. AZStd::function<void(bc7_enc_settings*)> m_bc7Alpha;
  43. AZStd::function<void(astc_enc_settings*, int block_width, int block_height)> m_astc;
  44. AZStd::function<void(astc_enc_settings*, int block_width, int block_height)> m_astcAlpha;
  45. };
  46. bool ISPCCompressor::IsCompressedPixelFormatSupported(EPixelFormat fmt)
  47. {
  48. // Even though the ISPC compressor support ASTC formats. But it has restrictions
  49. // 1. Only supports LDR color profile
  50. // 2. Only supports a subset of 2D block sizes
  51. // Also it has overall lower quality compare to astc-encoder
  52. // So we won't add ASTC as part of supported formats here
  53. // Ref: https://solidpixel.github.io/2020/03/02/astc-compared.html
  54. switch (fmt)
  55. {
  56. case ePixelFormat_BC3:
  57. case ePixelFormat_BC6UH:
  58. case ePixelFormat_BC7:
  59. case ePixelFormat_BC7t:
  60. return true;
  61. default:
  62. return false;
  63. }
  64. }
  65. bool ISPCCompressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt)
  66. {
  67. return (fmt == ePixelFormat_R16G16B16A16F || fmt == ePixelFormat_R8G8B8A8);
  68. }
  69. bool ISPCCompressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst)
  70. {
  71. return false;
  72. }
  73. bool ISPCCompressor::IsSourceColorSpaceSupported(ColorSpace colorSpace, EPixelFormat destinationFormat)
  74. {
  75. switch (destinationFormat)
  76. {
  77. case ePixelFormat_BC3:
  78. return !(colorSpace == ColorSpace::linear);
  79. case ePixelFormat_BC6UH:
  80. case ePixelFormat_BC7:
  81. case ePixelFormat_BC7t:
  82. return true;
  83. }
  84. AZ_Warning("ISPC Texture Compressor", false, "Destination format is not supported");
  85. return false;
  86. }
  87. ColorSpace ISPCCompressor::GetSupportedColorSpace(EPixelFormat compressFormat) const
  88. {
  89. switch (compressFormat)
  90. {
  91. case ePixelFormat_BC3:
  92. return ColorSpace::sRGB;
  93. case ePixelFormat_BC6UH:
  94. case ePixelFormat_BC7:
  95. case ePixelFormat_BC7t:
  96. return ColorSpace::autoSelect;
  97. }
  98. AZ_Warning("ISPC Texture Compressor", false, "Compression format is not supported.");
  99. return ColorSpace::autoSelect;
  100. }
  101. const char* ISPCCompressor::GetName() const
  102. {
  103. return "ISPCCompressor";
  104. }
  105. IImageObjectPtr ISPCCompressor::CompressImage(IImageObjectPtr sourceImage, EPixelFormat destinationFormat, const CompressOption* compressOption) const
  106. {
  107. // Used to find the profile setters, depending on the image quality
  108. using QualityTypeAndFunctionPair = AZStd::pair<ICompressor::EQuality, CompressionProfile>;
  109. const uint32_t QualityTypeCount = static_cast<uint32_t>(ICompressor::EQuality::Count);
  110. static const AZStd::array<QualityTypeAndFunctionPair, QualityTypeCount> qualityTypeMap =
  111. {
  112. AZStd::make_pair(ICompressor::eQuality_Preview, CompressionProfile {
  113. GetProfile_bc6h_veryfast, GetProfile_ultrafast, GetProfile_alpha_ultrafast, GetProfile_astc_fast, GetProfile_astc_alpha_fast }),
  114. AZStd::make_pair(ICompressor::eQuality_Fast, CompressionProfile {
  115. GetProfile_bc6h_fast, GetProfile_fast, GetProfile_alpha_fast, GetProfile_astc_fast, GetProfile_astc_alpha_fast }),
  116. AZStd::make_pair(ICompressor::eQuality_Normal, CompressionProfile {
  117. GetProfile_bc6h_basic, GetProfile_basic, GetProfile_alpha_basic, GetProfile_astc_alpha_slow, GetProfile_astc_alpha_slow }),
  118. AZStd::make_pair(ICompressor::eQuality_Slow, CompressionProfile {
  119. GetProfile_bc6h_basic, GetProfile_basic, GetProfile_alpha_basic, GetProfile_astc_alpha_slow, GetProfile_astc_alpha_slow })
  120. };
  121. static const CompressionProfile DefaultQuality = { GetProfile_bc6h_basic, GetProfile_basic, GetProfile_alpha_basic, GetProfile_astc_alpha_slow, GetProfile_astc_alpha_slow };
  122. EPixelFormat sourceFormat = sourceImage->GetPixelFormat();
  123. // Get suggested uncompressed format provides correspond uncompressed formats,
  124. // this is just to validate format again here
  125. AZ_Assert(sourceFormat == GetSuggestedUncompressedFormat(destinationFormat, sourceFormat), "GetSuggestedUncompressedFormat need to be called to get the proper uncompress format as input");
  126. // Source format need to be uncompressed and destination format need to compressed.
  127. if (!IsUncompressedPixelFormatSupported(sourceFormat) || !IsCompressedPixelFormatSupported(destinationFormat))
  128. {
  129. return nullptr;
  130. }
  131. // Get quality setting and alpha setting
  132. ICompressor::EQuality quality = ICompressor::eQuality_Normal;
  133. bool discardAlpha = false;
  134. if (compressOption)
  135. {
  136. quality = compressOption->compressQuality;
  137. discardAlpha = compressOption->discardAlpha;
  138. }
  139. // Get the compression profile
  140. const CompressionProfile* compressionProfile = nullptr;
  141. {
  142. // Find the quality profile functions
  143. const auto qualityTypeMapIt = AZStd::find_if(qualityTypeMap.begin(), qualityTypeMap.end(), [quality](const QualityTypeAndFunctionPair& qualityTypeAndFunctionPair)
  144. {
  145. return qualityTypeAndFunctionPair.first == quality;
  146. });
  147. // Get the compression profile if it is available
  148. if (qualityTypeMapIt != qualityTypeMap.end())
  149. {
  150. compressionProfile = &qualityTypeMapIt->second;
  151. }
  152. else
  153. {
  154. // Use the default profile if it doesn't exist
  155. compressionProfile = &DefaultQuality;
  156. }
  157. }
  158. // Allocate the destination image
  159. IImageObjectPtr destinationImage(sourceImage->AllocateImage(destinationFormat));
  160. // Compress the images per mip
  161. const uint32 mipCount = destinationImage->GetMipCount();
  162. for (uint32_t mip = 0; mip < mipCount; mip++)
  163. {
  164. // Create rgba_surface as input
  165. uint32 sourcePitch = 0;
  166. AZ::u8* sourceImageData = nullptr;
  167. sourceImage->GetImagePointer(mip, sourceImageData, sourcePitch);
  168. rgba_surface sourceSurface = {};
  169. {
  170. sourceSurface.ptr = sourceImageData;
  171. sourceSurface.width = sourceImage->GetWidth(mip);
  172. sourceSurface.height = sourceImage->GetHeight(mip);
  173. sourceSurface.stride = static_cast<int32_t>(sourcePitch);
  174. }
  175. // Get the mip image destination pointer
  176. uint32_t destinationPitch = 0;
  177. AZ::u8* destinationImageData = nullptr;
  178. destinationImage->GetImagePointer(mip, destinationImageData, destinationPitch);
  179. // Compress with the correct function, depending on the destination format
  180. switch (destinationFormat)
  181. {
  182. case ePixelFormat_BC3:
  183. CompressBlocksBC3(&sourceSurface, destinationImageData);
  184. break;
  185. case ePixelFormat_BC6UH:
  186. {
  187. // Get the profile setter
  188. bc6h_enc_settings settings = {};
  189. const auto setProfile = compressionProfile->GetBC6();
  190. setProfile(&settings);
  191. // Compress with BC6 half precision
  192. CompressBlocksBC6H(&sourceSurface, destinationImageData, &settings);
  193. }
  194. break;
  195. case ePixelFormat_BC7:
  196. case ePixelFormat_BC7t:
  197. {
  198. // Get the profile setter
  199. bc7_enc_settings settings = {};
  200. const auto setProfile = compressionProfile->GetBC7(discardAlpha);
  201. setProfile(&settings);
  202. // Compress with BC7
  203. CompressBlocksBC7(&sourceSurface, destinationImageData, &settings);
  204. }
  205. break;
  206. default:
  207. {
  208. // No valid pixel format
  209. AZ_Assert(false, "Unhandled pixel format %d", destinationFormat);
  210. return nullptr;
  211. }
  212. break;
  213. }
  214. }
  215. return destinationImage;
  216. }
  217. IImageObjectPtr ISPCCompressor::DecompressImage([[maybe_unused]] IImageObjectPtr sourceImage, [[maybe_unused]] EPixelFormat destinationFormat) const
  218. {
  219. return nullptr;
  220. }
  221. EPixelFormat ISPCCompressor::GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt) const
  222. {
  223. if (compressedfmt == ePixelFormat_BC6UH)
  224. {
  225. return ePixelFormat_R16G16B16A16F;
  226. }
  227. return ePixelFormat_R8G8B8A8;
  228. }
  229. }; // namespace ImageProcessingAtom