• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/vulkan/transfer_image.h"
16 
17 #include <cstring>
18 #include <limits>
19 #include <vector>
20 
21 #include "src/vulkan/command_buffer.h"
22 #include "src/vulkan/device.h"
23 
24 namespace amber {
25 namespace vulkan {
26 namespace {
27 
28 const VkImageCreateInfo kDefaultImageInfo = {
29     VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, /* sType */
30     nullptr,                             /* pNext */
31     0,                                   /* flags */
32     VK_IMAGE_TYPE_2D,                    /* imageType */
33     VK_FORMAT_R8G8B8A8_UNORM,            /* format */
34     {250, 250, 1},                       /* extent */
35     1,                                   /* mipLevels */
36     1,                                   /* arrayLayers */
37     VK_SAMPLE_COUNT_1_BIT,               /* samples */
38     VK_IMAGE_TILING_OPTIMAL,             /* tiling */
39     0,                                   /* usage */
40     VK_SHARING_MODE_EXCLUSIVE,           /* sharingMode */
41     0,                                   /* queueFamilyIndexCount */
42     nullptr,                             /* pQueueFamilyIndices */
43     VK_IMAGE_LAYOUT_UNDEFINED,           /* initialLayout */
44 };
45 
GetVkSampleCount(uint32_t samples)46 VkSampleCountFlagBits GetVkSampleCount(uint32_t samples) {
47   switch (samples) {
48     case 1u:
49       return VK_SAMPLE_COUNT_1_BIT;
50     case 2u:
51       return VK_SAMPLE_COUNT_2_BIT;
52     case 4u:
53       return VK_SAMPLE_COUNT_4_BIT;
54     case 8u:
55       return VK_SAMPLE_COUNT_8_BIT;
56     case 16u:
57       return VK_SAMPLE_COUNT_16_BIT;
58     case 32u:
59       return VK_SAMPLE_COUNT_32_BIT;
60     case 64u:
61       return VK_SAMPLE_COUNT_64_BIT;
62   }
63 
64   return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
65 }
66 
67 }  // namespace
68 
TransferImage(Device * device,const Format & format,VkImageAspectFlags aspect,VkImageType image_type,uint32_t x,uint32_t y,uint32_t z,uint32_t mip_levels,uint32_t base_mip_level,uint32_t used_mip_levels,uint32_t samples)69 TransferImage::TransferImage(Device* device,
70                              const Format& format,
71                              VkImageAspectFlags aspect,
72                              VkImageType image_type,
73                              uint32_t x,
74                              uint32_t y,
75                              uint32_t z,
76                              uint32_t mip_levels,
77                              uint32_t base_mip_level,
78                              uint32_t used_mip_levels,
79                              uint32_t samples)
80     : Resource(
81           device,
82           x * y * z *
83               (format.SizeInBytes() +
84                // D24_UNORM_S8_UINT requires 32bit component for depth when
85                // performing buffer copies. Reserve extra room to handle that.
86                (format.GetFormatType() == FormatType::kD24_UNORM_S8_UINT ? 1
87                                                                          : 0))),
88       image_info_(kDefaultImageInfo),
89       aspect_(aspect),
90       mip_levels_(mip_levels),
91       base_mip_level_(base_mip_level),
92       used_mip_levels_(used_mip_levels),
93       samples_(samples) {
94   image_info_.format = device_->GetVkFormat(format);
95   image_info_.imageType = image_type;
96   image_info_.extent = {x, y, z};
97   image_info_.mipLevels = mip_levels;
98   image_info_.samples = GetVkSampleCount(samples);
99 }
100 
~TransferImage()101 TransferImage::~TransferImage() {
102   if (view_ != VK_NULL_HANDLE) {
103     device_->GetPtrs()->vkDestroyImageView(device_->GetVkDevice(), view_,
104                                            nullptr);
105   }
106 
107   if (image_ != VK_NULL_HANDLE)
108     device_->GetPtrs()->vkDestroyImage(device_->GetVkDevice(), image_, nullptr);
109 
110   if (memory_ != VK_NULL_HANDLE)
111     device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(), memory_, nullptr);
112 
113   if (host_accessible_memory_ != VK_NULL_HANDLE) {
114     UnMapMemory(host_accessible_memory_);
115     device_->GetPtrs()->vkFreeMemory(device_->GetVkDevice(),
116                                      host_accessible_memory_, nullptr);
117   }
118 
119   if (host_accessible_buffer_ != VK_NULL_HANDLE) {
120     device_->GetPtrs()->vkDestroyBuffer(device_->GetVkDevice(),
121                                         host_accessible_buffer_, nullptr);
122   }
123 }
124 
Initialize(VkImageUsageFlags usage)125 Result TransferImage::Initialize(VkImageUsageFlags usage) {
126   if (image_ != VK_NULL_HANDLE)
127     return Result("Vulkan::TransferImage was already initialized");
128 
129   image_info_.usage = usage;
130 
131   if (device_->GetPtrs()->vkCreateImage(device_->GetVkDevice(), &image_info_,
132                                         nullptr, &image_) != VK_SUCCESS) {
133     return Result("Vulkan::Calling vkCreateImage Fail");
134   }
135 
136   uint32_t memory_type_index = 0;
137   Result r = AllocateAndBindMemoryToVkImage(image_, &memory_,
138                                             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
139                                             false, &memory_type_index);
140   if (!r.IsSuccess())
141     return r;
142 
143   if (aspect_ & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) &&
144       !(usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
145     // Combined depth/stencil image used as a descriptor. Only one aspect can be
146     // used for the image view.
147     r = CreateVkImageView(VK_IMAGE_ASPECT_DEPTH_BIT);
148   } else {
149     r = CreateVkImageView(aspect_);
150   }
151 
152   if (!r.IsSuccess())
153     return r;
154 
155   // For images, we always make a secondary buffer. When the tiling of an image
156   // is optimal, read/write data from CPU does not show correct values. We need
157   // a secondary buffer to convert the GPU-optimal data to CPU-readable data
158   // and vice versa.
159   r = CreateVkBuffer(
160       &host_accessible_buffer_,
161       VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
162   if (!r.IsSuccess())
163     return r;
164 
165   memory_type_index = 0;
166   r = AllocateAndBindMemoryToVkBuffer(host_accessible_buffer_,
167                                       &host_accessible_memory_,
168                                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
169                                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
170                                       true, &memory_type_index);
171   if (!r.IsSuccess())
172     return r;
173 
174   return MapMemory(host_accessible_memory_);
175 }
176 
GetImageViewType() const177 VkImageViewType TransferImage::GetImageViewType() const {
178   // TODO(alan-baker): handle other view types.
179   // 1D-array, 2D-array, Cube, Cube-array.
180   switch (image_info_.imageType) {
181     case VK_IMAGE_TYPE_1D:
182       return VK_IMAGE_VIEW_TYPE_1D;
183     case VK_IMAGE_TYPE_2D:
184       return VK_IMAGE_VIEW_TYPE_2D;
185     case VK_IMAGE_TYPE_3D:
186       return VK_IMAGE_VIEW_TYPE_3D;
187     default:
188       break;
189   }
190 
191   // Default to 2D image view.
192   return VK_IMAGE_VIEW_TYPE_2D;
193 }
194 
CreateVkImageView(VkImageAspectFlags aspect)195 Result TransferImage::CreateVkImageView(VkImageAspectFlags aspect) {
196   VkImageViewCreateInfo image_view_info = VkImageViewCreateInfo();
197   image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
198   image_view_info.image = image_;
199   image_view_info.viewType = GetImageViewType();
200   image_view_info.format = image_info_.format;
201   image_view_info.components = {
202       VK_COMPONENT_SWIZZLE_R,
203       VK_COMPONENT_SWIZZLE_G,
204       VK_COMPONENT_SWIZZLE_B,
205       VK_COMPONENT_SWIZZLE_A,
206   };
207   image_view_info.subresourceRange = {
208       aspect,           /* aspectMask */
209       base_mip_level_,  /* baseMipLevel */
210       used_mip_levels_, /* levelCount */
211       0,                /* baseArrayLayer */
212       1,                /* layerCount */
213   };
214 
215   if (device_->GetPtrs()->vkCreateImageView(device_->GetVkDevice(),
216                                             &image_view_info, nullptr,
217                                             &view_) != VK_SUCCESS) {
218     return Result("Vulkan::Calling vkCreateImageView Fail");
219   }
220 
221   return {};
222 }
223 
CreateBufferImageCopy(VkImageAspectFlags aspect,uint32_t mip_level)224 VkBufferImageCopy TransferImage::CreateBufferImageCopy(
225     VkImageAspectFlags aspect,
226     uint32_t mip_level) {
227   VkBufferImageCopy copy_region = VkBufferImageCopy();
228   if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
229     // Store stencil data at the end of the buffer after depth data.
230     copy_region.bufferOffset =
231         GetSizeInBytes() - image_info_.extent.width * image_info_.extent.height;
232   } else {
233     copy_region.bufferOffset = 0;
234   }
235   // Row length of 0 results in tight packing of rows, so the row stride
236   // is the number of texels times the texel stride.
237   copy_region.bufferRowLength = 0;
238   copy_region.bufferImageHeight = 0;
239   copy_region.imageSubresource = {
240       aspect,    /* aspectMask */
241       mip_level, /* mipLevel */
242       0,         /* baseArrayLayer */
243       1,         /* layerCount */
244   };
245   copy_region.imageOffset = {0, 0, 0};
246   copy_region.imageExtent = {image_info_.extent.width >> mip_level,
247                              image_info_.extent.height >> mip_level,
248                              image_info_.extent.depth};
249   return copy_region;
250 }
251 
CopyToHost(CommandBuffer * command_buffer)252 void TransferImage::CopyToHost(CommandBuffer* command_buffer) {
253   const VkImageAspectFlagBits aspects[] = {VK_IMAGE_ASPECT_COLOR_BIT,
254                                            VK_IMAGE_ASPECT_DEPTH_BIT,
255                                            VK_IMAGE_ASPECT_STENCIL_BIT};
256   // Copy operations don't support multisample images.
257   if (samples_ > 1)
258     return;
259 
260   std::vector<VkBufferImageCopy> copy_regions;
261   uint32_t last_mip_level = used_mip_levels_ == VK_REMAINING_MIP_LEVELS
262                                 ? mip_levels_
263                                 : base_mip_level_ + used_mip_levels_;
264   for (uint32_t i = base_mip_level_; i < last_mip_level; i++) {
265     for (auto aspect : aspects) {
266       if (aspect_ & aspect) {
267         copy_regions.push_back(CreateBufferImageCopy(aspect, i));
268       }
269     }
270   }
271 
272   device_->GetPtrs()->vkCmdCopyImageToBuffer(
273       command_buffer->GetVkCommandBuffer(), image_,
274       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, host_accessible_buffer_,
275       static_cast<uint32_t>(copy_regions.size()), copy_regions.data());
276 
277   MemoryBarrier(command_buffer);
278 }
279 
CopyToDevice(CommandBuffer * command_buffer)280 void TransferImage::CopyToDevice(CommandBuffer* command_buffer) {
281   // Copy operations don't support multisample images.
282   if (samples_ > 1)
283     return;
284 
285   const VkImageAspectFlagBits aspects[] = {VK_IMAGE_ASPECT_COLOR_BIT,
286                                            VK_IMAGE_ASPECT_DEPTH_BIT,
287                                            VK_IMAGE_ASPECT_STENCIL_BIT};
288   std::vector<VkBufferImageCopy> copy_regions;
289   uint32_t last_mip_level = used_mip_levels_ == VK_REMAINING_MIP_LEVELS
290                                 ? mip_levels_
291                                 : base_mip_level_ + used_mip_levels_;
292   for (uint32_t i = base_mip_level_; i < last_mip_level; i++) {
293     for (auto aspect : aspects) {
294       if (aspect_ & aspect) {
295         copy_regions.push_back(CreateBufferImageCopy(aspect, i));
296       }
297     }
298   }
299 
300   device_->GetPtrs()->vkCmdCopyBufferToImage(
301       command_buffer->GetVkCommandBuffer(), host_accessible_buffer_, image_,
302       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
303       static_cast<uint32_t>(copy_regions.size()), copy_regions.data());
304 
305   MemoryBarrier(command_buffer);
306 }
307 
ImageBarrier(CommandBuffer * command_buffer,VkImageLayout to_layout,VkPipelineStageFlags to_stage)308 void TransferImage::ImageBarrier(CommandBuffer* command_buffer,
309                                  VkImageLayout to_layout,
310                                  VkPipelineStageFlags to_stage) {
311   if (to_layout == layout_ && to_stage == stage_)
312     return;
313 
314   VkImageMemoryBarrier barrier = VkImageMemoryBarrier();
315   barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
316   barrier.oldLayout = layout_;
317   barrier.newLayout = to_layout;
318   barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
319   barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
320   barrier.image = image_;
321   barrier.subresourceRange = {
322       aspect_,                 /* aspectMask */
323       0,                       /* baseMipLevel */
324       VK_REMAINING_MIP_LEVELS, /* levelCount */
325       0,                       /* baseArrayLayer */
326       1,                       /* layerCount */
327   };
328 
329   switch (layout_) {
330     case VK_IMAGE_LAYOUT_PREINITIALIZED:
331       barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
332       break;
333     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
334       barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
335       break;
336     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
337       barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
338       break;
339     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
340       barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
341       break;
342     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
343       barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
344       break;
345     default:
346       barrier.srcAccessMask = 0;
347       break;
348   }
349 
350   switch (to_layout) {
351     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
352       barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
353                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
354       break;
355     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
356       barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
357                               VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
358       break;
359     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
360       barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
361       break;
362     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
363       barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
364       break;
365     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
366       barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
367       break;
368     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
369       barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
370       break;
371     default:
372       barrier.dstAccessMask = 0;
373       break;
374   }
375 
376   device_->GetPtrs()->vkCmdPipelineBarrier(command_buffer->GetVkCommandBuffer(),
377                                            stage_, to_stage, 0, 0, NULL, 0,
378                                            NULL, 1, &barrier);
379 
380   layout_ = to_layout;
381   stage_ = to_stage;
382 }
383 
AllocateAndBindMemoryToVkImage(VkImage image,VkDeviceMemory * memory,VkMemoryPropertyFlags flags,bool force_flags,uint32_t * memory_type_index)384 Result TransferImage::AllocateAndBindMemoryToVkImage(
385     VkImage image,
386     VkDeviceMemory* memory,
387     VkMemoryPropertyFlags flags,
388     bool force_flags,
389     uint32_t* memory_type_index) {
390   if (memory_type_index == nullptr) {
391     return Result(
392         "Vulkan: TransferImage::AllocateAndBindMemoryToVkImage "
393         "memory_type_index is "
394         "nullptr");
395   }
396 
397   *memory_type_index = 0;
398 
399   if (image == VK_NULL_HANDLE)
400     return Result("Vulkan::Given VkImage is VK_NULL_HANDLE");
401   if (memory == nullptr)
402     return Result("Vulkan::Given VkDeviceMemory pointer is nullptr");
403 
404   VkMemoryRequirements requirement;
405   device_->GetPtrs()->vkGetImageMemoryRequirements(device_->GetVkDevice(),
406                                                    image, &requirement);
407 
408   *memory_type_index =
409       ChooseMemory(requirement.memoryTypeBits, flags, force_flags);
410   if (*memory_type_index == std::numeric_limits<uint32_t>::max())
411     return Result("Vulkan::Find Proper Memory Fail");
412 
413   Result r = AllocateMemory(memory, requirement.size, *memory_type_index);
414   if (!r.IsSuccess())
415     return r;
416 
417   if (device_->GetPtrs()->vkBindImageMemory(device_->GetVkDevice(), image,
418                                             *memory, 0) != VK_SUCCESS) {
419     return Result("Vulkan::Calling vkBindImageMemory Fail");
420   }
421 
422   return {};
423 }
424 
425 }  // namespace vulkan
426 }  // namespace amber
427