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 
6 #include "fml/status.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