ImageMipChainAsset.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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/ImageMipChainAsset.h>
  9. #include <Atom/RPI.Reflect/Allocators.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. namespace AZ
  12. {
  13. namespace RPI
  14. {
  15. AZ_CLASS_ALLOCATOR_IMPL(ImageMipChainAsset, ImageMipChainAssetAllocator)
  16. static bool ConvertOldVersions(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  17. {
  18. if (classElement.GetVersion() < 1)
  19. {
  20. // We need to convert the vectors because we added a custom allocator
  21. // and the serialization system doens't automatically convert between two different classes
  22. {
  23. auto crc32 = AZ::Crc32("m_imageData");
  24. auto* vectorElement = classElement.FindSubElement(crc32);
  25. if (vectorElement)
  26. {
  27. // Get the old data
  28. AZStd::vector<uint8_t> oldData;
  29. if (vectorElement->GetData(oldData))
  30. {
  31. // Convert the vector with the new allocator
  32. vectorElement->Convert(context, AZ::AzTypeInfo<AZStd::vector<uint8_t, ImageMipChainAsset::Allocator>>::Uuid());
  33. // Copy old data to new data
  34. AZStd::vector<uint8_t, ImageMipChainAsset::Allocator> newData(oldData.size());
  35. ::memcpy(newData.data(), oldData.data(), newData.size());
  36. // Set the new data
  37. vectorElement->SetData(context, newData);
  38. }
  39. }
  40. }
  41. {
  42. auto crc32 = AZ::Crc32("m_subImageDataOffsets");
  43. auto* vectorElement = classElement.FindSubElement(crc32);
  44. if (vectorElement)
  45. {
  46. AZStd::vector<AZ::u64> oldData;
  47. if (classElement.GetChildData(crc32, oldData))
  48. {
  49. // Convert the vector with the new allocator
  50. vectorElement->Convert(context, AZ::AzTypeInfo<AZStd::vector<AZ::u64, ImageMipChainAsset::Allocator>>::Uuid());
  51. for (const auto& element : oldData)
  52. {
  53. // Convert each vector and re add it. During convertion all sub elements were removed.
  54. vectorElement->AddElementWithData<AZ::u64>(context, "element", element);
  55. }
  56. }
  57. }
  58. }
  59. }
  60. return true;
  61. }
  62. void ImageMipChainAsset::Reflect(ReflectContext* context)
  63. {
  64. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  65. {
  66. // Need to register the old type with the Serializer so we can read it in order to convert it
  67. serializeContext->RegisterGenericType<AZStd::vector<uint8_t>>();
  68. serializeContext->RegisterGenericType<AZStd::vector<u64>>();
  69. serializeContext->Class<ImageMipChainAsset, Data::AssetData>()
  70. ->Version(1, &ConvertOldVersions)
  71. ->Field("m_mipLevels", &ImageMipChainAsset::m_mipLevels)
  72. ->Field("m_arraySize", &ImageMipChainAsset::m_arraySize)
  73. ->Field("m_mipToSubImageOffset", &ImageMipChainAsset::m_mipToSubImageOffset)
  74. ->Field("m_subImageLayouts", &ImageMipChainAsset::m_subImageLayouts)
  75. ->Field("m_subImageDataOffsets", &ImageMipChainAsset::m_subImageDataOffsets)
  76. ->Field("m_imageData", &ImageMipChainAsset::m_imageData)
  77. ;
  78. }
  79. }
  80. uint16_t ImageMipChainAsset::GetMipLevelCount() const
  81. {
  82. return m_mipLevels;
  83. }
  84. uint16_t ImageMipChainAsset::GetArraySize() const
  85. {
  86. return m_arraySize;
  87. }
  88. size_t ImageMipChainAsset::GetSubImageCount() const
  89. {
  90. return m_subImageDatas.size();
  91. }
  92. AZStd::span<const uint8_t> ImageMipChainAsset::GetSubImageData(uint32_t mipSlice, uint32_t arraySlice) const
  93. {
  94. return GetSubImageData(mipSlice * m_arraySize + arraySlice);
  95. }
  96. AZStd::span<const uint8_t> ImageMipChainAsset::GetSubImageData(uint32_t subImageIndex) const
  97. {
  98. AZ_Assert(subImageIndex < m_subImageDataOffsets.size() && subImageIndex < m_subImageDatas.size(), "subImageIndex is out of range");
  99. // The offset vector contains an extra sentinel value.
  100. const size_t dataSize = m_subImageDataOffsets[subImageIndex + 1] - m_subImageDataOffsets[subImageIndex];
  101. return AZStd::span<const uint8_t>(reinterpret_cast<const uint8_t*>(m_subImageDatas[subImageIndex].m_data), dataSize);
  102. }
  103. const RHI::DeviceImageSubresourceLayout& ImageMipChainAsset::GetSubImageLayout(uint32_t mipSlice) const
  104. {
  105. return m_subImageLayouts[mipSlice];
  106. }
  107. const ImageMipChainAsset::MipSliceList& ImageMipChainAsset::GetMipSlices() const
  108. {
  109. return m_mipSlices;
  110. }
  111. size_t ImageMipChainAsset::GetImageDataSize() const
  112. {
  113. return m_imageData.size();
  114. }
  115. void ImageMipChainAsset::CopyFrom(const ImageMipChainAsset& source)
  116. {
  117. m_mipLevels = source.m_mipLevels;
  118. m_arraySize = source.m_arraySize;
  119. m_mipToSubImageOffset = source.m_mipToSubImageOffset;
  120. m_subImageLayouts = source.m_subImageLayouts;
  121. m_subImageDataOffsets = source.m_subImageDataOffsets;
  122. m_imageData = source.m_imageData;
  123. Init();
  124. }
  125. void ImageMipChainAsset::Init()
  126. {
  127. const size_t subImageCount = m_mipLevels * m_arraySize;
  128. AZ_Assert(m_status != AssetStatus::Ready, "ImageMipChainAsset has already been initialized!");
  129. AZ_Assert(m_subImageDataOffsets.size() == subImageCount + 1, "Expected image data offsets vector to be subImageCount + 1");
  130. AZ_Assert(m_subImageDatas.empty(), "Expected sub-image data to be empty");
  131. m_subImageDatas.resize(subImageCount);
  132. for (size_t subImageIndex = 0; subImageIndex < subImageCount; ++subImageIndex)
  133. {
  134. const uintptr_t ptrOffset = m_subImageDataOffsets[subImageIndex];
  135. const uintptr_t ptrBase = reinterpret_cast<uintptr_t>(m_imageData.data());
  136. m_subImageDatas[subImageIndex].m_data = reinterpret_cast<const void*>(ptrBase + ptrOffset);
  137. }
  138. for (uint16_t mipSliceIndex = 0; mipSliceIndex < m_mipLevels; ++mipSliceIndex)
  139. {
  140. RHI::StreamingImageMipSlice mipSlice;
  141. mipSlice.m_subresources = AZStd::span<const RHI::StreamingImageSubresourceData>(&m_subImageDatas[m_arraySize * mipSliceIndex], m_arraySize);
  142. mipSlice.m_subresourceLayout = m_subImageLayouts[mipSliceIndex];
  143. m_mipSlices.push_back(mipSlice);
  144. }
  145. }
  146. void ImageMipChainAsset::SetReady()
  147. {
  148. m_status = AssetStatus::Ready;
  149. }
  150. Data::AssetHandler::LoadResult ImageMipChainAssetHandler::LoadAssetData(
  151. const Data::Asset<Data::AssetData>& asset,
  152. AZStd::shared_ptr<Data::AssetDataStream> stream,
  153. const Data::AssetFilterCB& assetLoadFilterCB)
  154. {
  155. Data::AssetHandler::LoadResult result = Base::LoadAssetData(asset, stream, assetLoadFilterCB);
  156. if (result == Data::AssetHandler::LoadResult::LoadComplete)
  157. {
  158. asset.GetAs<ImageMipChainAsset>()->Init();
  159. }
  160. return result;
  161. }
  162. }
  163. }