ImageResource.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. U32 faces = 0;
  56. ResourceFilePtr file;
  57. ANKI_CHECK(openFile(filename, file));
  58. ANKI_CHECK(loader.load(file, filename, g_cvarRsrcMaxImageSize));
  59. m_avgColor = loader.getAverageColor();
  60. // Various sizes
  61. init.m_width = loader.getWidth();
  62. init.m_height = loader.getHeight();
  63. switch(loader.getImageType())
  64. {
  65. case ImageBinaryType::k2D:
  66. init.m_type = TextureType::k2D;
  67. init.m_depth = 1;
  68. faces = 1;
  69. init.m_layerCount = 1;
  70. break;
  71. case ImageBinaryType::kCube:
  72. init.m_type = TextureType::kCube;
  73. init.m_depth = 1;
  74. faces = 6;
  75. init.m_layerCount = 1;
  76. break;
  77. case ImageBinaryType::k2DArray:
  78. init.m_type = TextureType::k2DArray;
  79. init.m_layerCount = loader.getLayerCount();
  80. init.m_depth = 1;
  81. faces = 1;
  82. break;
  83. case ImageBinaryType::k3D:
  84. init.m_type = TextureType::k3D;
  85. init.m_depth = loader.getDepth();
  86. init.m_layerCount = 1;
  87. faces = 1;
  88. break;
  89. default:
  90. ANKI_ASSERT(0);
  91. }
  92. // Internal format
  93. if(loader.getColorFormat() == ImageBinaryColorFormat::kRgb8)
  94. {
  95. switch(loader.getCompression())
  96. {
  97. case ImageBinaryDataCompression::kRaw:
  98. init.m_format = Format::kR8G8B8_Unorm;
  99. break;
  100. case ImageBinaryDataCompression::kS3tc:
  101. init.m_format = Format::kBC1_Rgba_Unorm_Block;
  102. break;
  103. case ImageBinaryDataCompression::kAstc:
  104. if(loader.getAstcBlockSize() == UVec2(4u))
  105. {
  106. init.m_format = Format::kASTC_4x4_Unorm_Block;
  107. }
  108. else
  109. {
  110. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  111. init.m_format = Format::kASTC_8x8_Unorm_Block;
  112. }
  113. break;
  114. default:
  115. ANKI_ASSERT(0);
  116. }
  117. }
  118. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgba8)
  119. {
  120. switch(loader.getCompression())
  121. {
  122. case ImageBinaryDataCompression::kRaw:
  123. init.m_format = Format::kR8G8B8A8_Unorm;
  124. break;
  125. case ImageBinaryDataCompression::kS3tc:
  126. init.m_format = Format::kBC3_Unorm_Block;
  127. break;
  128. case ImageBinaryDataCompression::kAstc:
  129. if(loader.getAstcBlockSize() == UVec2(4u))
  130. {
  131. init.m_format = Format::kASTC_4x4_Unorm_Block;
  132. }
  133. else
  134. {
  135. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  136. init.m_format = Format::kASTC_8x8_Unorm_Block;
  137. }
  138. break;
  139. default:
  140. ANKI_ASSERT(0);
  141. }
  142. }
  143. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbFloat)
  144. {
  145. switch(loader.getCompression())
  146. {
  147. case ImageBinaryDataCompression::kS3tc:
  148. init.m_format = Format::kBC6H_Ufloat_Block;
  149. break;
  150. case ImageBinaryDataCompression::kAstc:
  151. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  152. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  153. break;
  154. default:
  155. ANKI_ASSERT(0);
  156. }
  157. }
  158. else if(loader.getColorFormat() == ImageBinaryColorFormat::kRgbaFloat)
  159. {
  160. switch(loader.getCompression())
  161. {
  162. case ImageBinaryDataCompression::kRaw:
  163. init.m_format = Format::kR32G32B32A32_Sfloat;
  164. break;
  165. case ImageBinaryDataCompression::kAstc:
  166. ANKI_ASSERT(loader.getAstcBlockSize() == UVec2(8u));
  167. init.m_format = Format::kASTC_8x8_Sfloat_Block;
  168. break;
  169. default:
  170. ANKI_ASSERT(0);
  171. }
  172. }
  173. else
  174. {
  175. ANKI_ASSERT(0);
  176. }
  177. // mipmapsCount
  178. init.m_mipmapCount = U8(loader.getMipmapCount());
  179. // Create the texture
  180. m_tex = GrManager::getSingleton().newTexture(init);
  181. // Upload the data
  182. if(async)
  183. {
  184. TexUploadTask* pTask;
  185. task.moveAndReset(pTask);
  186. AsyncLoader::getSingleton().submitTask(pTask, AsyncLoaderPriority::kMedium);
  187. }
  188. else
  189. {
  190. ANKI_CHECK(loadAsync(*ctx));
  191. }
  192. return Error::kNone;
  193. }
  194. Error ImageResource::loadAsync(LoadingContext& ctx) const
  195. {
  196. const U32 faceCount = textureTypeIsCube(m_tex->getTextureType()) ? 6 : 1;
  197. const U32 copyCount = m_tex->getLayerCount() * faceCount * ctx.m_loader.getMipmapCount();
  198. for(U32 b = 0; b < copyCount; b += kMaxCopiesBeforeFlush)
  199. {
  200. const U32 begin = b;
  201. const U32 end = min(copyCount, b + kMaxCopiesBeforeFlush);
  202. CommandBufferInitInfo ci;
  203. ci.m_flags = CommandBufferFlag::kGeneralWork | CommandBufferFlag::kSmallBatch;
  204. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(ci);
  205. // Set the barriers of the batch
  206. Array<TextureBarrierInfo, kMaxCopiesBeforeFlush> barriers;
  207. U32 barrierCount = 0;
  208. for(U32 i = begin; i < end; ++i)
  209. {
  210. U32 mip, layer, face;
  211. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  212. barriers[barrierCount++] = {TextureView(m_tex.get(), TextureSubresourceDesc::surface(mip, face, layer)), TextureUsageBit::kAllSrv,
  213. TextureUsageBit::kCopyDestination};
  214. }
  215. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  216. // Do the copies
  217. Array<TransferGpuAllocatorHandle, kMaxCopiesBeforeFlush> handles;
  218. U32 handleCount = 0;
  219. for(U32 i = begin; i < end; ++i)
  220. {
  221. U32 mip, layer, face;
  222. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  223. PtrSize surfOrVolSize;
  224. const void* surfOrVolData;
  225. PtrSize allocationSize;
  226. if(m_tex->getTextureType() == TextureType::k3D)
  227. {
  228. const auto& vol = ctx.m_loader.getVolume(mip);
  229. surfOrVolSize = vol.m_data.getSize();
  230. surfOrVolData = &vol.m_data[0];
  231. allocationSize = computeVolumeSize(m_tex->getWidth() >> mip, m_tex->getHeight() >> mip, m_tex->getDepth() >> mip, m_tex->getFormat());
  232. }
  233. else
  234. {
  235. const auto& surf = ctx.m_loader.getSurface(mip, face, layer);
  236. surfOrVolSize = surf.m_data.getSize();
  237. surfOrVolData = &surf.m_data[0];
  238. allocationSize = computeSurfaceSize(m_tex->getWidth() >> mip, m_tex->getHeight() >> mip, m_tex->getFormat());
  239. }
  240. ANKI_ASSERT(allocationSize >= surfOrVolSize);
  241. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  242. ANKI_CHECK(TransferGpuAllocator::getSingleton().allocate(allocationSize, handle));
  243. void* data = handle.getMappedMemory();
  244. ANKI_ASSERT(data);
  245. memcpy(data, surfOrVolData, surfOrVolSize);
  246. // Create temp tex view
  247. const TextureSubresourceDesc subresource = TextureSubresourceDesc::surface(mip, face, layer);
  248. cmdb->copyBufferToTexture(handle, TextureView(m_tex.get(), subresource));
  249. }
  250. // Set the barriers of the batch
  251. barrierCount = 0;
  252. for(U32 i = begin; i < end; ++i)
  253. {
  254. U32 mip, layer, face;
  255. unflatten3dArrayIndex(m_tex->getLayerCount(), faceCount, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  256. barriers[barrierCount++] = {TextureView(m_tex.get(), TextureSubresourceDesc::surface(mip, face, layer)),
  257. TextureUsageBit::kCopyDestination, TextureUsageBit::kSrvPixel | TextureUsageBit::kSrvGeometry};
  258. }
  259. cmdb->setPipelineBarrier({&barriers[0], barrierCount}, {}, {});
  260. // Flush batch
  261. FencePtr fence;
  262. cmdb->endRecording();
  263. GrManager::getSingleton().submit(cmdb.get(), {}, &fence);
  264. for(U i = 0; i < handleCount; ++i)
  265. {
  266. TransferGpuAllocator::getSingleton().release(handles[i], fence);
  267. }
  268. cmdb.reset(nullptr);
  269. }
  270. m_loadedMipCount.store(m_tex->getMipmapCount());
  271. return Error::kNone;
  272. }
  273. } // end namespace anki