TextureImpl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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/Gr/gl/TextureImpl.h>
  6. #include <AnKi/Gr/Texture.h>
  7. #include <AnKi/Gr/gl/Error.h>
  8. #include <AnKi/Util/Functions.h>
  9. #include <AnKi/Gr/GrManager.h>
  10. #include <AnKi/Gr/gl/GrManagerImpl.h>
  11. #include <AnKi/Gr/gl/TextureViewImpl.h>
  12. #include <AnKi/Gr/gl/RenderingThread.h>
  13. #include <AnKi/Gr/gl/CommandBufferImpl.h>
  14. namespace anki {
  15. static GLenum convertTextureType(TextureType type)
  16. {
  17. GLenum out = GL_NONE;
  18. switch(type)
  19. {
  20. case TextureType::_1D:
  21. out = GL_TEXTURE_1D;
  22. break;
  23. case TextureType::_2D:
  24. out = GL_TEXTURE_2D;
  25. break;
  26. case TextureType::_3D:
  27. out = GL_TEXTURE_3D;
  28. break;
  29. case TextureType::_2D_ARRAY:
  30. out = GL_TEXTURE_2D_ARRAY;
  31. break;
  32. case TextureType::CUBE:
  33. out = GL_TEXTURE_CUBE_MAP;
  34. break;
  35. case TextureType::CUBE_ARRAY:
  36. out = GL_TEXTURE_CUBE_MAP_ARRAY;
  37. break;
  38. default:
  39. ANKI_ASSERT(0);
  40. };
  41. return out;
  42. }
  43. class DeleteTextureCommand final : public GlCommand
  44. {
  45. public:
  46. GLuint m_tex;
  47. HashMap<TextureSubresourceInfo, MicroTextureView> m_views;
  48. GrAllocator<U8> m_alloc;
  49. DeleteTextureCommand(GLuint tex, HashMap<TextureSubresourceInfo, MicroTextureView>& views, GrAllocator<U8> alloc)
  50. : m_tex(tex)
  51. , m_views(std::move(views))
  52. , m_alloc(alloc)
  53. {
  54. }
  55. Error operator()(GlState& state)
  56. {
  57. // Delete views
  58. auto it = m_views.getBegin();
  59. auto end = m_views.getEnd();
  60. while(it != end)
  61. {
  62. const MicroTextureView& view = *it;
  63. glDeleteTextures(1, &view.m_glName);
  64. ++it;
  65. }
  66. m_views.destroy(m_alloc);
  67. // Delete texture
  68. if(m_tex != 0)
  69. {
  70. glDeleteTextures(1, &m_tex);
  71. }
  72. return Error::NONE;
  73. }
  74. };
  75. TextureImpl::~TextureImpl()
  76. {
  77. GrManager& manager = getManager();
  78. RenderingThread& thread = static_cast<GrManagerImpl&>(manager).getRenderingThread();
  79. if(!thread.isServerThread())
  80. {
  81. CommandBufferPtr commands;
  82. commands = manager.newCommandBuffer(CommandBufferInitInfo());
  83. static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteTextureCommand>(m_glName, m_viewsMap,
  84. getAllocator());
  85. static_cast<CommandBufferImpl&>(*commands).flush();
  86. }
  87. else
  88. {
  89. DeleteTextureCommand cmd(m_glName, m_viewsMap, getAllocator());
  90. cmd(static_cast<GrManagerImpl&>(manager).getState());
  91. }
  92. m_glName = 0;
  93. }
  94. void TextureImpl::bind() const
  95. {
  96. glActiveTexture(GL_TEXTURE0);
  97. glBindTexture(m_target, m_glName);
  98. }
  99. void TextureImpl::preInit(const TextureInitInfo& init)
  100. {
  101. ANKI_ASSERT(init.isValid());
  102. m_width = init.m_width;
  103. m_height = init.m_height;
  104. m_depth = init.m_depth;
  105. m_layerCount = init.m_layerCount;
  106. m_target = convertTextureType(init.m_type);
  107. m_texType = init.m_type;
  108. m_format = init.m_format;
  109. m_usage = init.m_usage;
  110. convertTextureInformation(init.m_format, m_compressed, m_glFormat, m_internalFormat, m_glType, m_aspect);
  111. if(m_target != GL_TEXTURE_3D)
  112. {
  113. m_mipCount = min<U>(init.m_mipmapCount, computeMaxMipmapCount2d(m_width, m_height));
  114. }
  115. else
  116. {
  117. m_mipCount = min<U>(init.m_mipmapCount, computeMaxMipmapCount3d(m_width, m_height, m_depth));
  118. }
  119. // Surface count
  120. switch(m_target)
  121. {
  122. case GL_TEXTURE_1D:
  123. case GL_TEXTURE_2D:
  124. case GL_TEXTURE_2D_MULTISAMPLE:
  125. m_surfaceCountPerLevel = 1;
  126. m_faceCount = 1;
  127. break;
  128. case GL_TEXTURE_CUBE_MAP:
  129. m_surfaceCountPerLevel = 6;
  130. m_faceCount = 6;
  131. break;
  132. case GL_TEXTURE_CUBE_MAP_ARRAY:
  133. m_surfaceCountPerLevel = m_layerCount * 6;
  134. m_faceCount = 6;
  135. break;
  136. case GL_TEXTURE_2D_ARRAY:
  137. m_surfaceCountPerLevel = m_layerCount;
  138. m_faceCount = 1;
  139. break;
  140. case GL_TEXTURE_3D:
  141. m_surfaceCountPerLevel = m_depth;
  142. m_faceCount = 1;
  143. break;
  144. default:
  145. ANKI_ASSERT(0);
  146. }
  147. }
  148. void TextureImpl::init(const TextureInitInfo& init)
  149. {
  150. ANKI_ASSERT(!isCreated());
  151. GrAllocator<U8> alloc = getAllocator();
  152. // Create
  153. //
  154. glGenTextures(1, &m_glName);
  155. ANKI_ASSERT(m_glName != 0);
  156. bind();
  157. // Create storage
  158. switch(m_target)
  159. {
  160. case GL_TEXTURE_2D:
  161. case GL_TEXTURE_CUBE_MAP:
  162. glTexStorage2D(m_target, m_mipCount, m_internalFormat, m_width, m_height);
  163. break;
  164. case GL_TEXTURE_CUBE_MAP_ARRAY:
  165. glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_layerCount * 6);
  166. break;
  167. case GL_TEXTURE_2D_ARRAY:
  168. glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_layerCount);
  169. break;
  170. case GL_TEXTURE_3D:
  171. glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_depth);
  172. break;
  173. case GL_TEXTURE_2D_MULTISAMPLE:
  174. glTexStorage2DMultisample(m_target, init.m_samples, m_internalFormat, m_width, m_height, GL_FALSE);
  175. break;
  176. default:
  177. ANKI_ASSERT(0);
  178. }
  179. // Make sure that the texture is complete
  180. glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, m_mipCount - 1);
  181. ANKI_CHECK_GL_ERROR();
  182. }
  183. void TextureImpl::copyFromBuffer(const TextureSubresourceInfo& subresource, GLuint pbo, PtrSize offset,
  184. PtrSize dataSize) const
  185. {
  186. ANKI_ASSERT(isSubresourceGoodForCopyFromBuffer(subresource));
  187. ANKI_ASSERT(dataSize > 0);
  188. const U mipmap = subresource.m_firstMipmap;
  189. const U w = m_width >> mipmap;
  190. const U h = m_height >> mipmap;
  191. const U d = m_depth >> mipmap;
  192. ANKI_ASSERT(w > 0);
  193. ANKI_ASSERT(h > 0);
  194. bind();
  195. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
  196. const void* ptrOffset = numberToPtr<const void*>(offset);
  197. switch(m_target)
  198. {
  199. case GL_TEXTURE_2D:
  200. if(!m_compressed)
  201. {
  202. glTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_glFormat, m_glType, ptrOffset);
  203. }
  204. else
  205. {
  206. glCompressedTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_glFormat, dataSize, ptrOffset);
  207. }
  208. break;
  209. case GL_TEXTURE_CUBE_MAP:
  210. {
  211. const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, subresource.m_firstFace, 0));
  212. if(!m_compressed)
  213. {
  214. glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, m_glType,
  215. ptrOffset);
  216. }
  217. else
  218. {
  219. glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat,
  220. dataSize, ptrOffset);
  221. }
  222. break;
  223. }
  224. case GL_TEXTURE_2D_ARRAY:
  225. {
  226. const U surfIdx = computeSurfaceIdx(TextureSurfaceInfo(mipmap, 0, 0, subresource.m_firstLayer));
  227. if(!m_compressed)
  228. {
  229. glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, m_glType, ptrOffset);
  230. }
  231. else
  232. {
  233. glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, dataSize, ptrOffset);
  234. }
  235. break;
  236. }
  237. case GL_TEXTURE_3D:
  238. ANKI_ASSERT(d > 0);
  239. if(!m_compressed)
  240. {
  241. glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, m_glType, ptrOffset);
  242. }
  243. else
  244. {
  245. glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, dataSize, ptrOffset);
  246. }
  247. break;
  248. default:
  249. ANKI_ASSERT(0);
  250. }
  251. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  252. ANKI_CHECK_GL_ERROR();
  253. }
  254. void TextureImpl::generateMipmaps2d(const TextureViewImpl& view) const
  255. {
  256. ANKI_ASSERT(view.m_tex.get() == this);
  257. ANKI_ASSERT(isSubresourceGoodForMipmapGeneration(view.getSubresource()));
  258. ANKI_ASSERT(!m_compressed);
  259. if(m_surfaceCountPerLevel > 1)
  260. {
  261. glGenerateTextureMipmap(view.m_view.m_glName);
  262. }
  263. else
  264. {
  265. glGenerateTextureMipmap(m_glName);
  266. }
  267. }
  268. void TextureImpl::clear(const TextureSubresourceInfo& subresource, const ClearValue& clearValue) const
  269. {
  270. ANKI_ASSERT(isCreated());
  271. ANKI_ASSERT(isSubresourceValid(subresource));
  272. ANKI_ASSERT(m_texType != TextureType::_3D && "TODO");
  273. // Find the aspect to clear
  274. const DepthStencilAspectBit aspect = subresource.m_depthStencilAspect;
  275. GLenum format;
  276. if(aspect == DepthStencilAspectBit::DEPTH)
  277. {
  278. ANKI_ASSERT(m_glFormat == GL_DEPTH_COMPONENT || m_glFormat == GL_DEPTH_STENCIL);
  279. format = GL_DEPTH_COMPONENT;
  280. }
  281. else if(aspect == DepthStencilAspectBit::STENCIL)
  282. {
  283. ANKI_ASSERT(m_glFormat == GL_STENCIL_INDEX || m_glFormat == GL_DEPTH_STENCIL);
  284. format = GL_STENCIL_INDEX;
  285. }
  286. else if(aspect == DepthStencilAspectBit::DEPTH_STENCIL)
  287. {
  288. ANKI_ASSERT(m_glFormat == GL_DEPTH_STENCIL);
  289. format = GL_DEPTH_STENCIL;
  290. }
  291. else
  292. {
  293. format = m_glFormat;
  294. }
  295. for(U mip = subresource.m_firstMipmap; mip < subresource.m_firstMipmap + subresource.m_mipmapCount; ++mip)
  296. {
  297. for(U face = subresource.m_firstFace; face < subresource.m_firstFace + subresource.m_faceCount; ++face)
  298. {
  299. for(U layer = subresource.m_firstLayer; layer < subresource.m_firstLayer + subresource.m_layerCount;
  300. ++layer)
  301. {
  302. const U surfaceIdx = computeSurfaceIdx(TextureSurfaceInfo(mip, 0, face, layer));
  303. const U width = m_width >> mip;
  304. const U height = m_height >> mip;
  305. glClearTexSubImage(m_glName, mip, 0, 0, surfaceIdx, width, height, 1, format, GL_FLOAT,
  306. &clearValue.m_colorf[0]);
  307. }
  308. }
  309. }
  310. }
  311. U TextureImpl::computeSurfaceIdx(const TextureSurfaceInfo& surf) const
  312. {
  313. U out;
  314. if(m_target == GL_TEXTURE_3D)
  315. {
  316. // Check depth for this level
  317. ANKI_ASSERT(surf.m_depth < (m_depth >> surf.m_level));
  318. out = surf.m_depth;
  319. }
  320. else
  321. {
  322. out = m_faceCount * surf.m_layer + surf.m_face;
  323. }
  324. ANKI_ASSERT(out < m_surfaceCountPerLevel);
  325. return out;
  326. }
  327. MicroTextureView TextureImpl::getOrCreateView(const TextureSubresourceInfo& subresource) const
  328. {
  329. // Quick opt: Check if the subresource refers to the whole tex
  330. TextureSubresourceInfo wholeTexSubresource;
  331. wholeTexSubresource.m_mipmapCount = getMipmapCount();
  332. wholeTexSubresource.m_faceCount = textureTypeIsCube(getTextureType()) ? 6 : 1;
  333. wholeTexSubresource.m_layerCount = getLayerCount();
  334. wholeTexSubresource.m_depthStencilAspect = getDepthStencilAspect();
  335. if(subresource == wholeTexSubresource)
  336. {
  337. MicroTextureView view{getGlName(), wholeTexSubresource.m_depthStencilAspect};
  338. return view;
  339. }
  340. // Continue with the regular init
  341. LockGuard<Mutex> lock(m_viewsMapMtx);
  342. auto it = m_viewsMap.find(subresource);
  343. if(it != m_viewsMap.getEnd())
  344. {
  345. return *it;
  346. }
  347. else
  348. {
  349. // Create a new view
  350. // Compute the new target if needed
  351. const TextureType newTexType = computeNewTexTypeOfSubresource(subresource);
  352. GLenum glTarget = m_target;
  353. if(newTexType == TextureType::_2D)
  354. {
  355. // Change that anyway
  356. glTarget = GL_TEXTURE_2D;
  357. }
  358. const U firstSurf = computeSurfaceIdx(
  359. TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace, subresource.m_firstLayer));
  360. const U lastSurf = computeSurfaceIdx(
  361. TextureSurfaceInfo(subresource.m_firstMipmap, 0, subresource.m_firstFace + subresource.m_faceCount - 1,
  362. subresource.m_firstLayer + subresource.m_layerCount - 1));
  363. ANKI_ASSERT(firstSurf <= lastSurf);
  364. MicroTextureView view;
  365. view.m_aspect = subresource.m_depthStencilAspect;
  366. glGenTextures(1, &view.m_glName);
  367. glTextureView(view.m_glName, glTarget, m_glName, m_internalFormat, subresource.m_firstMipmap,
  368. subresource.m_mipmapCount, firstSurf, lastSurf - firstSurf + 1);
  369. m_viewsMap.emplace(getAllocator(), subresource, view);
  370. return view;
  371. }
  372. }
  373. } // end namespace anki