ImageResource.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/ImageResource.h>
  6. #include <AnKi/Resource/ImageLoader.h>
  7. #include <AnKi/Resource/ResourceManager.h>
  8. #include <AnKi/Resource/AsyncLoader.h>
  9. #include <AnKi/Util/CVarSet.h>
  10. #include <AnKi/Util/Filesystem.h>
  11. namespace anki {
  12. class ImageResource::LoadingContext
  13. {
  14. public:
  15. ImageLoader m_loader{&ResourceMemoryPool::getSingleton()};
  16. ImageResourcePtr m_image;
  17. };
  18. /// Image upload async task.
  19. class ImageResource::TexUploadTask : public AsyncLoaderTask
  20. {
  21. public:
  22. ImageResource::LoadingContext m_ctx;
  23. Error operator()([[maybe_unused]] AsyncLoaderTaskContext& ctx) final
  24. {
  25. return m_ctx.m_image->loadAsync(m_ctx);
  26. }
  27. static BaseMemoryPool& getMemoryPool()
  28. {
  29. return ResourceMemoryPool::getSingleton();
  30. }
  31. };
  32. ImageResource::~ImageResource()
  33. {
  34. }
  35. Error ImageResource::load(const ResourceFilename& filename, Bool async)
  36. {
  37. UniquePtr<TexUploadTask> task;
  38. LoadingContext* ctx;
  39. LoadingContext localCtx;
  40. if(async)
  41. {
  42. task.reset(AsyncLoader::getSingleton().newTask<TexUploadTask>());
  43. ctx = &task->m_ctx;
  44. ctx->m_image.reset(this);
  45. }
  46. else
  47. {
  48. ctx = &localCtx;
  49. }
  50. ImageLoader& loader = ctx->m_loader;
  51. String filenameExt;
  52. getFilepathFilename(filename, filenameExt);
  53. TextureInitInfo init(filenameExt);
  54. init.m_usage = TextureUsageBit::kAllSrv | TextureUsageBit::kCopyDestination;
  55. ResourceFilePtr file;
  56. ANKI_CHECK(openFile(filename, file));
  57. ANKI_CHECK(loader.load(file, filename, g_cvarRsrcMaxImageSize));
  58. m_avgColor = loader.getAverageColor();
  59. // Various sizes
  60. init.m_width = loader.getWidth();
  61. init.m_height = loader.getHeight();
  62. switch(loader.getImageType())
  63. {
  64. case ImageBinaryType::k2D:
  65. init.m_type = TextureType::k2D;
  66. init.m_depth = 1;
  67. init.m_layerCount = 1;
  68. break;
  69. case ImageBinaryType::kCube:
  70. init.m_type = TextureType::kCube;
  71. init.m_depth = 1;
  72. init.m_layerCount = 1;
  73. break;
  74. case ImageBinaryType::k2DArray:
  75. init.m_type = TextureType::k2DArray;
  76. init.m_layerCount = loader.getLayerCount();
  77. init.m_depth = 1;
  78. break;
  79. case ImageBinaryType::k3D:
  80. init.m_type = TextureType::k3D;
  81. init.m_depth = loader.getDepth();
  82. init.m_layerCount = 1;
  83. break;
  84. default:
  85. ANKI_ASSERT(0);
  86. }
  87. // Internal format
  88. if(loader.getColorFormat() == ImageBinaryColorFormat::kRgb8)
  89. {
  90. switch(loader.getCompression())
  91. {
  92. case ImageBinaryDataCompression::kRaw:
  93. init.m_format = Format::kR8G8B8_Unorm;
  94. break;
  95. case ImageBinaryDataCompression::kS3tc:
  96. init.m_format = Format::kBC1_Rgba_Unorm_Block;
  97. break;
  98. case ImageBinaryDataCompression::kAstc:
  99. if(loader.getAstcBlockSize() == UVec2(4u))
  100. {
  101. init.m_format = Format::kASTC_4x4_Unorm_Block;
  102. }
  103. else
  104. {
  105. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  106. init.m_format = Format::kASTC_8x8_Unorm_Block;
  107. }
  108. break;
  109. default:
  110. ANKI_ASSERT(0);
  111. }
  112. }
  113. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgba8)
  114. {
  115. switch(loader.getCompression())
  116. {
  117. case ImageBinaryDataCompression::kRaw:
  118. init.m_format = Format::kR8G8B8A8_Unorm;
  119. break;
  120. case ImageBinaryDataCompression::kS3tc:
  121. init.m_format = Format::kBC3_Unorm_Block;
  122. break;
  123. case ImageBinaryDataCompression::kAstc:
  124. if(loader.getAstcBlockSize() == UVec2(4u))
  125. {
  126. init.m_format = Format::kASTC_4x4_Unorm_Block;
  127. }
  128. else
  129. {
  130. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  131. init.m_format = Format::kASTC_8x8_Unorm_Block;
  132. }
  133. break;
  134. default:
  135. ANKI_ASSERT(0);
  136. }
  137. }
  138. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbFloat)
  139. {
  140. switch(loader.getCompression())
  141. {
  142. case ImageBinaryDataCompression::kS3tc:
  143. init.m_format = Format::kBC6H_Ufloat_Block;
  144. break;
  145. case ImageBinaryDataCompression::kAstc:
  146. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  147. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  148. break;
  149. default:
  150. ANKI_ASSERT(0);
  151. }
  152. }
  153. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbaFloat)
  154. {
  155. switch(loader.getCompression())
  156. {
  157. case ImageBinaryDataCompression::kRaw:
  158. init.m_format = Format::kR32G32B32A32_Sfloat;
  159. break;
  160. case ImageBinaryDataCompression::kAstc:
  161. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  162. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  163. break;
  164. default:
  165. ANKI_ASSERT(0);
  166. }
  167. }
  168. else
  169. {
  170. ANKI_ASSERT(0);
  171. }
  172. // mipmapsCount
  173. init.m_mipmapCount = U8(loader.getMipmapCount());
  174. m_pendingLoadedMips.setNonAtomically(init.m_mipmapCount);
  175. // Create the texture
  176. m_tex = GrManager::getSingleton().newTexture(init);
  177. // Upload the data
  178. if(async)
  179. {
  180. TexUploadTask* pTask;
  181. task.moveAndReset(pTask);
  182. AsyncLoader::getSingleton().submitTask(pTask, AsyncLoaderPriority::kMedium);
  183. }
  184. else
  185. {
  186. ANKI_CHECK(loadAsync(*ctx));
  187. }
  188. return Error::kNone;
  189. }
  190. Error ImageResource::loadAsync(LoadingContext& ctx) const
  191. {
  192. const U32 faceCount = textureTypeIsCube(m_tex->getTextureType()) ? 6 : 1;
  193. const U32 copyCount = m_tex->getLayerCount() * faceCount * ctx.m_loader.getMipmapCount();
  194. for(U32 b = 0; b < copyCount; b += kMaxCopiesBeforeFlush)
  195. {
  196. const U32 begin = b;
  197. const U32 end = min(copyCount, b + kMaxCopiesBeforeFlush);
  198. CommandBufferInitInfo ci;
  199. ci.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
  200. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(ci);
  201. // Set the barriers of the batch
  202. Array<TextureBarrierInfo, kMaxCopiesBeforeFlush> barriers;
  203. U32 barrierCount = 0;
  204. for(U32 i = begin; i < end; ++i)
  205. {
  206. U32 mip, layer, face;
  207. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  208. barriers[barrierCount++] = {TextureView(m_tex.get(), TextureSubresourceDesc::surface(mip, face, layer)), TextureUsageBit::kNone,
  209. TextureUsageBit::kCopyDestination};
  210. }
  211. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  212. // Do the copies
  213. Array<TransferGpuAllocatorHandle, kMaxCopiesBeforeFlush> handles;
  214. U32 handleCount = 0;
  215. for(U32 i = begin; i < end; ++i)
  216. {
  217. U32 mip, layer, face;
  218. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  219. PtrSize surfOrVolSize;
  220. const void* surfOrVolData;
  221. PtrSize allocationSize;
  222. if(m_tex->getTextureType() == TextureType::k3D)
  223. {
  224. const auto& vol = ctx.m_loader.getVolume(mip);
  225. surfOrVolSize = vol.m_data.getSize();
  226. surfOrVolData = &vol.m_data[0];
  227. allocationSize = computeVolumeSize(m_tex->getWidth() >> mip, m_tex->getHeight() >> mip, m_tex->getDepth() >> mip, m_tex->getFormat());
  228. }
  229. else
  230. {
  231. const auto& surf = ctx.m_loader.getSurface(mip, face, layer);
  232. surfOrVolSize = surf.m_data.getSize();
  233. surfOrVolData = &surf.m_data[0];
  234. allocationSize = computeSurfaceSize(m_tex->getWidth() >> mip, m_tex->getHeight() >> mip, m_tex->getFormat());
  235. }
  236. ANKI_ASSERT(allocationSize >= surfOrVolSize);
  237. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  238. ANKI_CHECK(TransferGpuAllocator::getSingleton().allocate(allocationSize, handle));
  239. void* data = handle.getMappedMemory();
  240. ANKI_ASSERT(data);
  241. memcpy(data, surfOrVolData, surfOrVolSize);
  242. // Create temp tex view
  243. const TextureSubresourceDesc subresource = TextureSubresourceDesc::surface(mip, face, layer);
  244. cmdb->copyBufferToTexture(handle, TextureView(m_tex.get(), subresource));
  245. }
  246. // Set the barriers of the batch
  247. barrierCount = 0;
  248. for(U32 i = begin; i < end; ++i)
  249. {
  250. U32 mip, layer, face;
  251. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  252. barriers[barrierCount++] = {TextureView(m_tex.get(), TextureSubresourceDesc::surface(mip, face, layer)),
  253. TextureUsageBit::kCopyDestination, TextureUsageBit::kAllSrv};
  254. }
  255. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  256. // Flush batch
  257. FencePtr fence;
  258. cmdb->endRecording();
  259. GrManager::getSingleton().submit(cmdb.get(), {}, &fence);
  260. for(U i = 0; i < handleCount; ++i)
  261. {
  262. TransferGpuAllocator::getSingleton().release(handles[i], fence);
  263. }
  264. cmdb.reset(nullptr);
  265. }
  266. [[maybe_unused]] const U32 prevVal = m_pendingLoadedMips.fetchSub(m_tex->getMipmapCount());
  267. ANKI_ASSERT(prevVal == m_tex->getMipmapCount());
  268. return Error::kNone;
  269. }
  270. } // end namespace anki