ImageResource.cpp 10.0 KB

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