3
0

StreamingImageAsset.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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 <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
  9. #include <AzCore/Asset/AssetSerializer.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. namespace AZ
  12. {
  13. namespace RPI
  14. {
  15. const char* StreamingImageAsset::DisplayName = "StreamingImage";
  16. const char* StreamingImageAsset::Group = "Image";
  17. const char* StreamingImageAsset::Extension = "streamingimage";
  18. void StreamingImageAsset::Reflect(ReflectContext* context)
  19. {
  20. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  21. {
  22. serializeContext->Class<MipChain>()
  23. ->Field("m_mipOffset", &MipChain::m_mipOffset)
  24. ->Field("m_mipCount", &MipChain::m_mipCount)
  25. ->Field("m_asset", &MipChain::m_asset)
  26. ;
  27. serializeContext->Class<StreamingImageAsset, ImageAsset>()
  28. ->Version(2) // Added m_averageColor field
  29. ->Field("m_mipLevelToChainIndex", &StreamingImageAsset::m_mipLevelToChainIndex)
  30. ->Field("m_mipChains", &StreamingImageAsset::m_mipChains)
  31. ->Field("m_flags", &StreamingImageAsset::m_flags)
  32. ->Field("m_tailMipChain", &StreamingImageAsset::m_tailMipChain)
  33. ->Field("m_totalImageDataSize", &StreamingImageAsset::m_totalImageDataSize)
  34. ->Field("m_averageColor", &StreamingImageAsset::m_averageColor)
  35. ->Field("m_tags", &StreamingImageAsset::m_tags)
  36. ;
  37. }
  38. }
  39. const Data::Asset<ImageMipChainAsset>& StreamingImageAsset::GetMipChainAsset(size_t mipChainIndex) const
  40. {
  41. return m_mipChains[mipChainIndex].m_asset;
  42. }
  43. const ImageMipChainAsset& StreamingImageAsset::GetTailMipChain() const
  44. {
  45. return m_tailMipChain;
  46. }
  47. size_t StreamingImageAsset::GetMipChainCount() const
  48. {
  49. return m_mipChains.size();
  50. }
  51. size_t StreamingImageAsset::GetMipChainIndex(size_t mipLevel) const
  52. {
  53. if (mipLevel >= m_imageDescriptor.m_mipLevels)
  54. {
  55. AZ_Assert(false, "Input mipLevel doesn't exist");
  56. mipLevel = m_imageDescriptor.m_mipLevels - 1;
  57. }
  58. return m_mipLevelToChainIndex[mipLevel];
  59. }
  60. size_t StreamingImageAsset::GetMipLevel(size_t mipChainIndex) const
  61. {
  62. return m_mipChains[mipChainIndex].m_mipOffset;
  63. }
  64. size_t StreamingImageAsset::GetMipCount(size_t mipChainIndex) const
  65. {
  66. return m_mipChains[mipChainIndex].m_mipCount;
  67. }
  68. const Data::AssetId& StreamingImageAsset::GetPoolAssetId() const
  69. {
  70. return m_poolAssetId;
  71. }
  72. StreamingImageFlags StreamingImageAsset::GetFlags() const
  73. {
  74. return m_flags;
  75. }
  76. size_t StreamingImageAsset::GetTotalImageDataSize() const
  77. {
  78. return m_totalImageDataSize;
  79. }
  80. Color StreamingImageAsset::GetAverageColor() const
  81. {
  82. if (m_averageColor.IsFinite())
  83. {
  84. return m_averageColor;
  85. }
  86. else
  87. {
  88. AZ_Warning(
  89. "Streaming Image", false,
  90. "Non-finite average color, it probably was never initialized. Returning black.");
  91. return Color(0.0f);
  92. }
  93. }
  94. RHI::ImageDescriptor StreamingImageAsset::GetImageDescriptorForMipLevel(AZ::u32 mipLevel) const
  95. {
  96. RHI::ImageDescriptor imageDescriptor = GetImageDescriptor();
  97. // Retrieve the layout for the particular mip level.
  98. // The levels get stored in a series of ImageMipChainAssets, which keep a
  99. // record of an offset so that you can calculate the sub-image index
  100. // based on the actual mip level.
  101. const ImageMipChainAsset* mipChainAsset = GetImageMipChainAsset(mipLevel);
  102. if (mipChainAsset)
  103. {
  104. auto mipChainIndex = GetMipChainIndex(mipLevel);
  105. auto mipChainOffset = aznumeric_cast<AZ::u32>(GetMipLevel(mipChainIndex));
  106. auto layout = mipChainAsset->GetSubImageLayout(mipLevel - mipChainOffset);
  107. imageDescriptor.m_size = layout.m_size;
  108. }
  109. else
  110. {
  111. AZ_Warning("Streaming Image", false, "Mip level index (%u) out of bounds, only %u levels available for asset %s",
  112. mipLevel, imageDescriptor.m_mipLevels, m_assetId.ToString<AZStd::string>().c_str());
  113. return RHI::ImageDescriptor();
  114. }
  115. return imageDescriptor;
  116. }
  117. const AZStd::vector<AZ::Name>& StreamingImageAsset::GetTags() const
  118. {
  119. return m_tags;
  120. }
  121. void StreamingImageAsset::RemoveFrontMipchains(size_t mipChainLevel)
  122. {
  123. mipChainLevel = AZStd::min(mipChainLevel, m_mipChains.size() - 1);
  124. if (mipChainLevel == 0)
  125. {
  126. return;
  127. }
  128. AZ::u16 mipmapShift = m_mipChains[mipChainLevel].m_mipOffset;
  129. AZStd::move(m_mipLevelToChainIndex.begin() + mipmapShift, m_mipLevelToChainIndex.end(), m_mipLevelToChainIndex.begin());
  130. AZ_Assert(m_mipLevelToChainIndex.front() == mipChainLevel, "unmatching mipchain index");
  131. for (AZ::u16& chainIndex : m_mipLevelToChainIndex)
  132. {
  133. chainIndex -= aznumeric_cast<AZ::u16>(mipChainLevel);
  134. }
  135. AZStd::move(m_mipChains.begin() + mipChainLevel, m_mipChains.end(), m_mipChains.begin());
  136. m_mipChains.resize(m_mipChains.size() - mipChainLevel);
  137. for (auto& mipChain : m_mipChains)
  138. {
  139. // Assert that the offset does not become negative after subtraction:
  140. AZ_Assert(mipChain.m_mipOffset >= mipmapShift, "unexpected mipoffset");
  141. mipChain.m_mipOffset -= mipmapShift;
  142. }
  143. m_imageDescriptor.m_mipLevels -= mipmapShift;
  144. m_imageDescriptor.m_size = m_imageDescriptor.m_size.GetReducedMip(mipmapShift);
  145. }
  146. AZStd::span<const uint8_t> StreamingImageAsset::GetSubImageData(uint32_t mip, uint32_t slice)
  147. {
  148. auto mipChainIndex = GetMipChainIndex(mip);
  149. const ImageMipChainAsset* mipChainAsset = GetImageMipChainAsset(mip);
  150. if (mipChainAsset == nullptr)
  151. {
  152. MipChain& mipChain = m_mipChains[mipChainIndex];
  153. if (mipChain.m_asset.QueueLoad())
  154. {
  155. mipChain.m_asset.BlockUntilLoadComplete();
  156. }
  157. mipChainAsset = GetImageMipChainAsset(mip);
  158. }
  159. if (mipChainAsset == nullptr)
  160. {
  161. AZ_Warning("Streaming Image", false, "MipChain asset wasn't loaded for assetId %s",
  162. m_assetId.ToString<AZStd::string>().c_str());
  163. return AZStd::span<const uint8_t>();
  164. }
  165. auto mipChainOffset = aznumeric_cast<AZ::u32>(GetMipLevel(mipChainIndex));
  166. return mipChainAsset->GetSubImageData(mip - mipChainOffset, slice);
  167. }
  168. const ImageMipChainAsset* StreamingImageAsset::GetImageMipChainAsset(AZ::u32 mipLevel) const
  169. {
  170. if (mipLevel >= m_mipLevelToChainIndex.size())
  171. {
  172. return nullptr;
  173. }
  174. size_t mipChainIndex = m_mipLevelToChainIndex[mipLevel];
  175. const MipChain& mipChain = m_mipChains[mipChainIndex];
  176. const ImageMipChainAsset* mipChainAsset = nullptr;
  177. // Use m_tailMipChain if it's the last mip chain
  178. if (mipChainIndex == m_mipChains.size() - 1)
  179. {
  180. mipChainAsset = &m_tailMipChain;
  181. }
  182. else if (mipChain.m_asset.IsReady())
  183. {
  184. mipChainAsset = mipChain.m_asset.Get();
  185. }
  186. return mipChainAsset;
  187. }
  188. bool StreamingImageAsset::HasFullMipChainAssets() const
  189. {
  190. for (const auto& mipChain : m_mipChains)
  191. {
  192. if (mipChain.m_asset.GetId().IsValid() && !mipChain.m_asset.GetData())
  193. {
  194. // if the asset id is valid but the asset doesn't contain asset data, return false
  195. return false;
  196. }
  197. }
  198. return true;
  199. }
  200. }
  201. }