ImageResource.cpp 8.7 KB

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