1 // Copyright 2019 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/image_descriptor.h"
16 
17 #include <algorithm>
18 #include <unordered_map>
19 #include <utility>
20 
21 #include "src/vulkan/device.h"
22 #include "src/vulkan/resource.h"
23 
24 namespace amber {
25 namespace vulkan {
26 
ImageDescriptor(Buffer * buffer,DescriptorType type,Device * device,uint32_t base_mip_level,uint32_t desc_set,uint32_t binding,Pipeline * pipeline)27 ImageDescriptor::ImageDescriptor(Buffer* buffer,
28                                  DescriptorType type,
29                                  Device* device,
30                                  uint32_t base_mip_level,
31                                  uint32_t desc_set,
32                                  uint32_t binding,
33                                  Pipeline* pipeline)
34     : BufferBackedDescriptor(buffer, type, device, desc_set, binding, pipeline),
35       base_mip_level_(base_mip_level),
36       vulkan_sampler_(device) {}
37 
38 ImageDescriptor::~ImageDescriptor() = default;
39 
CreateResourceIfNeeded()40 Result ImageDescriptor::CreateResourceIfNeeded() {
41   auto& transfer_resources = pipeline_->GetDescriptorTransferResources();
42 
43   for (const auto& amber_buffer : GetAmberBuffers()) {
44     if (amber_buffer->ValuePtr()->empty())
45       continue;
46 
47     // Check if the transfer image is already created.
48     if (transfer_resources.count(amber_buffer) > 0) {
49       continue;
50     }
51 
52     // Default to 2D image.
53     VkImageType image_type = VK_IMAGE_TYPE_2D;
54     switch (amber_buffer->GetImageDimension()) {
55       case ImageDimension::k1D:
56         image_type = VK_IMAGE_TYPE_1D;
57         break;
58       case ImageDimension::k2D:
59         image_type = VK_IMAGE_TYPE_2D;
60         break;
61       case ImageDimension::k3D:
62         image_type = VK_IMAGE_TYPE_3D;
63         break;
64       default:
65         break;
66     }
67 
68     Format* fmt = amber_buffer->GetFormat();
69     VkImageAspectFlags aspect = 0;
70     if (fmt->HasDepthComponent() && fmt->HasStencilComponent()) {
71       aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
72     } else if (fmt->HasDepthComponent()) {
73       aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
74     } else if (fmt->HasStencilComponent()) {
75       aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
76     } else {
77       aspect = VK_IMAGE_ASPECT_COLOR_BIT;
78     }
79 
80     VkImageUsageFlags usage =
81         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
82     if (type_ == DescriptorType::kStorageImage) {
83       usage |= VK_IMAGE_USAGE_STORAGE_BIT;
84     } else {
85       assert(type_ == DescriptorType::kSampledImage ||
86              type_ == DescriptorType::kCombinedImageSampler);
87       usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
88     }
89 
90     auto transfer_image = MakeUnique<TransferImage>(
91         device_, *fmt, aspect, image_type, usage, amber_buffer->GetWidth(),
92         amber_buffer->GetHeight(), amber_buffer->GetDepth(),
93         amber_buffer->GetMipLevels(), base_mip_level_, VK_REMAINING_MIP_LEVELS,
94         amber_buffer->GetSamples());
95 
96     // Store the transfer image to the pipeline's map of transfer images.
97     transfer_resources[amber_buffer] = std::move(transfer_image);
98   }
99 
100   if (amber_sampler_) {
101     Result r = vulkan_sampler_.CreateSampler(amber_sampler_);
102     if (!r.IsSuccess())
103       return r;
104   }
105 
106   is_descriptor_set_update_needed_ = true;
107   return {};
108 }
109 
UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set)110 void ImageDescriptor::UpdateDescriptorSetIfNeeded(
111     VkDescriptorSet descriptor_set) {
112   if (!is_descriptor_set_update_needed_)
113     return;
114 
115   // Always use general layout.
116   VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL;
117 
118   std::vector<VkDescriptorImageInfo> image_infos;
119 
120   // Create VkDescriptorImageInfo for every descriptor image.
121   for (const auto& amber_buffer : GetAmberBuffers()) {
122     const auto& image =
123         pipeline_->GetDescriptorTransferResources()[amber_buffer]
124             ->AsTransferImage();
125     VkDescriptorImageInfo image_info = {vulkan_sampler_.GetVkSampler(),
126                                         image->GetVkImageView(), layout};
127     image_infos.push_back(image_info);
128   }
129 
130   VkWriteDescriptorSet write = VkWriteDescriptorSet();
131   write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
132   write.dstSet = descriptor_set;
133   write.dstBinding = binding_;
134   write.dstArrayElement = 0;
135   write.descriptorCount = static_cast<uint32_t>(image_infos.size());
136   write.descriptorType = GetVkDescriptorType();
137   write.pImageInfo = image_infos.data();
138 
139   device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write,
140                                              0, nullptr);
141 
142   is_descriptor_set_update_needed_ = false;
143 }
144 
145 }  // namespace vulkan
146 }  // namespace amber
147