| Flutter Impeller |

binding_helpers_vk.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/renderer/backend/vulkan/binding_helpers_vk.h"
6 #include "fml/status.h"
7 #include "impeller/core/shader_types.h"
8 #include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
9 #include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
10 #include "impeller/renderer/backend/vulkan/command_pool_vk.h"
11 #include "impeller/renderer/backend/vulkan/compute_pipeline_vk.h"
12 #include "impeller/renderer/backend/vulkan/context_vk.h"
13 #include "impeller/renderer/backend/vulkan/sampler_vk.h"
14 #include "impeller/renderer/backend/vulkan/texture_vk.h"
15 #include "impeller/renderer/command.h"
16 #include "impeller/renderer/compute_command.h"
17 #include "vulkan/vulkan_core.h"
18
19 namespace impeller {
20
21 // Warning: if any of the constant values or layouts are changed in the
22 // framebuffer fetch shader, then this input binding may need to be
23 // manually changed.
24 static constexpr size_t kMagicSubpassInputBinding = 64;
25
26 static bool BindImages(const Bindings& bindings,
27 Allocator& allocator,
28 const std::shared_ptr<CommandEncoderVK>& encoder,
29 vk::DescriptorSet& vk_desc_set,
30 std::vector<vk::DescriptorImageInfo>& images,
31 std::vector<vk::WriteDescriptorSet>& writes) {
32 for (const TextureAndSampler& data : bindings.sampled_images) {
33 auto texture = data.texture.resource;
34 const auto& texture_vk = TextureVK::Cast(*texture);
35 const SamplerVK& sampler = SamplerVK::Cast(*data.sampler);
36
37 if (!encoder->Track(texture) ||
38 !encoder->Track(sampler.GetSharedSampler())) {
39 return false;
40 }
41
42 const SampledImageSlot& slot = data.slot;
43
44 vk::DescriptorImageInfo image_info;
45 image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
46 image_info.sampler = sampler.GetSampler();
47 image_info.imageView = texture_vk.GetImageView();
48 images.push_back(image_info);
49
50 vk::WriteDescriptorSet write_set;
51 write_set.dstSet = vk_desc_set;
52 write_set.dstBinding = slot.binding;
53 write_set.descriptorCount = 1u;
54 write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
55 write_set.pImageInfo = &images.back();
56
57 writes.push_back(write_set);
58 }
59
60 return true;
61 };
62
63 static bool BindBuffers(const Bindings& bindings,
64 Allocator& allocator,
65 const std::shared_ptr<CommandEncoderVK>& encoder,
66 vk::DescriptorSet& vk_desc_set,
67 const std::vector<DescriptorSetLayout>& desc_set,
68 std::vector<vk::DescriptorBufferInfo>& buffers,
69 std::vector<vk::WriteDescriptorSet>& writes) {
70 for (const BufferAndUniformSlot& data : bindings.buffers) {
71 const auto& buffer_view = data.view.resource.buffer;
72
73 auto device_buffer = buffer_view->GetDeviceBuffer(allocator);
74 if (!device_buffer) {
75 VALIDATION_LOG << "Failed to get device buffer for vertex binding";
76 return false;
77 }
78
79 auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
80 if (!buffer) {
81 return false;
82 }
83
84 if (!encoder->Track(device_buffer)) {
85 return false;
86 }
87
88 uint32_t offset = data.view.resource.range.offset;
89
90 vk::DescriptorBufferInfo buffer_info;
91 buffer_info.buffer = buffer;
92 buffer_info.offset = offset;
93 buffer_info.range = data.view.resource.range.length;
94 buffers.push_back(buffer_info);
95
96 // TODO(jonahwilliams): remove this part by storing more data in
97 // ShaderUniformSlot.
98 const ShaderUniformSlot& uniform = data.slot;
99 auto layout_it =
100 std::find_if(desc_set.begin(), desc_set.end(),
101 [&uniform](const DescriptorSetLayout& layout) {
102 return layout.binding == uniform.binding;
103 });
104 if (layout_it == desc_set.end()) {
105 VALIDATION_LOG << "Failed to get descriptor set layout for binding "
106 << uniform.binding;
107 return false;
108 }
109 auto layout = *layout_it;
110
111 vk::WriteDescriptorSet write_set;
112 write_set.dstSet = vk_desc_set;
113 write_set.dstBinding = uniform.binding;
114 write_set.descriptorCount = 1u;
115 write_set.descriptorType = ToVKDescriptorType(layout.descriptor_type);
116 write_set.pBufferInfo = &buffers.back();
117
118 writes.push_back(write_set);
119 }
120 return true;
121 }
122
123 fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
124 const ContextVK& context,
125 const std::shared_ptr<CommandEncoderVK>& encoder,
126 const std::vector<Command>& commands,
127 const TextureVK& input_attachment) {
128 if (commands.empty()) {
129 return std::vector<vk::DescriptorSet>{};
130 }
131
132 // Step 1: Determine the total number of buffer and sampler descriptor
133 // sets required. Collect this information along with the layout information
134 // to allocate a correctly sized descriptor pool.
135 size_t buffer_count = 0;
136 size_t samplers_count = 0;
137 size_t subpass_count = 0;
138 std::vector<vk::DescriptorSetLayout> layouts;
139 layouts.reserve(commands.size());
140
141 for (const auto& command : commands) {
142 buffer_count += command.vertex_bindings.buffers.size();
143 buffer_count += command.fragment_bindings.buffers.size();
144 samplers_count += command.fragment_bindings.sampled_images.size();
145 subpass_count +=
146 command.pipeline->GetDescriptor().UsesSubpassInput() ? 1 : 0;
147
148 layouts.emplace_back(
149 PipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout());
150 }
151 auto descriptor_result = encoder->AllocateDescriptorSets(
152 buffer_count, samplers_count, subpass_count, layouts);
153 if (!descriptor_result.ok()) {
154 return descriptor_result.status();
155 }
156 auto descriptor_sets = descriptor_result.value();
157 if (descriptor_sets.empty()) {
158 return fml::Status();
159 }
160
161 // Step 2: Update the descriptors for all image and buffer descriptors used
162 // in the render pass.
163 std::vector<vk::DescriptorImageInfo> images;
164 std::vector<vk::DescriptorBufferInfo> buffers;
165 std::vector<vk::WriteDescriptorSet> writes;
166 images.reserve(samplers_count + subpass_count);
167 buffers.reserve(buffer_count);
168 writes.reserve(samplers_count + buffer_count + subpass_count);
169
170 auto& allocator = *context.GetResourceAllocator();
171 auto desc_index = 0u;
172 for (const auto& command : commands) {
173 auto desc_set = command.pipeline->GetDescriptor()
174 .GetVertexDescriptor()
175 ->GetDescriptorSetLayouts();
176
177 if (!BindBuffers(command.vertex_bindings, allocator, encoder,
178 descriptor_sets[desc_index], desc_set, buffers, writes) ||
179 !BindBuffers(command.fragment_bindings, allocator, encoder,
180 descriptor_sets[desc_index], desc_set, buffers, writes) ||
181 !BindImages(command.fragment_bindings, allocator, encoder,
182 descriptor_sets[desc_index], images, writes)) {
183 return fml::Status(fml::StatusCode::kUnknown,
184 "Failed to bind texture or buffer.");
185 }
186
187 if (command.pipeline->GetDescriptor().UsesSubpassInput()) {
188 vk::DescriptorImageInfo image_info;
189 image_info.imageLayout = vk::ImageLayout::eGeneral;
190 image_info.sampler = VK_NULL_HANDLE;
191 image_info.imageView = input_attachment.GetImageView();
192 images.push_back(image_info);
193
194 vk::WriteDescriptorSet write_set;
195 write_set.dstSet = descriptor_sets[desc_index];
196 write_set.dstBinding = kMagicSubpassInputBinding;
197 write_set.descriptorCount = 1u;
198 write_set.descriptorType = vk::DescriptorType::eInputAttachment;
199 write_set.pImageInfo = &images.back();
200
201 writes.push_back(write_set);
202 }
203 desc_index += 1;
204 }
205
206 context.GetDevice().updateDescriptorSets(writes, {});
207 return descriptor_sets;
208 }
209
210 fml::StatusOr<std::vector<vk::DescriptorSet>> AllocateAndBindDescriptorSets(
211 const ContextVK& context,
212 const std::shared_ptr<CommandEncoderVK>& encoder,
213 const std::vector<ComputeCommand>& commands) {
214 if (commands.empty()) {
215 return std::vector<vk::DescriptorSet>{};
216 }
217 // Step 1: Determine the total number of buffer and sampler descriptor
218 // sets required. Collect this information along with the layout information
219 // to allocate a correctly sized descriptor pool.
220 size_t buffer_count = 0;
221 size_t samplers_count = 0;
222 std::vector<vk::DescriptorSetLayout> layouts;
223 layouts.reserve(commands.size());
224
225 for (const auto& command : commands) {
226 buffer_count += command.bindings.buffers.size();
227 samplers_count += command.bindings.sampled_images.size();
228
229 layouts.emplace_back(
230 ComputePipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout());
231 }
232 auto descriptor_result =
233 encoder->AllocateDescriptorSets(buffer_count, samplers_count, 0, layouts);
234 if (!descriptor_result.ok()) {
235 return descriptor_result.status();
236 }
237 auto descriptor_sets = descriptor_result.value();
238 if (descriptor_sets.empty()) {
239 return fml::Status();
240 }
241 // Step 2: Update the descriptors for all image and buffer descriptors used
242 // in the render pass.
243 std::vector<vk::DescriptorImageInfo> images;
244 std::vector<vk::DescriptorBufferInfo> buffers;
245 std::vector<vk::WriteDescriptorSet> writes;
246 images.reserve(samplers_count);
247 buffers.reserve(buffer_count);
248 writes.reserve(samplers_count + buffer_count);
249
250 auto& allocator = *context.GetResourceAllocator();
251 auto desc_index = 0u;
252 for (const auto& command : commands) {
253 auto desc_set = command.pipeline->GetDescriptor().GetDescriptorSetLayouts();
254
255 if (!BindBuffers(command.bindings, allocator, encoder,
256 descriptor_sets[desc_index], desc_set, buffers, writes) ||
257 !BindImages(command.bindings, allocator, encoder,
258 descriptor_sets[desc_index], images, writes)) {
259 return fml::Status(fml::StatusCode::kUnknown,
260 "Failed to bind texture or buffer.");
261 }
262 desc_index += 1;
263 }
264
265 context.GetDevice().updateDescriptorSets(writes, {});
266 return descriptor_sets;
267 }
268
269 } // namespace impeller
impeller::DeviceBufferVK::GetBuffer
vk::Buffer GetBuffer() const
Definition: device_buffer_vk.cc:70
impeller::DescriptorSetLayout
Definition: shader_types.h:162
impeller::ShaderUniformSlot
Metadata required to bind a buffer.
Definition: shader_types.h:81
impeller::Resource::resource
ResourceType resource
Definition: command.h:34
impeller::AllocateAndBindDescriptorSets
fml::StatusOr< std::vector< vk::DescriptorSet > > AllocateAndBindDescriptorSets(const ContextVK &context, const std::shared_ptr< CommandEncoderVK > &encoder, const std::vector< Command > &commands, const TextureVK &input_attachment)
Definition: binding_helpers_vk.cc:123
command_encoder_vk.h
impeller::ToVKDescriptorType
constexpr vk::DescriptorType ToVKDescriptorType(DescriptorType type)
Definition: formats_vk.h:269
impeller::ContextVK::GetResourceAllocator
std::shared_ptr< Allocator > GetResourceAllocator() const override
Returns the allocator used to create textures and buffers on the device.
Definition: context_vk.cc:474
impeller::Range::offset
size_t offset
Definition: range.h:15
impeller::Bindings::sampled_images
std::vector< TextureAndSampler > sampled_images
Definition: command.h:74
impeller::TextureAndSampler::sampler
std::shared_ptr< const Sampler > sampler
Definition: command.h:64
impeller::BufferView::range
Range range
Definition: buffer_view.h:16
impeller::SamplerVK
Definition: sampler_vk.h:18
command_pool_vk.h
impeller::ShaderUniformSlot::binding
size_t binding
The Vulkan binding value.
Definition: shader_types.h:92
command.h
command_buffer_vk.h
impeller::TextureVK::GetImageView
vk::ImageView GetImageView() const
Definition: texture_vk.cc:132
compute_pipeline_vk.h
impeller::BufferView::buffer
std::shared_ptr< const Buffer > buffer
Definition: buffer_view.h:14
impeller::ComputePipelineVK::GetDescriptorSetLayout
const vk::DescriptorSetLayout & GetDescriptorSetLayout() const
Definition: compute_pipeline_vk.cc:49
impeller::SampledImageSlot
Metadata required to bind a combined texture and sampler.
Definition: shader_types.h:98
impeller::BufferAndUniformSlot::view
BufferResource view
Definition: command.h:70
impeller::Allocator
An object that allocates device memory.
Definition: allocator.h:22
impeller::SamplerVK::GetSampler
vk::Sampler GetSampler() const
Definition: sampler_vk.cc:17
impeller::TextureVK
Definition: texture_vk.h:21
impeller::BindBuffers
static bool BindBuffers(const Bindings &bindings, Allocator &allocator, const std::shared_ptr< CommandEncoderVK > &encoder, vk::DescriptorSet &vk_desc_set, const std::vector< DescriptorSetLayout > &desc_set, std::vector< vk::DescriptorBufferInfo > &buffers, std::vector< vk::WriteDescriptorSet > &writes)
Definition: binding_helpers_vk.cc:63
texture_vk.h
impeller::TextureAndSampler
combines the texture, sampler and sampler slot information.
Definition: command.h:61
impeller::ContextVK
Definition: context_vk.h:40
impeller::kMagicSubpassInputBinding
static constexpr size_t kMagicSubpassInputBinding
Definition: binding_helpers_vk.cc:24
impeller::TextureAndSampler::texture
TextureResource texture
Definition: command.h:63
impeller::BufferAndUniformSlot::slot
ShaderUniformSlot slot
Definition: command.h:69
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
impeller::TextureAndSampler::slot
SampledImageSlot slot
Definition: command.h:62
impeller::Bindings::buffers
std::vector< BufferAndUniformSlot > buffers
Definition: command.h:75
impeller::ContextVK::GetDevice
const vk::Device & GetDevice() const
Definition: context_vk.cc:501
binding_helpers_vk.h
impeller::BindImages
static bool BindImages(const Bindings &bindings, Allocator &allocator, const std::shared_ptr< CommandEncoderVK > &encoder, vk::DescriptorSet &vk_desc_set, std::vector< vk::DescriptorImageInfo > &images, std::vector< vk::WriteDescriptorSet > &writes)
Definition: binding_helpers_vk.cc:26
impeller::BackendCast< TextureVK, Texture >::Cast
static TextureVK & Cast(Texture &base)
Definition: backend_cast.h:15
compute_command.h
sampler_vk.h
impeller::SampledImageSlot::binding
size_t binding
The Vulkan binding value.
Definition: shader_types.h:109
impeller::Range::length
size_t length
Definition: range.h:16
context_vk.h
impeller::DescriptorSetLayout::descriptor_type
DescriptorType descriptor_type
Definition: shader_types.h:164
impeller::PipelineVK::GetDescriptorSetLayout
const vk::DescriptorSetLayout & GetDescriptorSetLayout() const
Definition: pipeline_vk.cc:56
shader_types.h
impeller
Definition: aiks_context.cc:10
impeller::SamplerVK::GetSharedSampler
const std::shared_ptr< SharedObjectVKT< vk::Sampler > > & GetSharedSampler() const
Definition: sampler_vk.cc:22
impeller::BufferAndUniformSlot
combines the buffer resource and its uniform slot information.
Definition: command.h:68
impeller::Bindings
Definition: command.h:73