• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <executorch/backends/vulkan/runtime/vk_api/memory/Image.h>
10 
11 namespace vkcompute {
12 namespace vkapi {
13 
14 //
15 // ImageSampler
16 //
17 
operator ==(const ImageSampler::Properties & _1,const ImageSampler::Properties & _2)18 bool operator==(
19     const ImageSampler::Properties& _1,
20     const ImageSampler::Properties& _2) {
21   return (
22       _1.filter == _2.filter && _1.mipmap_mode == _2.mipmap_mode &&
23       _1.address_mode == _2.address_mode && _1.border_color == _2.border_color);
24 }
25 
ImageSampler(VkDevice device,const ImageSampler::Properties & props)26 ImageSampler::ImageSampler(
27     VkDevice device,
28     const ImageSampler::Properties& props)
29     : device_(device), handle_(VK_NULL_HANDLE) {
30   const VkSamplerCreateInfo sampler_create_info{
31       VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // sType
32       nullptr, // pNext
33       0u, // flags
34       props.filter, // magFilter
35       props.filter, // minFilter
36       props.mipmap_mode, // mipmapMode
37       props.address_mode, // addressModeU
38       props.address_mode, // addressModeV
39       props.address_mode, // addressModeW
40       0.0f, // mipLodBias
41       VK_FALSE, // anisotropyEnable
42       1.0f, // maxAnisotropy,
43       VK_FALSE, // compareEnable
44       VK_COMPARE_OP_NEVER, // compareOp
45       0.0f, // minLod
46       VK_LOD_CLAMP_NONE, // maxLod
47       props.border_color, // borderColor
48       VK_FALSE, // unnormalizedCoordinates
49   };
50 
51   VK_CHECK(vkCreateSampler(device_, &sampler_create_info, nullptr, &handle_));
52 }
53 
ImageSampler(ImageSampler && other)54 ImageSampler::ImageSampler(ImageSampler&& other) noexcept
55     : device_(other.device_), handle_(other.handle_) {
56   other.handle_ = VK_NULL_HANDLE;
57 }
58 
~ImageSampler()59 ImageSampler::~ImageSampler() {
60   if (handle_ == VK_NULL_HANDLE) {
61     return;
62   }
63   vkDestroySampler(device_, handle_, nullptr);
64 }
65 
operator ()(const ImageSampler::Properties & props) const66 size_t ImageSampler::Hasher::operator()(
67     const ImageSampler::Properties& props) const {
68   size_t seed = 0;
69   seed = utils::hash_combine(seed, std::hash<VkFilter>()(props.filter));
70   seed = utils::hash_combine(
71       seed, std::hash<VkSamplerMipmapMode>()(props.mipmap_mode));
72   seed = utils::hash_combine(
73       seed, std::hash<VkSamplerAddressMode>()(props.address_mode));
74   seed =
75       utils::hash_combine(seed, std::hash<VkBorderColor>()(props.border_color));
76   return seed;
77 }
78 
swap(ImageSampler & lhs,ImageSampler & rhs)79 void swap(ImageSampler& lhs, ImageSampler& rhs) noexcept {
80   VkDevice tmp_device = lhs.device_;
81   VkSampler tmp_handle = lhs.handle_;
82 
83   lhs.device_ = rhs.device_;
84   lhs.handle_ = rhs.handle_;
85 
86   rhs.device_ = tmp_device;
87   rhs.handle_ = tmp_handle;
88 }
89 
90 //
91 // VulkanImage
92 //
93 
VulkanImage()94 VulkanImage::VulkanImage()
95     : device_{VK_NULL_HANDLE},
96       image_properties_{},
97       view_properties_{},
98       sampler_properties_{},
99       allocator_(VK_NULL_HANDLE),
100       memory_{},
101       owns_memory_(false),
102       owns_view_(false),
103       is_copy_(false),
104       handles_{
105           VK_NULL_HANDLE,
106           VK_NULL_HANDLE,
107           VK_NULL_HANDLE,
108       },
109       layout_{} {}
110 
VulkanImage(VkDevice device,VmaAllocator vma_allocator,const VmaAllocationCreateInfo & allocation_create_info,const ImageProperties & image_props,const ViewProperties & view_props,const SamplerProperties & sampler_props,VkSampler sampler,const VkImageLayout layout,const bool allocate_memory)111 VulkanImage::VulkanImage(
112     VkDevice device,
113     VmaAllocator vma_allocator,
114     const VmaAllocationCreateInfo& allocation_create_info,
115     const ImageProperties& image_props,
116     const ViewProperties& view_props,
117     const SamplerProperties& sampler_props,
118     VkSampler sampler,
119     const VkImageLayout layout,
120     const bool allocate_memory)
121     : device_{device},
122       image_properties_(image_props),
123       view_properties_(view_props),
124       sampler_properties_(sampler_props),
125       allocator_(vma_allocator),
126       memory_{},
127       owns_memory_{allocate_memory},
128       owns_view_(false),
129       is_copy_(false),
130       handles_{
131           VK_NULL_HANDLE,
132           VK_NULL_HANDLE,
133           sampler,
134       },
135       layout_(layout) {
136   VmaAllocatorInfo allocator_info{};
137   vmaGetAllocatorInfo(allocator_, &allocator_info);
138 
139   // If any dims are zero, then allocate a 1x1x1 image texture. This is to
140   // ensure that there will be some resource that can be bound to a shader.
141   if (image_props.image_extents.width == 0 ||
142       image_props.image_extents.height == 0 ||
143       image_props.image_extents.depth == 0) {
144     image_properties_.image_extents.width = 1u;
145     image_properties_.image_extents.height = 1u;
146     image_properties_.image_extents.depth = 1u;
147   }
148 
149   const VkImageCreateInfo image_create_info{
150       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
151       nullptr, // pNext
152       0u, // flags
153       image_properties_.image_type, // imageType
154       image_properties_.image_format, // format
155       image_properties_.image_extents, // extents
156       1u, // mipLevels
157       1u, // arrayLayers
158       VK_SAMPLE_COUNT_1_BIT, // samples
159       image_properties_.image_tiling, // tiling
160       image_properties_.image_usage, // usage
161       VK_SHARING_MODE_EXCLUSIVE, // sharingMode
162       0u, // queueFamilyIndexCount
163       nullptr, // pQueueFamilyIndices
164       layout_, // initialLayout
165   };
166 
167   if (allocate_memory) {
168     VK_CHECK(vmaCreateImage(
169         allocator_,
170         &image_create_info,
171         &allocation_create_info,
172         &(handles_.image),
173         &(memory_.allocation),
174         nullptr));
175     // Only create the image view if the image has been bound to memory
176     owns_view_ = true;
177     create_image_view();
178   } else {
179     VK_CHECK(vkCreateImage(
180         allocator_info.device, &image_create_info, nullptr, &(handles_.image)));
181   }
182 }
183 
VulkanImage(VkDevice device,const ImageProperties & image_props,VkImage image,VkImageView image_view,VkSampler sampler,const VkImageLayout layout)184 VulkanImage::VulkanImage(
185     VkDevice device,
186     const ImageProperties& image_props,
187     VkImage image,
188     VkImageView image_view,
189     VkSampler sampler,
190     const VkImageLayout layout)
191     : device_{device},
192       image_properties_{image_props},
193       view_properties_{},
194       sampler_properties_{},
195       allocator_(VK_NULL_HANDLE),
196       memory_{},
197       owns_memory_(false),
198       is_copy_(false),
199       handles_{
200           image,
201           image_view,
202           sampler,
203       },
204       layout_{layout} {}
205 
VulkanImage(const VulkanImage & other)206 VulkanImage::VulkanImage(const VulkanImage& other) noexcept
207     : device_(other.device_),
208       image_properties_(other.image_properties_),
209       view_properties_(other.view_properties_),
210       sampler_properties_(other.sampler_properties_),
211       allocator_(other.allocator_),
212       memory_(other.memory_),
213       owns_memory_{false},
214       owns_view_{false},
215       is_copy_(true),
216       handles_(other.handles_),
217       layout_(other.layout_) {}
218 
VulkanImage(VulkanImage && other)219 VulkanImage::VulkanImage(VulkanImage&& other) noexcept
220     : device_(other.device_),
221       image_properties_(other.image_properties_),
222       view_properties_(other.view_properties_),
223       sampler_properties_(other.sampler_properties_),
224       allocator_(other.allocator_),
225       memory_(std::move(other.memory_)),
226       owns_memory_(other.owns_memory_),
227       owns_view_(other.owns_view_),
228       is_copy_(other.is_copy_),
229       handles_(other.handles_),
230       layout_(other.layout_) {
231   other.handles_.image = VK_NULL_HANDLE;
232   other.handles_.image_view = VK_NULL_HANDLE;
233   other.handles_.sampler = VK_NULL_HANDLE;
234   other.owns_memory_ = false;
235 }
236 
operator =(VulkanImage && other)237 VulkanImage& VulkanImage::operator=(VulkanImage&& other) noexcept {
238   VkImage tmp_image = handles_.image;
239   VkImageView tmp_image_view = handles_.image_view;
240   bool tmp_owns_memory = owns_memory_;
241 
242   device_ = other.device_;
243   image_properties_ = other.image_properties_;
244   view_properties_ = other.view_properties_;
245   sampler_properties_ = other.sampler_properties_;
246   allocator_ = other.allocator_;
247   memory_ = std::move(other.memory_);
248   owns_memory_ = other.owns_memory_;
249   is_copy_ = other.is_copy_;
250   handles_ = other.handles_;
251   layout_ = other.layout_;
252 
253   other.handles_.image = tmp_image;
254   other.handles_.image_view = tmp_image_view;
255   other.owns_memory_ = tmp_owns_memory;
256 
257   return *this;
258 }
259 
~VulkanImage()260 VulkanImage::~VulkanImage() {
261   if (owns_view_ && handles_.image_view != VK_NULL_HANDLE) {
262     vkDestroyImageView(this->device(), handles_.image_view, nullptr);
263   }
264 
265   // Do not destroy any resources if this class instance is a copy of another
266   // class instance, since this means that this class instance does not have
267   // ownership of the underlying resource.
268   if (is_copy_) {
269     return;
270   }
271 
272   if (handles_.image != VK_NULL_HANDLE) {
273     if (owns_memory_) {
274       vmaDestroyImage(allocator_, handles_.image, memory_.allocation);
275     } else {
276       vkDestroyImage(this->device(), handles_.image, nullptr);
277     }
278     // Prevent the underlying memory allocation from being freed; it was either
279     // freed by vmaDestroyImage, or this resource does not own the underlying
280     // memory
281     memory_.allocation = VK_NULL_HANDLE;
282   }
283 }
284 
create_image_view()285 void VulkanImage::create_image_view() {
286   VmaAllocatorInfo allocator_info{};
287   vmaGetAllocatorInfo(allocator_, &allocator_info);
288 
289   const VkComponentMapping component_mapping{
290       VK_COMPONENT_SWIZZLE_IDENTITY, // r
291       VK_COMPONENT_SWIZZLE_IDENTITY, // g
292       VK_COMPONENT_SWIZZLE_IDENTITY, // b
293       VK_COMPONENT_SWIZZLE_IDENTITY, // a
294   };
295 
296   const VkImageSubresourceRange subresource_range{
297       VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
298       0u, // baseMipLevel
299       VK_REMAINING_MIP_LEVELS, // levelCount
300       0u, // baseArrayLayer
301       VK_REMAINING_ARRAY_LAYERS, // layerCount
302   };
303 
304   const VkImageViewCreateInfo image_view_create_info{
305       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
306       nullptr, // pNext
307       0u, // flags
308       handles_.image, // image
309       view_properties_.view_type, // viewType
310       view_properties_.view_format, // format
311       component_mapping, // components
312       subresource_range, // subresourceRange
313   };
314 
315   VK_CHECK(vkCreateImageView(
316       allocator_info.device,
317       &(image_view_create_info),
318       nullptr,
319       &(handles_.image_view)));
320 }
321 
get_memory_requirements() const322 VkMemoryRequirements VulkanImage::get_memory_requirements() const {
323   VkMemoryRequirements memory_requirements;
324   vkGetImageMemoryRequirements(
325       this->device(), handles_.image, &memory_requirements);
326   return memory_requirements;
327 }
328 
329 //
330 // ImageMemoryBarrier
331 //
332 
ImageMemoryBarrier(const VkAccessFlags src_access_flags,const VkAccessFlags dst_access_flags,const VkImageLayout src_layout_flags,const VkImageLayout dst_layout_flags,const VulkanImage & image)333 ImageMemoryBarrier::ImageMemoryBarrier(
334     const VkAccessFlags src_access_flags,
335     const VkAccessFlags dst_access_flags,
336     const VkImageLayout src_layout_flags,
337     const VkImageLayout dst_layout_flags,
338     const VulkanImage& image)
339     : handle{
340           VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
341           nullptr, // pNext
342           src_access_flags, // srcAccessMask
343           dst_access_flags, // dstAccessMask
344           src_layout_flags, // oldLayout
345           dst_layout_flags, // newLayout
346           VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
347           VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex
348           image.handles_.image, // image
349           {
350               // subresourceRange
351               VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
352               0u, // baseMipLevel
353               VK_REMAINING_MIP_LEVELS, // levelCount
354               0u, // baseArrayLayer
355               VK_REMAINING_ARRAY_LAYERS, // layerCount
356           },
357       } {}
358 
359 //
360 // SamplerCache
361 //
362 
SamplerCache(VkDevice device)363 SamplerCache::SamplerCache(VkDevice device)
364     : cache_mutex_{}, device_(device), cache_{} {}
365 
SamplerCache(SamplerCache && other)366 SamplerCache::SamplerCache(SamplerCache&& other) noexcept
367     : cache_mutex_{}, device_(other.device_), cache_(std::move(other.cache_)) {
368   std::lock_guard<std::mutex> lock(other.cache_mutex_);
369 }
370 
~SamplerCache()371 SamplerCache::~SamplerCache() {
372   purge();
373 }
374 
retrieve(const SamplerCache::Key & key)375 VkSampler SamplerCache::retrieve(const SamplerCache::Key& key) {
376   std::lock_guard<std::mutex> lock(cache_mutex_);
377 
378   auto it = cache_.find(key);
379   if (cache_.cend() == it) {
380     it = cache_.insert({key, SamplerCache::Value(device_, key)}).first;
381   }
382 
383   return it->second.handle();
384 }
385 
purge()386 void SamplerCache::purge() {
387   std::lock_guard<std::mutex> lock(cache_mutex_);
388   cache_.clear();
389 }
390 
391 } // namespace vkapi
392 } // namespace vkcompute
393