ImageResource.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. namespace anki
  10. {
  11. class ImageResource::LoadingContext
  12. {
  13. public:
  14. ImageLoader m_loader;
  15. U32 m_faces = 0;
  16. U32 m_layerCount = 0;
  17. GrManager* m_gr ANKI_DEBUG_CODE(= nullptr);
  18. TransferGpuAllocator* m_trfAlloc ANKI_DEBUG_CODE(= nullptr);
  19. TextureType m_texType;
  20. TexturePtr m_tex;
  21. LoadingContext(GenericMemoryPoolAllocator<U8> alloc)
  22. : m_loader(alloc)
  23. {
  24. }
  25. };
  26. /// Image upload async task.
  27. class ImageResource::TexUploadTask : public AsyncLoaderTask
  28. {
  29. public:
  30. ImageResource::LoadingContext m_ctx;
  31. TexUploadTask(GenericMemoryPoolAllocator<U8> alloc)
  32. : m_ctx(alloc)
  33. {
  34. }
  35. Error operator()(AsyncLoaderTaskContext& ctx) final
  36. {
  37. return ImageResource::load(m_ctx);
  38. }
  39. };
  40. ImageResource::~ImageResource()
  41. {
  42. }
  43. Error ImageResource::load(const ResourceFilename& filename, Bool async)
  44. {
  45. TexUploadTask* task;
  46. LoadingContext* ctx;
  47. LoadingContext localCtx(getTempAllocator());
  48. if(async)
  49. {
  50. task = getManager().getAsyncLoader().newTask<TexUploadTask>(getManager().getAsyncLoader().getAllocator());
  51. ctx = &task->m_ctx;
  52. }
  53. else
  54. {
  55. task = nullptr;
  56. ctx = &localCtx;
  57. }
  58. ImageLoader& loader = ctx->m_loader;
  59. TextureInitInfo init("RsrcTex");
  60. init.m_usage = TextureUsageBit::ALL_SAMPLED | TextureUsageBit::TRANSFER_DESTINATION;
  61. init.m_initialUsage = TextureUsageBit::ALL_SAMPLED;
  62. U32 faces = 0;
  63. ResourceFilePtr file;
  64. ANKI_CHECK(openFile(filename, file));
  65. ANKI_CHECK(loader.load(file, filename, getManager().getMaxImageSize()));
  66. // Various sizes
  67. init.m_width = loader.getWidth();
  68. init.m_height = loader.getHeight();
  69. switch(loader.getImageType())
  70. {
  71. case ImageBinaryType::_2D:
  72. init.m_type = TextureType::_2D;
  73. init.m_depth = 1;
  74. faces = 1;
  75. init.m_layerCount = 1;
  76. break;
  77. case ImageBinaryType::CUBE:
  78. init.m_type = TextureType::CUBE;
  79. init.m_depth = 1;
  80. faces = 6;
  81. init.m_layerCount = 1;
  82. break;
  83. case ImageBinaryType::_2D_ARRAY:
  84. init.m_type = TextureType::_2D_ARRAY;
  85. init.m_layerCount = loader.getLayerCount();
  86. init.m_depth = 1;
  87. faces = 1;
  88. break;
  89. case ImageBinaryType::_3D:
  90. init.m_type = TextureType::_3D;
  91. init.m_depth = loader.getDepth();
  92. init.m_layerCount = 1;
  93. faces = 1;
  94. break;
  95. default:
  96. ANKI_ASSERT(0);
  97. }
  98. // Internal format
  99. if(loader.getColorFormat() == ImageBinaryColorFormat::RGB8)
  100. {
  101. switch(loader.getCompression())
  102. {
  103. case ImageBinaryDataCompression::RAW:
  104. init.m_format = Format::R8G8B8_UNORM;
  105. break;
  106. case ImageBinaryDataCompression::S3TC:
  107. init.m_format = Format::BC1_RGB_UNORM_BLOCK;
  108. break;
  109. default:
  110. ANKI_ASSERT(0);
  111. }
  112. }
  113. else if(loader.getColorFormat() == ImageBinaryColorFormat::RGBA8)
  114. {
  115. switch(loader.getCompression())
  116. {
  117. case ImageBinaryDataCompression::RAW:
  118. init.m_format = Format::R8G8B8A8_UNORM;
  119. break;
  120. case ImageBinaryDataCompression::S3TC:
  121. init.m_format = Format::BC3_UNORM_BLOCK;
  122. break;
  123. default:
  124. ANKI_ASSERT(0);
  125. }
  126. }
  127. else
  128. {
  129. ANKI_ASSERT(0);
  130. }
  131. // mipmapsCount
  132. init.m_mipmapCount = U8(loader.getMipmapCount());
  133. // Create the texture
  134. m_tex = getManager().getGrManager().newTexture(init);
  135. // Set the context
  136. ctx->m_faces = faces;
  137. ctx->m_layerCount = init.m_layerCount;
  138. ctx->m_gr = &getManager().getGrManager();
  139. ctx->m_trfAlloc = &getManager().getTransferGpuAllocator();
  140. ctx->m_texType = init.m_type;
  141. ctx->m_tex = m_tex;
  142. // Upload the data
  143. if(async)
  144. {
  145. getManager().getAsyncLoader().submitTask(task);
  146. }
  147. else
  148. {
  149. ANKI_CHECK(load(*ctx));
  150. }
  151. m_size = UVec3(init.m_width, init.m_height, init.m_depth);
  152. m_layerCount = init.m_layerCount;
  153. // Create the texture view
  154. TextureViewInitInfo viewInit(m_tex, "Rsrc");
  155. m_texView = getManager().getGrManager().newTextureView(viewInit);
  156. return Error::NONE;
  157. }
  158. Error ImageResource::load(LoadingContext& ctx)
  159. {
  160. const U32 copyCount = ctx.m_layerCount * ctx.m_faces * ctx.m_loader.getMipmapCount();
  161. for(U32 b = 0; b < copyCount; b += MAX_COPIES_BEFORE_FLUSH)
  162. {
  163. const U32 begin = b;
  164. const U32 end = min(copyCount, b + MAX_COPIES_BEFORE_FLUSH);
  165. CommandBufferInitInfo ci;
  166. ci.m_flags = CommandBufferFlag::GENERAL_WORK | CommandBufferFlag::SMALL_BATCH;
  167. CommandBufferPtr cmdb = ctx.m_gr->newCommandBuffer(ci);
  168. // Set the barriers of the batch
  169. for(U32 i = begin; i < end; ++i)
  170. {
  171. U32 mip, layer, face;
  172. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  173. if(ctx.m_texType == TextureType::_3D)
  174. {
  175. TextureVolumeInfo vol(mip);
  176. cmdb->setTextureVolumeBarrier(ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION,
  177. vol);
  178. }
  179. else
  180. {
  181. TextureSurfaceInfo surf(mip, 0, face, layer);
  182. cmdb->setTextureSurfaceBarrier(ctx.m_tex, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION,
  183. surf);
  184. }
  185. }
  186. // Do the copies
  187. Array<TransferGpuAllocatorHandle, MAX_COPIES_BEFORE_FLUSH> handles;
  188. U32 handleCount = 0;
  189. for(U32 i = begin; i < end; ++i)
  190. {
  191. U32 mip, layer, face;
  192. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  193. PtrSize surfOrVolSize;
  194. const void* surfOrVolData;
  195. PtrSize allocationSize;
  196. if(ctx.m_texType == TextureType::_3D)
  197. {
  198. const auto& vol = ctx.m_loader.getVolume(mip);
  199. surfOrVolSize = vol.m_data.getSize();
  200. surfOrVolData = &vol.m_data[0];
  201. allocationSize = computeVolumeSize(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip,
  202. ctx.m_tex->getDepth() >> mip, ctx.m_tex->getFormat());
  203. }
  204. else
  205. {
  206. const auto& surf = ctx.m_loader.getSurface(mip, face, layer);
  207. surfOrVolSize = surf.m_data.getSize();
  208. surfOrVolData = &surf.m_data[0];
  209. allocationSize = computeSurfaceSize(ctx.m_tex->getWidth() >> mip, ctx.m_tex->getHeight() >> mip,
  210. ctx.m_tex->getFormat());
  211. }
  212. ANKI_ASSERT(allocationSize >= surfOrVolSize);
  213. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  214. ANKI_CHECK(ctx.m_trfAlloc->allocate(allocationSize, handle));
  215. void* data = handle.getMappedMemory();
  216. ANKI_ASSERT(data);
  217. memcpy(data, surfOrVolData, surfOrVolSize);
  218. // Create temp tex view
  219. TextureSubresourceInfo subresource;
  220. if(ctx.m_texType == TextureType::_3D)
  221. {
  222. subresource = TextureSubresourceInfo(TextureVolumeInfo(mip));
  223. }
  224. else
  225. {
  226. subresource = TextureSubresourceInfo(TextureSurfaceInfo(mip, 0, face, layer));
  227. }
  228. TextureViewPtr tmpView = ctx.m_gr->newTextureView(TextureViewInitInfo(ctx.m_tex, subresource, "RsrcTmp"));
  229. cmdb->copyBufferToTextureView(handle.getBuffer(), handle.getOffset(), handle.getRange(), tmpView);
  230. }
  231. // Set the barriers of the batch
  232. for(U32 i = begin; i < end; ++i)
  233. {
  234. U32 mip, layer, face;
  235. unflatten3dArrayIndex(ctx.m_layerCount, ctx.m_faces, ctx.m_loader.getMipmapCount(), i, layer, face, mip);
  236. if(ctx.m_texType == TextureType::_3D)
  237. {
  238. TextureVolumeInfo vol(mip);
  239. cmdb->setTextureVolumeBarrier(ctx.m_tex, TextureUsageBit::TRANSFER_DESTINATION,
  240. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_GEOMETRY,
  241. vol);
  242. }
  243. else
  244. {
  245. TextureSurfaceInfo surf(mip, 0, face, layer);
  246. cmdb->setTextureSurfaceBarrier(ctx.m_tex, TextureUsageBit::TRANSFER_DESTINATION,
  247. TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_GEOMETRY,
  248. surf);
  249. }
  250. }
  251. // Flush batch
  252. FencePtr fence;
  253. cmdb->flush({}, &fence);
  254. for(U i = 0; i < handleCount; ++i)
  255. {
  256. ctx.m_trfAlloc->release(handles[i], fence);
  257. }
  258. cmdb.reset(nullptr);
  259. }
  260. return Error::NONE;
  261. }
  262. } // end namespace anki