ImageResource.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. // Copyright (C) 2009-2023, 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/Core/ConfigSet.h>
  10. #include <AnKi/Util/Filesystem.h>
  11. namespace anki {
  12. static NumericCVar<U32> g_maxImageSizeCVar(CVarSubsystem::kResource, "MaxImageSize", 1024u * 1024u, 4u, kMaxU32, "Max image size to load");
  13. class ImageResource::LoadingContext
  14. {
  15. public:
  16. ImageLoader m_loader{&ResourceMemoryPool::getSingleton()};
  17. U32 m_faces = 0;
  18. U32 m_layerCount = 0;
  19. TextureType m_texType;
  20. TexturePtr m_tex;
  21. };
  22. /// Image upload async task.
  23. class ImageResource::TexUploadTask : public AsyncLoaderTask
  24. {
  25. public:
  26. ImageResource::LoadingContext m_ctx;
  27. Error operator()([[maybe_unused]] AsyncLoaderTaskContext& ctx) final
  28. {
  29. return ImageResource::load(m_ctx);
  30. }
  31. };
  32. ImageResource::~ImageResource()
  33. {
  34. }
  35. Error ImageResource::load(const ResourceFilename& filename, Bool async)
  36. {
  37. TexUploadTask* task;
  38. LoadingContext* ctx;
  39. LoadingContext localCtx;
  40. if(async)
  41. {
  42. task = ResourceManager::getSingleton().getAsyncLoader().newTask<TexUploadTask>();
  43. ctx = &task->m_ctx;
  44. }
  45. else
  46. {
  47. task = nullptr;
  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::kAllSampled | TextureUsageBit::kTransferDestination;
  55. U32 faces = 0;
  56. ResourceFilePtr file;
  57. ANKI_CHECK(openFile(filename, file));
  58. ANKI_CHECK(loader.load(file, filename, g_maxImageSizeCVar.get()));
  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. faces = 1;
  68. init.m_layerCount = 1;
  69. break;
  70. case ImageBinaryType::kCube:
  71. init.m_type = TextureType::kCube;
  72. init.m_depth = 1;
  73. faces = 6;
  74. init.m_layerCount = 1;
  75. break;
  76. case ImageBinaryType::k2DArray:
  77. init.m_type = TextureType::k2DArray;
  78. init.m_layerCount = loader.getLayerCount();
  79. init.m_depth = 1;
  80. faces = 1;
  81. break;
  82. case ImageBinaryType::k3D:
  83. init.m_type = TextureType::k3D;
  84. init.m_depth = loader.getDepth();
  85. init.m_layerCount = 1;
  86. faces = 1;
  87. break;
  88. default:
  89. ANKI_ASSERT(0);
  90. }
  91. // Internal format
  92. if(loader.getColorFormat() == ImageBinaryColorFormat::kRgb8)
  93. {
  94. switch(loader.getCompression())
  95. {
  96. case ImageBinaryDataCompression::kRaw:
  97. init.m_format = Format::kR8G8B8_Unorm;
  98. break;
  99. case ImageBinaryDataCompression::kS3tc:
  100. init.m_format = Format::kBC1_Rgb_Unorm_Block;
  101. break;
  102. case ImageBinaryDataCompression::kAstc:
  103. if(loader.getAstcBlockSize() == UVec2(4u))
  104. {
  105. init.m_format = Format::kASTC_4x4_Unorm_Block;
  106. }
  107. else
  108. {
  109. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  110. init.m_format = Format::kASTC_8x8_Unorm_Block;
  111. }
  112. break;
  113. default:
  114. ANKI_ASSERT(0);
  115. }
  116. }
  117. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgba8)
  118. {
  119. switch(loader.getCompression())
  120. {
  121. case ImageBinaryDataCompression::kRaw:
  122. init.m_format = Format::kR8G8B8A8_Unorm;
  123. break;
  124. case ImageBinaryDataCompression::kS3tc:
  125. init.m_format = Format::kBC3_Unorm_Block;
  126. break;
  127. case ImageBinaryDataCompression::kAstc:
  128. if(loader.getAstcBlockSize() == UVec2(4u))
  129. {
  130. init.m_format = Format::kASTC_4x4_Unorm_Block;
  131. }
  132. else
  133. {
  134. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  135. init.m_format = Format::kASTC_8x8_Unorm_Block;
  136. }
  137. break;
  138. default:
  139. ANKI_ASSERT(0);
  140. }
  141. }
  142. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbFloat)
  143. {
  144. switch(loader.getCompression())
  145. {
  146. case ImageBinaryDataCompression::kS3tc:
  147. init.m_format = Format::kBC6H_Ufloat_Block;
  148. break;
  149. case ImageBinaryDataCompression::kAstc:
  150. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  151. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  152. break;
  153. default:
  154. ANKI_ASSERT(0);
  155. }
  156. }
  157. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbaFloat)
  158. {
  159. switch(loader.getCompression())
  160. {
  161. case ImageBinaryDataCompression::kRaw:
  162. init.m_format = Format::kR32G32B32A32_Sfloat;
  163. break;
  164. case ImageBinaryDataCompression::kAstc:
  165. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  166. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  167. break;
  168. default:
  169. ANKI_ASSERT(0);
  170. }
  171. }
  172. else
  173. {
  174. ANKI_ASSERT(0);
  175. }
  176. // mipmapsCount
  177. init.m_mipmapCount = U8(loader.getMipmapCount());
  178. // Create the texture
  179. m_tex = GrManager::getSingleton().newTexture(init);
  180. // Transition it. TODO remove that eventually
  181. {
  182. CommandBufferInitInfo cmdbinit;
  183. cmdbinit.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
  184. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbinit);
  185. TextureSubresourceInfo subresource;
  186. subresource.m_faceCount = textureTypeIsCube(init.m_type) ? 6 : 1;
  187. subresource.m_layerCount = init.m_layerCount;
  188. subresource.m_mipmapCount = init.m_mipmapCount;
  189. const TextureBarrierInfo barrier = {m_tex.get(), TextureUsageBit::kNone, TextureUsageBit::kAllSampled, subresource};
  190. cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
  191. FencePtr outFence;
  192. cmdb->flush({}, &outFence);
  193. outFence->clientWait(60.0_sec);
  194. }
  195. // Set the context
  196. ctx->m_faces = faces;
  197. ctx->m_layerCount = init.m_layerCount;
  198. ctx->m_texType = init.m_type;
  199. ctx->m_tex = m_tex;
  200. // Upload the data
  201. if(async)
  202. {
  203. ResourceManager::getSingleton().getAsyncLoader().submitTask(task);
  204. }
  205. else
  206. {
  207. ANKI_CHECK(load(*ctx));
  208. }
  209. m_size = UVec3(init.m_width, init.m_height, init.m_depth);
  210. m_layerCount = init.m_layerCount;
  211. // Create the texture view
  212. TextureViewInitInfo viewInit(m_tex.get(), "Rsrc");
  213. m_texView = GrManager::getSingleton().newTextureView(viewInit);
  214. return Error::kNone;
  215. }
  216. Error ImageResource::load(LoadingContext& ctx)
  217. {
  218. const U32 copyCount = ctx.m_layerCount * ctx.m_faces * ctx.m_loader.getMipmapCount();
  219. for(U32 b = 0; b < copyCount; b += kMaxCopiesBeforeFlush)
  220. {
  221. const U32 begin = b;
  222. const U32 end = min(copyCount, b + kMaxCopiesBeforeFlush);
  223. CommandBufferInitInfo ci;
  224. ci.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
  225. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(ci);
  226. // Set the barriers of the batch
  227. Array<TextureBarrierInfo, kMaxCopiesBeforeFlush> barriers;
  228. U32 barrierCount = 0;
  229. for(U32 i = begin; i < end; ++i)
  230. {
  231. U32 mip, layer, face;
  232. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  233. TextureBarrierInfo& barrier = barriers[barrierCount++];
  234. barrier = {ctx.m_tex.get(), TextureUsageBit::kNone, TextureUsageBit::kTransferDestination, TextureSubresourceInfo()};
  235. if(ctx.m_texType == TextureType::k3D)
  236. {
  237. barrier.m_subresource = TextureVolumeInfo(mip);
  238. TextureVolumeInfo vol(mip);
  239. }
  240. else
  241. {
  242. barrier.m_subresource = TextureSurfaceInfo(mip, 0, face, layer);
  243. }
  244. }
  245. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  246. // Do the copies
  247. Array<TransferGpuAllocatorHandle, kMaxCopiesBeforeFlush> handles;
  248. U32 handleCount = 0;
  249. for(U32 i = begin; i < end; ++i)
  250. {
  251. U32 mip, layer, face;
  252. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  253. PtrSize surfOrVolSize;
  254. const void* surfOrVolData;
  255. PtrSize allocationSize;
  256. if(ctx.m_texType == TextureType::k3D)
  257. {
  258. const auto& vol = ctx.m_loader.getVolume(mip);
  259. surfOrVolSize = vol.m_data.getSize();
  260. surfOrVolData = &vol.m_data[0];
  261. allocationSize = computeVolumeSize(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip, ctx.m_tex->getDepth() >> mip,
  262. ctx.m_tex->getFormat());
  263. }
  264. else
  265. {
  266. const auto& surf = ctx.m_loader.getSurface(mip, face, layer);
  267. surfOrVolSize = surf.m_data.getSize();
  268. surfOrVolData = &surf.m_data[0];
  269. allocationSize = computeSurfaceSize(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip, ctx.m_tex->getFormat());
  270. }
  271. ANKI_ASSERT(allocationSize >= surfOrVolSize);
  272. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  273. ANKI_CHECK(ResourceManager::getSingleton().getTransferGpuAllocator().allocate(allocationSize, handle));
  274. void* data = handle.getMappedMemory();
  275. ANKI_ASSERT(data);
  276. memcpy(data, surfOrVolData, surfOrVolSize);
  277. // Create temp tex view
  278. TextureSubresourceInfo subresource;
  279. if(ctx.m_texType == TextureType::k3D)
  280. {
  281. subresource = TextureSubresourceInfo(TextureVolumeInfo(mip));
  282. }
  283. else
  284. {
  285. subresource = TextureSubresourceInfo(TextureSurfaceInfo(mip, 0, face, layer));
  286. }
  287. TextureViewPtr tmpView = GrManager::getSingleton().newTextureView(TextureViewInitInfo(ctx.m_tex.get(), subresource, "RsrcTmp"));
  288. cmdb->copyBufferToTextureView(&handle.getBuffer(), handle.getOffset(), handle.getRange(), tmpView.get());
  289. }
  290. // Set the barriers of the batch
  291. barrierCount = 0;
  292. for(U32 i = begin; i < end; ++i)
  293. {
  294. U32 mip, layer, face;
  295. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  296. TextureBarrierInfo& barrier = barriers[barrierCount++];
  297. barrier.m_previousUsage = TextureUsageBit::kTransferDestination;
  298. barrier.m_nextUsage = TextureUsageBit::kSampledFragment | TextureUsageBit::kSampledGeometry;
  299. if(ctx.m_texType == TextureType::k3D)
  300. {
  301. barrier.m_subresource = TextureVolumeInfo(mip);
  302. }
  303. else
  304. {
  305. barrier.m_subresource = TextureSurfaceInfo(mip, 0, face, layer);
  306. }
  307. }
  308. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  309. // Flush batch
  310. FencePtr fence;
  311. cmdb->flush({}, &fence);
  312. for(U i = 0; i < handleCount; ++i)
  313. {
  314. ResourceManager::getSingleton().getTransferGpuAllocator().release(handles[i], fence);
  315. }
  316. cmdb.reset(nullptr);
  317. }
  318. return Error::kNone;
  319. }
  320. } // end namespace anki