TextureImpl.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. #pragma once
  6. #include <AnKi/Gr/Texture.h>
  7. #include <AnKi/Gr/Vulkan/VulkanObject.h>
  8. #include <AnKi/Gr/Vulkan/GpuMemoryManager.h>
  9. #include <AnKi/Gr/Utils/Functions.h>
  10. #include <AnKi/Gr/Vulkan/SamplerFactory.h>
  11. #include <AnKi/Util/HashMap.h>
  12. namespace anki {
  13. // Forward
  14. class TextureUsageState;
  15. /// @addtogroup vulkan
  16. /// @{
  17. enum class TextureImplWorkaround : U8
  18. {
  19. NONE,
  20. R8G8B8_TO_R8G8B8A8 = 1 << 0,
  21. S8_TO_D24S8 = 1 << 1,
  22. D24S8_TO_D32S8 = 1 << 2,
  23. };
  24. ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureImplWorkaround)
  25. /// A Vulkan image view with some extra data.
  26. class MicroImageView
  27. {
  28. friend class TextureImpl;
  29. public:
  30. MicroImageView() = default;
  31. MicroImageView(MicroImageView&& b)
  32. {
  33. *this = std::move(b);
  34. }
  35. ~MicroImageView()
  36. {
  37. for(U32 idx : m_bindlessIndices)
  38. {
  39. ANKI_ASSERT(idx == MAX_U32 && "Forgot to unbind the bindless");
  40. (void)idx;
  41. }
  42. ANKI_ASSERT(m_handle == VK_NULL_HANDLE);
  43. }
  44. MicroImageView& operator=(MicroImageView&& b)
  45. {
  46. m_handle = b.m_handle;
  47. b.m_handle = VK_NULL_HANDLE;
  48. m_bindlessIndices = b.m_bindlessIndices;
  49. b.m_bindlessIndices = {MAX_U32, MAX_U32};
  50. m_derivedTextureType = b.m_derivedTextureType;
  51. b.m_derivedTextureType = TextureType::COUNT;
  52. return *this;
  53. }
  54. VkImageView getHandle() const
  55. {
  56. ANKI_ASSERT(m_handle);
  57. return m_handle;
  58. }
  59. /// @note It's thread-safe.
  60. U32 getOrCreateBindlessIndex(VkImageLayout layout, GrManagerImpl& gr) const;
  61. TextureType getDerivedTextureType() const
  62. {
  63. ANKI_ASSERT(m_derivedTextureType != TextureType::COUNT);
  64. return m_derivedTextureType;
  65. }
  66. private:
  67. VkImageView m_handle = VK_NULL_HANDLE;
  68. /// Index 0: Sampled image with SHADER_READ_ONLY layout.
  69. /// Index 1: Storage image with ofcource GENERAL layout.
  70. mutable Array<U32, 2> m_bindlessIndices = {MAX_U32, MAX_U32};
  71. /// Protect the m_bindlessIndices.
  72. mutable SpinLock m_lock;
  73. /// Because for example a single surface view of a cube texture will be a 2D view.
  74. TextureType m_derivedTextureType = TextureType::COUNT;
  75. };
  76. /// Texture container.
  77. class TextureImpl final : public Texture, public VulkanObject<Texture, TextureImpl>
  78. {
  79. public:
  80. VkImage m_imageHandle = VK_NULL_HANDLE;
  81. GpuMemoryHandle m_memHandle;
  82. VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
  83. TextureImplWorkaround m_workarounds = TextureImplWorkaround::NONE;
  84. VkImageViewCreateInfo m_viewCreateInfoTemplate;
  85. TextureImpl(GrManager* manager, CString name)
  86. : Texture(manager, name)
  87. {
  88. }
  89. ~TextureImpl();
  90. ANKI_USE_RESULT Error init(const TextureInitInfo& init)
  91. {
  92. return initInternal(VK_NULL_HANDLE, init);
  93. }
  94. ANKI_USE_RESULT Error initExternal(VkImage image, const TextureInitInfo& init)
  95. {
  96. return initInternal(image, init);
  97. }
  98. Bool aspectValid(DepthStencilAspectBit aspect) const
  99. {
  100. return m_aspect == aspect || !!(aspect & m_aspect);
  101. }
  102. /// Compute the layer as defined by Vulkan.
  103. U32 computeVkArrayLayer(const TextureSurfaceInfo& surf) const
  104. {
  105. U32 layer = 0;
  106. switch(m_texType)
  107. {
  108. case TextureType::_2D:
  109. layer = 0;
  110. break;
  111. case TextureType::CUBE:
  112. layer = surf.m_face;
  113. break;
  114. case TextureType::_2D_ARRAY:
  115. layer = surf.m_layer;
  116. break;
  117. case TextureType::CUBE_ARRAY:
  118. layer = surf.m_layer * 6 + surf.m_face;
  119. break;
  120. default:
  121. ANKI_ASSERT(0);
  122. }
  123. return layer;
  124. }
  125. U32 computeVkArrayLayer(const TextureVolumeInfo& vol) const
  126. {
  127. ANKI_ASSERT(m_texType == TextureType::_3D);
  128. return 0;
  129. }
  130. Bool usageValid(TextureUsageBit usage) const
  131. {
  132. #if ANKI_ENABLE_ASSERTIONS
  133. LockGuard<SpinLock> lock(m_usedForMtx);
  134. m_usedFor |= usage;
  135. #endif
  136. return (usage & m_usage) == usage;
  137. }
  138. /// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
  139. void computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, U32 level, VkPipelineStageFlags& srcStages,
  140. VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
  141. VkAccessFlags& dstAccesses) const;
  142. /// Predict the image layout.
  143. VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
  144. void computeVkImageSubresourceRange(const TextureSubresourceInfo& in, VkImageSubresourceRange& range) const
  145. {
  146. ANKI_ASSERT(isSubresourceValid(in));
  147. range.aspectMask = convertImageAspect(in.m_depthStencilAspect);
  148. range.baseMipLevel = in.m_firstMipmap;
  149. range.levelCount = in.m_mipmapCount;
  150. const U32 faceCount = textureTypeIsCube(m_texType) ? 6 : 1;
  151. range.baseArrayLayer = in.m_firstLayer * faceCount + in.m_firstFace;
  152. range.layerCount = in.m_layerCount * in.m_faceCount;
  153. }
  154. void computeVkImageViewCreateInfo(const TextureSubresourceInfo& subresource, VkImageViewCreateInfo& viewCi,
  155. TextureType& newTextureType) const
  156. {
  157. ANKI_ASSERT(isSubresourceValid(subresource));
  158. viewCi = m_viewCreateInfoTemplate;
  159. computeVkImageSubresourceRange(subresource, viewCi.subresourceRange);
  160. // Fixup the image view type
  161. newTextureType = computeNewTexTypeOfSubresource(subresource);
  162. viewCi.viewType = convertTextureViewType(newTextureType);
  163. }
  164. const MicroImageView& getOrCreateView(const TextureSubresourceInfo& subresource) const;
  165. private:
  166. mutable HashMap<TextureSubresourceInfo, MicroImageView> m_viewsMap;
  167. mutable RWMutex m_viewsMapMtx;
  168. /// This is a special optimization for textures that have only one surface. In this case we don't need to go through
  169. /// the hashmap above.
  170. MicroImageView m_singleSurfaceImageView;
  171. VkDeviceMemory m_dedicatedMem = VK_NULL_HANDLE;
  172. #if ANKI_ENABLE_ASSERTIONS
  173. mutable TextureUsageBit m_usedFor = TextureUsageBit::NONE;
  174. mutable SpinLock m_usedForMtx;
  175. #endif
  176. ANKI_USE_RESULT static VkFormatFeatureFlags calcFeatures(const TextureInitInfo& init);
  177. ANKI_USE_RESULT static VkImageCreateFlags calcCreateFlags(const TextureInitInfo& init);
  178. ANKI_USE_RESULT Bool imageSupported(const TextureInitInfo& init);
  179. ANKI_USE_RESULT Error initImage(const TextureInitInfo& init);
  180. template<typename TextureInfo>
  181. void updateUsageState(const TextureInfo& surfOrVol, TextureUsageBit usage, StackAllocator<U8>& alloc,
  182. TextureUsageState& state) const;
  183. void updateUsageState(TextureUsageBit usage, StackAllocator<U8>& alloc, TextureUsageState& state) const;
  184. /// Compute the new type of a texture view.
  185. TextureType computeNewTexTypeOfSubresource(const TextureSubresourceInfo& subresource) const;
  186. ANKI_USE_RESULT Error initInternal(VkImage externalImage, const TextureInitInfo& init);
  187. void computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level, VkPipelineStageFlags& stages,
  188. VkAccessFlags& accesses) const;
  189. void destroyMicroImageView(MicroImageView& view);
  190. };
  191. /// @}
  192. } // end namespace anki