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 "src/vulkan/device.h"
18 #include "src/vulkan/resource.h"
19
20 namespace amber {
21 namespace vulkan {
22
ImageDescriptor(Buffer * buffer,DescriptorType type,Device * device,uint32_t base_mip_level,uint32_t desc_set,uint32_t binding)23 ImageDescriptor::ImageDescriptor(Buffer* buffer,
24 DescriptorType type,
25 Device* device,
26 uint32_t base_mip_level,
27 uint32_t desc_set,
28 uint32_t binding)
29 : BufferBackedDescriptor(buffer, type, device, desc_set, binding),
30 base_mip_level_(base_mip_level),
31 vulkan_sampler_(device) {}
32
33 ImageDescriptor::~ImageDescriptor() = default;
34
RecordCopyDataToResourceIfNeeded(CommandBuffer * command)35 Result ImageDescriptor::RecordCopyDataToResourceIfNeeded(
36 CommandBuffer* command) {
37 for (auto& image : transfer_images_) {
38 image->ImageBarrier(command, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
39 VK_PIPELINE_STAGE_TRANSFER_BIT);
40 }
41
42 Result r = BufferBackedDescriptor::RecordCopyDataToResourceIfNeeded(command);
43 if (!r.IsSuccess())
44 return r;
45
46 // Just do this as early as possible.
47 for (auto& image : transfer_images_) {
48 image->ImageBarrier(command, VK_IMAGE_LAYOUT_GENERAL,
49 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
50 }
51
52 return {};
53 }
54
CreateResourceIfNeeded()55 Result ImageDescriptor::CreateResourceIfNeeded() {
56 if (!transfer_images_.empty()) {
57 return Result(
58 "Vulkan: ImageDescriptor::CreateResourceIfNeeded() must be called "
59 "only when |transfer_images| is empty");
60 }
61
62 transfer_images_.reserve(GetAmberBuffers().size());
63
64 for (const auto& amber_buffer : GetAmberBuffers()) {
65 if (amber_buffer->ValuePtr()->empty())
66 continue;
67
68 // Default to 2D image.
69 VkImageType image_type = VK_IMAGE_TYPE_2D;
70 switch (amber_buffer->GetImageDimension()) {
71 case ImageDimension::k1D:
72 image_type = VK_IMAGE_TYPE_1D;
73 break;
74 case ImageDimension::k2D:
75 image_type = VK_IMAGE_TYPE_2D;
76 break;
77 case ImageDimension::k3D:
78 image_type = VK_IMAGE_TYPE_3D;
79 break;
80 default:
81 break;
82 }
83
84 Format* fmt = amber_buffer->GetFormat();
85 VkImageAspectFlags aspect = 0;
86 if (fmt->HasDepthComponent() && fmt->HasStencilComponent()) {
87 aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
88 } else if (fmt->HasDepthComponent()) {
89 aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
90 } else if (fmt->HasStencilComponent()) {
91 aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
92 } else {
93 aspect = VK_IMAGE_ASPECT_COLOR_BIT;
94 }
95
96 transfer_images_.emplace_back(MakeUnique<TransferImage>(
97 device_, *fmt, aspect, image_type, amber_buffer->GetWidth(),
98 amber_buffer->GetHeight(), amber_buffer->GetDepth(),
99 amber_buffer->GetMipLevels(), base_mip_level_, VK_REMAINING_MIP_LEVELS,
100 amber_buffer->GetSamples()));
101 VkImageUsageFlags usage =
102 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
103
104 if (type_ == DescriptorType::kStorageImage) {
105 usage |= VK_IMAGE_USAGE_STORAGE_BIT;
106 } else {
107 assert(type_ == DescriptorType::kSampledImage ||
108 type_ == DescriptorType::kCombinedImageSampler);
109 usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
110 }
111
112 Result r = transfer_images_.back()->Initialize(usage);
113
114 if (!r.IsSuccess())
115 return r;
116 }
117
118 if (amber_sampler_) {
119 Result r = vulkan_sampler_.CreateSampler(amber_sampler_);
120 if (!r.IsSuccess())
121 return r;
122 }
123
124 is_descriptor_set_update_needed_ = true;
125 return {};
126 }
127
RecordCopyDataToHost(CommandBuffer * command)128 Result ImageDescriptor::RecordCopyDataToHost(CommandBuffer* command) {
129 if (!IsReadOnly()) {
130 for (auto& image : transfer_images_) {
131 image->ImageBarrier(command, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
132 VK_PIPELINE_STAGE_TRANSFER_BIT);
133 }
134
135 BufferBackedDescriptor::RecordCopyDataToHost(command);
136 }
137
138 return {};
139 }
140
MoveResourceToBufferOutput()141 Result ImageDescriptor::MoveResourceToBufferOutput() {
142 Result r = BufferBackedDescriptor::MoveResourceToBufferOutput();
143
144 transfer_images_.clear();
145
146 return r;
147 }
148
UpdateDescriptorSetIfNeeded(VkDescriptorSet descriptor_set)149 void ImageDescriptor::UpdateDescriptorSetIfNeeded(
150 VkDescriptorSet descriptor_set) {
151 if (!is_descriptor_set_update_needed_)
152 return;
153
154 // Always use general layout.
155 VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL;
156
157 std::vector<VkDescriptorImageInfo> image_infos;
158
159 for (const auto& image : transfer_images_) {
160 VkDescriptorImageInfo image_info = {vulkan_sampler_.GetVkSampler(),
161 image->GetVkImageView(), layout};
162 image_infos.push_back(image_info);
163 }
164
165 VkWriteDescriptorSet write = VkWriteDescriptorSet();
166 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
167 write.dstSet = descriptor_set;
168 write.dstBinding = binding_;
169 write.dstArrayElement = 0;
170 write.descriptorCount = static_cast<uint32_t>(image_infos.size());
171 write.descriptorType = GetVkDescriptorType();
172 write.pImageInfo = image_infos.data();
173
174 device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write,
175 0, nullptr);
176
177 is_descriptor_set_update_needed_ = false;
178 }
179
GetResources()180 std::vector<Resource*> ImageDescriptor::GetResources() {
181 std::vector<Resource*> ret;
182 for (auto& i : transfer_images_) {
183 ret.push_back(i.get());
184 }
185 return ret;
186 }
187
188 } // namespace vulkan
189 } // namespace amber
190