3
0

PixelFormatInfo.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 <Processing/PixelFormatInfo.h>
  9. #include <Processing/DDSHeader.h>
  10. #include <AzCore/Math/MathUtils.h>
  11. namespace ImageProcessingAtom
  12. {
  13. CPixelFormats* CPixelFormats::s_instance = nullptr;
  14. CPixelFormats& CPixelFormats::GetInstance()
  15. {
  16. if (s_instance == nullptr)
  17. {
  18. s_instance = new CPixelFormats();
  19. }
  20. return *s_instance;
  21. }
  22. void CPixelFormats::DestroyInstance()
  23. {
  24. delete s_instance;
  25. s_instance = nullptr;
  26. }
  27. bool IsASTCFormat(EPixelFormat fmt)
  28. {
  29. if (fmt == ePixelFormat_ASTC_4x4
  30. || fmt == ePixelFormat_ASTC_5x4
  31. || fmt == ePixelFormat_ASTC_5x5
  32. || fmt == ePixelFormat_ASTC_6x5
  33. || fmt == ePixelFormat_ASTC_6x6
  34. || fmt == ePixelFormat_ASTC_8x5
  35. || fmt == ePixelFormat_ASTC_8x6
  36. || fmt == ePixelFormat_ASTC_8x8
  37. || fmt == ePixelFormat_ASTC_10x5
  38. || fmt == ePixelFormat_ASTC_10x6
  39. || fmt == ePixelFormat_ASTC_10x8
  40. || fmt == ePixelFormat_ASTC_10x10
  41. || fmt == ePixelFormat_ASTC_12x10
  42. || fmt == ePixelFormat_ASTC_12x12)
  43. {
  44. return true;
  45. }
  46. return false;
  47. }
  48. bool IsHDRFormat(EPixelFormat fmt)
  49. {
  50. switch (fmt)
  51. {
  52. case ePixelFormat_BC6UH:
  53. case ePixelFormat_R9G9B9E5:
  54. case ePixelFormat_R32G32B32A32F:
  55. case ePixelFormat_R32G32F:
  56. case ePixelFormat_R32F:
  57. case ePixelFormat_R16G16B16A16F:
  58. case ePixelFormat_R16G16F:
  59. case ePixelFormat_R16F:
  60. return true;
  61. default:
  62. return false;
  63. }
  64. }
  65. PixelFormatInfo::PixelFormatInfo(
  66. uint32_t a_bitsPerPixel,
  67. uint32_t a_Channels,
  68. bool a_Alpha,
  69. const char* a_szAlpha,
  70. uint32 a_minWidth,
  71. uint32 a_minHeight,
  72. uint32_t a_blockWidth,
  73. uint32_t a_blockHeight,
  74. uint32_t a_bitsPerBlock,
  75. bool a_bSquarePow2,
  76. DXGI_FORMAT a_d3d10Format,
  77. uint32_t a_fourCC,
  78. ESampleType a_eSampleType,
  79. const char* a_szName,
  80. const char* a_szDescription,
  81. bool a_bCompressed,
  82. bool a_bSelectable)
  83. : nChannels(a_Channels)
  84. , bHasAlpha(a_Alpha)
  85. , minWidth(a_minWidth)
  86. , minHeight(a_minHeight)
  87. , blockWidth(a_blockWidth)
  88. , blockHeight(a_blockHeight)
  89. , bitsPerBlock(a_bitsPerBlock)
  90. , bSquarePow2(a_bSquarePow2)
  91. , szAlpha(a_szAlpha)
  92. , d3d10Format(a_d3d10Format)
  93. , fourCC(a_fourCC)
  94. , eSampleType(a_eSampleType)
  95. , szName(a_szName)
  96. , szDescription(a_szDescription)
  97. , bCompressed(a_bCompressed)
  98. , bSelectable(a_bSelectable)
  99. {
  100. //validate pixel format
  101. //a_bitsPerPixel could be 0 if it's ACTC format since the actual bits per-pixel could be 6.4, 5.12 etc.
  102. if (a_bitsPerPixel)
  103. {
  104. AZ_Assert(a_bitsPerPixel * blockWidth * blockHeight == bitsPerBlock, "PixelFormatInfo: Wrong block setting");
  105. }
  106. AZ_Assert(szName, "szName can't be nullptr");
  107. AZ_Assert(nChannels > 0 && nChannels <= 4, "unreasonable channel count %d", nChannels);
  108. AZ_Assert(a_szDescription, "szDescription can't be nullptr");
  109. AZ_Assert(blockWidth > 0 && blockHeight > 0, "blcok size need to be larger than 0: %d x %d", blockWidth, blockHeight);
  110. AZ_Assert(minWidth > 0 && minHeight > 0, "piexel required mininum image size need to be larger than 0: %d x %d", minWidth, minHeight);
  111. if (!bCompressed)
  112. {
  113. AZ_Assert(blockWidth == 1 && blockHeight == 1, "Uncompressed format shouldn't have block which size > 1");
  114. }
  115. }
  116. CPixelFormats::CPixelFormats()
  117. {
  118. InitPixelFormats();
  119. }
  120. void CPixelFormats::InitPixelFormat(EPixelFormat format, const PixelFormatInfo& formatInfo)
  121. {
  122. AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format);
  123. if (m_pixelFormatInfo[format].szName && m_pixelFormatNameMap.find(formatInfo.szName) != m_pixelFormatNameMap.end())
  124. {
  125. // double initialization
  126. AZ_Assert(false, "Pixel format already exist: %s", m_pixelFormatInfo[format].szName);
  127. }
  128. m_pixelFormatNameMap[formatInfo.szName] = format;
  129. m_pixelFormatInfo[format] = formatInfo;
  130. }
  131. void CPixelFormats::InitPixelFormats()
  132. {
  133. // Unsigned Formats
  134. // Data in an unsigned format must be positive. Unsigned formats use combinations of
  135. // (R)ed, (G)reen, (B)lue, (A)lpha, (L)uminance
  136. InitPixelFormat(ePixelFormat_R8G8B8A8, PixelFormatInfo(32, 4, true, "8", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R8G8B8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8B8A8", "32-bit RGBA pixel format with alpha, using 8 bits per channel", false, true));
  137. InitPixelFormat(ePixelFormat_R8G8B8X8, PixelFormatInfo(32, 4, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R8G8B8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8B8X8", "32-bit RGB pixel format, where 8 bits are reserved for each color", false, true));
  138. InitPixelFormat(ePixelFormat_R8G8, PixelFormatInfo(16, 2, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R8G8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8", "16-bit red/green, using 8 bits per channel", false, false));
  139. InitPixelFormat(ePixelFormat_R8, PixelFormatInfo(8, 1, false, "0", 1, 1, 1, 1, 8, false, DXGI_FORMAT_R8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8", "8-bit red only", false, false));
  140. InitPixelFormat(ePixelFormat_A8, PixelFormatInfo(8, 1, true, "8", 1, 1, 1, 1, 8, false, DXGI_FORMAT_A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "A8", "8-bit alpha only", false, true));
  141. InitPixelFormat(ePixelFormat_R16G16B16A16, PixelFormatInfo(64, 4, true, "16", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R16G16B16A16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16G16B16A16", "64-bit ARGB pixel format with alpha, using 16 bits per channel", false, false));
  142. InitPixelFormat(ePixelFormat_R16G16, PixelFormatInfo(32, 2, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R16G16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16G16", "32-bit red/green, using 16 bits per channel", false, false));
  143. InitPixelFormat(ePixelFormat_R16, PixelFormatInfo(16, 1, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R16_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint16, "R16", "16-bit red only", false, false));
  144. // Custom FourCC Formats
  145. // Data in these FourCC formats is custom compressed data and only decodable by certain hardware.
  146. InitPixelFormat(ePixelFormat_ASTC_4x4, PixelFormatInfo(0, 4, true, "?", 16, 16, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_4x4, ESampleType::eSampleType_Compressed, "ASTC_4x4", "ASTC 4x4 compressed texture format", true, false));
  147. InitPixelFormat(ePixelFormat_ASTC_5x4, PixelFormatInfo(0, 4, true, "?", 16, 16, 5, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_5x4, ESampleType::eSampleType_Compressed, "ASTC_5x4", "ASTC 5x4 compressed texture format", true, false));
  148. InitPixelFormat(ePixelFormat_ASTC_5x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 5, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_5x5, ESampleType::eSampleType_Compressed, "ASTC_5x5", "ASTC 5x5 compressed texture format", true, false));
  149. InitPixelFormat(ePixelFormat_ASTC_6x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 6, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_6x5, ESampleType::eSampleType_Compressed, "ASTC_6x5", "ASTC 6x5 compressed texture format", true, false));
  150. InitPixelFormat(ePixelFormat_ASTC_6x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 6, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_6x6, ESampleType::eSampleType_Compressed, "ASTC_6x6", "ASTC 6x6 compressed texture format", true, false));
  151. InitPixelFormat(ePixelFormat_ASTC_8x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x5, ESampleType::eSampleType_Compressed, "ASTC_8x5", "ASTC 8x5 compressed texture format", true, false));
  152. InitPixelFormat(ePixelFormat_ASTC_8x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x6, ESampleType::eSampleType_Compressed, "ASTC_8x6", "ASTC 8x6 compressed texture format", true, false));
  153. InitPixelFormat(ePixelFormat_ASTC_8x8, PixelFormatInfo(0, 4, true, "?", 16, 16, 8, 8, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_8x8, ESampleType::eSampleType_Compressed, "ASTC_8x8", "ASTC 8x8 compressed texture format", true, false));
  154. InitPixelFormat(ePixelFormat_ASTC_10x5, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 5, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x5, ESampleType::eSampleType_Compressed, "ASTC_10x5", "ASTC 10x5 compressed texture format", true, false));
  155. InitPixelFormat(ePixelFormat_ASTC_10x6, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 6, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x6, ESampleType::eSampleType_Compressed, "ASTC_10x6", "ASTC 10x6 compressed texture format", true, false));
  156. InitPixelFormat(ePixelFormat_ASTC_10x8, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 8, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x8, ESampleType::eSampleType_Compressed, "ASTC_10x8", "ASTC 10x8 compressed texture format", true, false));
  157. InitPixelFormat(ePixelFormat_ASTC_10x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x10, ESampleType::eSampleType_Compressed, "ASTC_10x10", "ASTC 10x10 compressed texture format", true, false));
  158. InitPixelFormat(ePixelFormat_ASTC_12x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x10, ESampleType::eSampleType_Compressed, "ASTC_12x10", "ASTC 12x10 compressed texture format", true, false));
  159. InitPixelFormat(ePixelFormat_ASTC_12x12, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 12, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x12, ESampleType::eSampleType_Compressed, "ASTC_12x12", "ASTC 12x12 compressed texture format", true, false));
  160. // Standardized Compressed DXGI Formats (DX10+)
  161. // Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API.
  162. InitPixelFormat(ePixelFormat_BC1, PixelFormatInfo(4, 3, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC1_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC1", "BC1 compressed texture format", true, true));
  163. InitPixelFormat(ePixelFormat_BC1a, PixelFormatInfo(4, 4, true, "1", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC1_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC1a", "BC1a compressed texture format with transparency", true, true));
  164. InitPixelFormat(ePixelFormat_BC3, PixelFormatInfo(8, 4, true, "3of8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC3_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC3", "BC3 compressed texture format", true, true));
  165. InitPixelFormat(ePixelFormat_BC3t, PixelFormatInfo(8, 4, true, "3of8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC3_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC3t", "BC3t compressed texture format with transparency", true, true));
  166. InitPixelFormat(ePixelFormat_BC4, PixelFormatInfo(4, 1, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC4_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC4", "BC4 compressed texture format for single channel maps. 3DCp", true, true));
  167. InitPixelFormat(ePixelFormat_BC4s, PixelFormatInfo(4, 1, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_BC4_SNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC4s", "BC4 compressed texture format for signed single channel maps", true, true));
  168. InitPixelFormat(ePixelFormat_BC5, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC5_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC5", "BC5 compressed texture format for two channel maps or normalmaps. 3DC", true, true));
  169. InitPixelFormat(ePixelFormat_BC5s, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC5_SNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC5s", "BC5 compressed texture format for signed two channel maps or normalmaps", true, true));
  170. InitPixelFormat(ePixelFormat_BC6UH, PixelFormatInfo(8, 3, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC6H_UF16, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC6UH", "BC6 compressed texture format, unsigned half", true, true));
  171. InitPixelFormat(ePixelFormat_BC7, PixelFormatInfo(8, 4, true, "8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC7_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC7", "BC7 compressed texture format", true, true));
  172. InitPixelFormat(ePixelFormat_BC7t, PixelFormatInfo(8, 4, true, "8", 4, 4, 4, 4, 128, false, DXGI_FORMAT_BC7_UNORM, FOURCC_DX10, ESampleType::eSampleType_Compressed, "BC7t", "BC7t compressed texture format with transparency", true, true));
  173. // Float formats
  174. // Data in a Float format is floating point data.
  175. InitPixelFormat(ePixelFormat_R9G9B9E5, PixelFormatInfo(32, 3, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, FOURCC_DX10, ESampleType::eSampleType_Compressed, "R9G9B9E5", "32-bit RGB pixel format with shared exponent", false, true));
  176. InitPixelFormat(ePixelFormat_R32G32B32A32F, PixelFormatInfo(128, 4, true, "23", 1, 1, 1, 1, 128, false, DXGI_FORMAT_R32G32B32A32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32G32B32A32F", "four float channels", false, false));
  177. InitPixelFormat(ePixelFormat_R32G32F, PixelFormatInfo(64, 2, false, "0", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R32G32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32G32F", "two float channels", false, false)); // FIXME: This should be eTF_R32G32F, but that enum is not in ITexture.h yet
  178. InitPixelFormat(ePixelFormat_R32F, PixelFormatInfo(32, 1, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R32_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Float, "R32F", "one float channel", false, false));
  179. InitPixelFormat(ePixelFormat_R16G16B16A16F, PixelFormatInfo(64, 4, true, "10", 1, 1, 1, 1, 64, false, DXGI_FORMAT_R16G16B16A16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16G16B16A16F", "four half channels", false, false));
  180. InitPixelFormat(ePixelFormat_R16G16F, PixelFormatInfo(32, 2, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_R16G16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16G16F", "two half channel", false, false));
  181. InitPixelFormat(ePixelFormat_R16F, PixelFormatInfo(16, 1, false, "0", 1, 1, 1, 1, 16, false, DXGI_FORMAT_R16_FLOAT, FOURCC_DX10, ESampleType::eSampleType_Half, "R16F", "one half channel", false, false));
  182. //legacy BGRA8
  183. InitPixelFormat(ePixelFormat_B8G8R8A8, PixelFormatInfo(32, 4, true, "8", 1, 1, 1, 1, 32, false, DXGI_FORMAT_B8G8R8A8_UNORM, FOURCC_DX10, ESampleType::eSampleType_Uint8, "B8G8R8A8", "32-bit BGRA pixel format with alpha, using 8 bits per channel", false, false));
  184. InitPixelFormat(ePixelFormat_B8G8R8, PixelFormatInfo(24, 3, true, "0", 1, 1, 1, 1, 24, false, DXGI_FORMAT_UNKNOWN, FOURCC_DX10, ESampleType::eSampleType_Uint8, "B8G8R8", "24-bit BGR pixel format, using 8 bits per channel", false, false));
  185. InitPixelFormat(ePixelFormat_R8G8B8, PixelFormatInfo(24, 3, true, "0", 1, 1, 1, 1, 24, false, DXGI_FORMAT_UNKNOWN, FOURCC_DX10, ESampleType::eSampleType_Uint8, "R8G8B8", "24-bit RGB pixel format, using 8 bits per channel", false, false));
  186. InitPixelFormat(ePixelFormat_R32, PixelFormatInfo(32, 1, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_FORCE_UINT, FOURCC_DX10, ESampleType::eSampleType_Uint32, "R32", "32-bit red only", false, false));
  187. //validate all pixel formats are proper initialized
  188. for (int i = 0; i < ePixelFormat_Count; ++i)
  189. {
  190. if (m_pixelFormatInfo[i].szName == 0)
  191. {
  192. // Uninitialized entry. Should never happen. But, if it happened: make sure that entries from
  193. // the EPixelFormat enum and InitPixelFormat() calls match.
  194. AZ_Assert(false, "InitPixelFormats error: not all pixel formats have an implementation.");
  195. }
  196. }
  197. }
  198. EPixelFormat CPixelFormats::FindPixelFormatByName(const char* name)
  199. {
  200. if (m_pixelFormatNameMap.find(name) != m_pixelFormatNameMap.end())
  201. {
  202. return m_pixelFormatNameMap[name];
  203. }
  204. return ePixelFormat_Unknown;
  205. }
  206. const PixelFormatInfo* CPixelFormats::GetPixelFormatInfo(EPixelFormat format)
  207. {
  208. AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format);
  209. return &m_pixelFormatInfo[format];
  210. }
  211. bool CPixelFormats::IsPixelFormatUncompressed(EPixelFormat format)
  212. {
  213. AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format);
  214. return !m_pixelFormatInfo[format].bCompressed;
  215. }
  216. bool CPixelFormats::IsPixelFormatWithoutAlpha(EPixelFormat format)
  217. {
  218. AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format);
  219. return !m_pixelFormatInfo[format].bHasAlpha;
  220. }
  221. uint32 CPixelFormats::ComputeMaxMipCount(EPixelFormat format, uint32 width, uint32 height, uint32_t depth)
  222. {
  223. const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format);
  224. AZ_Assert(pFormatInfo != nullptr, "ComputeMaxMipCount: unsupport pixel format %d", format);
  225. uint32 tmpWidth = width;
  226. uint32 tmpHeight = height;
  227. uint32 tmpDepth = depth;
  228. bool bIgnoreBlockSize = CanImageSizeIgnoreBlockSize(format);
  229. uint32 mipCountW = 0;
  230. while ((tmpWidth >= pFormatInfo->minWidth) && (bIgnoreBlockSize || (tmpWidth % pFormatInfo->blockWidth == 0)))
  231. {
  232. ++mipCountW;
  233. tmpWidth >>= 1;
  234. }
  235. uint32 mipCountH = 0;
  236. while ((tmpHeight >= pFormatInfo->minHeight) && (bIgnoreBlockSize || (tmpHeight % pFormatInfo->blockHeight == 0)))
  237. {
  238. ++mipCountH;
  239. tmpHeight >>= 1;
  240. }
  241. uint32 mipCountD = 0;
  242. while ((tmpDepth >= 1))
  243. {
  244. ++mipCountD;
  245. tmpDepth >>= 1;
  246. }
  247. //for compressed image, use minmum mip out of W and H because any size below won't be compressed properly
  248. //for non-compressed image. use maximum mip count. for example the lowest two mips of 128x64 would be 2x1 and 1x1
  249. const uint32 mipCount = (pFormatInfo->bCompressed)
  250. ? AZStd::min<uint32>(mipCountW, mipCountH)
  251. : AZStd::max(AZStd::max<uint32>(mipCountW, mipCountH), mipCountD);
  252. // In some cases, user may call this function for image size which is qualified for this pixel format,
  253. // the mipCount could be 0 for those cases. Round it to 1 if it happend.
  254. return AZStd::max<uint32>((uint32)1, mipCount);
  255. }
  256. bool CPixelFormats::CanImageSizeIgnoreBlockSize(EPixelFormat format)
  257. {
  258. // ASTC is a kind of block compression but it doesn't need the image size to be interger mutiples of block size.
  259. // reference: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt
  260. //"For images which are not an integer multiple of the block size, additional texels are added to the edges
  261. // with maximum X and Y.These texels may be any color, as they will not be accessed."
  262. bool bIgnoreBlockSize = IsASTCFormat(format);
  263. return bIgnoreBlockSize;
  264. }
  265. bool CPixelFormats::IsImageSizeValid(EPixelFormat format, uint32 imageWidth, uint32 imageHeight, [[maybe_unused]] bool logWarning)
  266. {
  267. const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format);
  268. AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format);
  269. //if the format requires image to be sqaure and power of 2
  270. if (pFormatInfo->bSquarePow2 && ((imageWidth != imageHeight) || (imageWidth & (imageWidth - 1)) != 0))
  271. {
  272. AZ_Warning("ImageBuilder", !logWarning, "Image size need to be square and power of 2 for pixel format %s",
  273. pFormatInfo->szName);
  274. return false;
  275. }
  276. // minimum size required by the pixel format
  277. if (imageWidth < pFormatInfo->minWidth || imageHeight < pFormatInfo->minHeight)
  278. {
  279. AZ_Warning("ImageBuilder", !logWarning, "The image size (%dx%d) is smaller than minimum size (%dx%d) for pixel format %s",
  280. imageWidth, imageHeight, pFormatInfo->minWidth, pFormatInfo->minHeight, pFormatInfo->szName);
  281. return false;
  282. }
  283. //check image size againest block size
  284. if (!CanImageSizeIgnoreBlockSize(format))
  285. {
  286. if (imageWidth % pFormatInfo->blockWidth != 0 || imageHeight % pFormatInfo->blockHeight != 0)
  287. {
  288. AZ_Warning("ImageBuilder", !logWarning, "Image size (%dx%d) need to be integer multiplier of compression block size (%dx%d) for pixel format %s",
  289. imageWidth, imageHeight, pFormatInfo->minWidth, pFormatInfo->minHeight, pFormatInfo->szName);
  290. return false;
  291. }
  292. }
  293. return true;
  294. }
  295. AZ::u32 NextPowOf2(AZ::u32 value)
  296. {
  297. value--;
  298. value |= value >> 1;
  299. value |= value >> 2;
  300. value |= value >> 4;
  301. value |= value >> 8;
  302. value |= value >> 16;
  303. value++;
  304. return value;
  305. }
  306. void CPixelFormats::GetSuitableImageSize(EPixelFormat format, AZ::u32 imageWidth, AZ::u32 imageHeight,
  307. AZ::u32& outWidth, AZ::u32& outHeight)
  308. {
  309. const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format);
  310. AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format);
  311. outWidth = imageWidth;
  312. outHeight = imageHeight;
  313. // minimum size required by the pixel format
  314. if (outWidth < pFormatInfo->minWidth)
  315. {
  316. outWidth = pFormatInfo->minWidth;
  317. }
  318. if (outHeight < pFormatInfo->minHeight)
  319. {
  320. outHeight = pFormatInfo->minHeight;
  321. }
  322. if (pFormatInfo->bSquarePow2 && ((outWidth != outHeight) || (outWidth & (outWidth - 1)) != 0))
  323. {
  324. AZ::u32 sideSide = AZ::GetMax(outWidth, outHeight);
  325. outWidth = NextPowOf2(sideSide);
  326. outHeight = outWidth;
  327. }
  328. //check image size againest block size
  329. //if the format requires square and power of 2. we can skip this step
  330. if (!CanImageSizeIgnoreBlockSize(format) && !pFormatInfo->bSquarePow2)
  331. {
  332. if (outWidth % pFormatInfo->blockWidth != 0)
  333. {
  334. outWidth = AZ::RoundUpToMultiple(outWidth, pFormatInfo->blockWidth);
  335. }
  336. if (outHeight % pFormatInfo->blockHeight != 0)
  337. {
  338. outHeight = AZ::RoundUpToMultiple(outHeight, pFormatInfo->blockHeight);
  339. }
  340. }
  341. }
  342. uint32 CPixelFormats::EvaluateImageDataSize(EPixelFormat format, uint32 imageWidth, uint32 imageHeight)
  343. {
  344. const PixelFormatInfo* const pFormatInfo = GetPixelFormatInfo(format);
  345. AZ_Assert(pFormatInfo != nullptr, "IsImageSizeValid: unsupport pixel format %d", format);
  346. //the image should pass IsImageSizeValid test to be eavluated correctly
  347. if (!IsImageSizeValid(format, imageWidth, imageHeight, false))
  348. {
  349. return 0;
  350. }
  351. // get number of blocks and multiply with bits per block. Divided by 8 to get
  352. // final byte size
  353. return (AZ::DivideAndRoundUp(imageWidth, pFormatInfo->blockWidth) *
  354. AZ::DivideAndRoundUp(imageHeight, pFormatInfo->blockHeight) *
  355. pFormatInfo->bitsPerBlock) / 8;
  356. }
  357. bool CPixelFormats::IsFormatSingleChannel(EPixelFormat fmt)
  358. {
  359. return (m_pixelFormatInfo[fmt].nChannels == 1);
  360. }
  361. bool CPixelFormats::IsFormatSigned(EPixelFormat fmt)
  362. {
  363. // all these formats contain signed data, the FP-formats contain scale & biased unsigned data
  364. return (fmt == ePixelFormat_BC4s || fmt == ePixelFormat_BC5s /*|| fmt == ePixelFormat_BC6SH*/);
  365. }
  366. bool CPixelFormats::IsFormatFloatingPoint(EPixelFormat fmt, bool bFullPrecision)
  367. {
  368. // all these formats contain floating point data
  369. if (!bFullPrecision)
  370. {
  371. return ((fmt == ePixelFormat_R16F || fmt == ePixelFormat_R16G16F ||
  372. fmt == ePixelFormat_R16G16B16A16F) || (fmt == ePixelFormat_BC6UH || fmt == ePixelFormat_R9G9B9E5));
  373. }
  374. else
  375. {
  376. return ((fmt == ePixelFormat_R32F || fmt == ePixelFormat_R32G32F || fmt == ePixelFormat_R32G32B32A32F));
  377. }
  378. }
  379. } // namespace ImageProcessingAtom