ImageResource.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright (C) 2009-2021, 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()(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::ALL_SAMPLED | TextureUsageBit::TRANSFER_DESTINATION;
  64. init.m_initialUsage = TextureUsageBit::ALL_SAMPLED;
  65. U32 faces = 0;
  66. ResourceFilePtr file;
  67. ANKI_CHECK(openFile(filename, file));
  68. ANKI_CHECK(loader.load(file, filename, getConfig().getRsrcMaxImageSize()));
  69. // Various sizes
  70. init.m_width = loader.getWidth();
  71. init.m_height = loader.getHeight();
  72. switch(loader.getImageType())
  73. {
  74. case ImageBinaryType::_2D:
  75. init.m_type = TextureType::_2D;
  76. init.m_depth = 1;
  77. faces = 1;
  78. init.m_layerCount = 1;
  79. break;
  80. case ImageBinaryType::CUBE:
  81. init.m_type = TextureType::CUBE;
  82. init.m_depth = 1;
  83. faces = 6;
  84. init.m_layerCount = 1;
  85. break;
  86. case ImageBinaryType::_2D_ARRAY:
  87. init.m_type = TextureType::_2D_ARRAY;
  88. init.m_layerCount = loader.getLayerCount();
  89. init.m_depth = 1;
  90. faces = 1;
  91. break;
  92. case ImageBinaryType::_3D:
  93. init.m_type = TextureType::_3D;
  94. init.m_depth = loader.getDepth();
  95. init.m_layerCount = 1;
  96. faces = 1;
  97. break;
  98. default:
  99. ANKI_ASSERT(0);
  100. }
  101. // Internal format
  102. if(loader.getColorFormat() == ImageBinaryColorFormat::RGB8)
  103. {
  104. switch(loader.getCompression())
  105. {
  106. case ImageBinaryDataCompression::RAW:
  107. init.m_format = Format::R8G8B8_UNORM;
  108. break;
  109. case ImageBinaryDataCompression::S3TC:
  110. init.m_format = Format::BC1_RGB_UNORM_BLOCK;
  111. break;
  112. case ImageBinaryDataCompression::ASTC:
  113. if(loader.getAstcBlockSize() == UVec2(4u))
  114. {
  115. init.m_format = Format::ASTC_4x4_UNORM_BLOCK;
  116. }
  117. else
  118. {
  119. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  120. init.m_format = Format::ASTC_8x8_UNORM_BLOCK;
  121. }
  122. break;
  123. default:
  124. ANKI_ASSERT(0);
  125. }
  126. }
  127. else if(loader.getColorFormat() == ImageBinaryColorFormat::RGBA8)
  128. {
  129. switch(loader.getCompression())
  130. {
  131. case ImageBinaryDataCompression::RAW:
  132. init.m_format = Format::R8G8B8A8_UNORM;
  133. break;
  134. case ImageBinaryDataCompression::S3TC:
  135. init.m_format = Format::BC3_UNORM_BLOCK;
  136. break;
  137. case ImageBinaryDataCompression::ASTC:
  138. if(loader.getAstcBlockSize() == UVec2(4u))
  139. {
  140. init.m_format = Format::ASTC_4x4_UNORM_BLOCK;
  141. }
  142. else
  143. {
  144. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  145. init.m_format = Format::ASTC_8x8_UNORM_BLOCK;
  146. }
  147. break;
  148. default:
  149. ANKI_ASSERT(0);
  150. }
  151. }
  152. else
  153. {
  154. ANKI_ASSERT(0);
  155. }
  156. // mipmapsCount
  157. init.m_mipmapCount = U8(loader.getMipmapCount());
  158. // Create the texture
  159. m_tex = getManager().getGrManager().newTexture(init);
  160. // Set the context
  161. ctx->m_faces = faces;
  162. ctx->m_layerCount = init.m_layerCount;
  163. ctx->m_gr = &getManager().getGrManager();
  164. ctx->m_trfAlloc = &getManager().getTransferGpuAllocator();
  165. ctx->m_texType = init.m_type;
  166. ctx->m_tex = m_tex;
  167. // Upload the data
  168. if(async)
  169. {
  170. getManager().getAsyncLoader().submitTask(task);
  171. }
  172. else
  173. {
  174. ANKI_CHECK(load(*ctx));
  175. }
  176. m_size = UVec3(init.m_width, init.m_height, init.m_depth);
  177. m_layerCount = init.m_layerCount;
  178. // Create the texture view
  179. TextureViewInitInfo viewInit(m_tex, "Rsrc");
  180. m_texView = getManager().getGrManager().newTextureView(viewInit);
  181. return Error::NONE;
  182. }
  183. Error ImageResource::load(LoadingContext& ctx)
  184. {
  185. const U32 copyCount = ctx.m_layerCount * ctx.m_faces * ctx.m_loader.getMipmapCount();
  186. for(U32 b = 0; b < copyCount; b += MAX_COPIES_BEFORE_FLUSH)
  187. {
  188. const U32 begin = b;
  189. const U32 end = min(copyCount, b + MAX_COPIES_BEFORE_FLUSH);
  190. CommandBufferInitInfo ci;
  191. ci.m_flags = CommandBufferFlag::GENERAL_WORK | CommandBufferFlag::SMALL_BATCH;
  192. CommandBufferPtr cmdb = ctx.m_gr->newCommandBuffer(ci);
  193. // Set the barriers of the batch
  194. for(U32 i = begin; i < end; ++i)
  195. {
  196. U32 mip, layer, face;
  197. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  198. if(ctx.m_texType == TextureType::_3D)
  199. {
  200. TextureVolumeInfo vol(mip);
  201. cmdb->setTextureVolumeBarrier(ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION,
  202. vol);
  203. }
  204. else
  205. {
  206. TextureSurfaceInfo surf(mip, 0, face, layer);
  207. cmdb->setTextureSurfaceBarrier(ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION,
  208. surf);
  209. }
  210. }
  211. // Do the copies
  212. Array<TransferGpuAllocatorHandle, MAX_COPIES_BEFORE_FLUSH> handles;
  213. U32 handleCount = 0;
  214. for(U32 i = begin; i < end; ++i)
  215. {
  216. U32 mip, layer, face;
  217. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  218. PtrSize surfOrVolSize;
  219. const void* surfOrVolData;
  220. PtrSize allocationSize;
  221. if(ctx.m_texType == TextureType::_3D)
  222. {
  223. const auto& vol = ctx.m_loader.getVolume(mip);
  224. surfOrVolSize = vol.m_data.getSize();
  225. surfOrVolData = &vol.m_data[0];
  226. allocationSize = computeVolumeSize(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip,
  227. ctx.m_tex->getDepth() >> mip, ctx.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(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip,
  235. ctx.m_tex->getFormat());
  236. }
  237. ANKI_ASSERT(allocationSize >= surfOrVolSize);
  238. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  239. ANKI_CHECK(ctx.m_trfAlloc->allocate(allocationSize, handle));
  240. void* data = handle.getMappedMemory();
  241. ANKI_ASSERT(data);
  242. memcpy(data, surfOrVolData, surfOrVolSize);
  243. // Create temp tex view
  244. TextureSubresourceInfo subresource;
  245. if(ctx.m_texType == TextureType::_3D)
  246. {
  247. subresource = TextureSubresourceInfo(TextureVolumeInfo(mip));
  248. }
  249. else
  250. {
  251. subresource = TextureSubresourceInfo(TextureSurfaceInfo(mip, 0, face, layer));
  252. }
  253. TextureViewPtr tmpView = ctx.m_gr->newTextureView(TextureViewInitInfo(ctx.m_tex, subresource, "RsrcTmp"));
  254. cmdb->copyBufferToTextureView(handle.getBuffer(), handle.getOffset(), handle.getRange(), tmpView);
  255. }
  256. // Set the barriers of the batch
  257. for(U32 i = begin; i < end; ++i)
  258. {
  259. U32 mip, layer, face;
  260. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  261. if(ctx.m_texType == TextureType::_3D)
  262. {
  263. TextureVolumeInfo vol(mip);
  264. cmdb->setTextureVolumeBarrier(ctx.m_tex, TextureUsageBit::TRANSFER_DESTINATION,
  265. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_GEOMETRY,
  266. vol);
  267. }
  268. else
  269. {
  270. TextureSurfaceInfo surf(mip, 0, face, layer);
  271. cmdb->setTextureSurfaceBarrier(ctx.m_tex, TextureUsageBit::TRANSFER_DESTINATION,
  272. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_GEOMETRY,
  273. surf);
  274. }
  275. }
  276. // Flush batch
  277. FencePtr fence;
  278. cmdb->flush({}, &fence);
  279. for(U i = 0; i < handleCount; ++i)
  280. {
  281. ctx.m_trfAlloc->release(handles[i], fence);
  282. }
  283. cmdb.reset(nullptr);
  284. }
  285. return Error::NONE;
  286. }
  287. } // end namespace anki