Flutter Impeller
render_pass_builder_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 
9 
10 namespace impeller {
11 
12 namespace {
13 // Compute the final layout for a given image state.
14 vk::ImageLayout ComputeFinalLayout(bool is_swapchain, SampleCount count) {
15  if (is_swapchain || count != SampleCount::kCount1) {
16  return vk::ImageLayout::eGeneral;
17  }
18  return vk::ImageLayout::eShaderReadOnlyOptimal;
19 }
20 } // namespace
21 
23  vk::PipelineStageFlagBits::eColorAttachmentOutput;
25  vk::AccessFlagBits::eColorAttachmentWrite;
26 
28  vk::PipelineStageFlagBits::eFragmentShader;
30  vk::AccessFlagBits::eInputAttachmentRead;
31 
32 constexpr auto kSelfDependencyFlags = vk::DependencyFlagBits::eByRegion;
33 
35 
37 
39  size_t index,
40  PixelFormat format,
41  SampleCount sample_count,
42  LoadAction load_action,
43  StoreAction store_action,
44  vk::ImageLayout current_layout,
45  bool is_swapchain) {
46  vk::AttachmentDescription desc;
47  desc.format = ToVKImageFormat(format);
48  desc.samples = ToVKSampleCount(sample_count);
49  desc.loadOp = ToVKAttachmentLoadOp(load_action);
50  desc.storeOp = ToVKAttachmentStoreOp(store_action, false);
51  desc.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
52  desc.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
53  if (load_action == LoadAction::kLoad) {
54  desc.initialLayout = current_layout;
55  } else {
56  desc.initialLayout = vk::ImageLayout::eUndefined;
57  }
58  desc.finalLayout = ComputeFinalLayout(is_swapchain, sample_count);
59 
60  const bool performs_resolves = StoreActionPerformsResolve(store_action);
61  if (index == 0u) {
62  color0_ = desc;
63 
64  if (performs_resolves) {
65  desc.storeOp = ToVKAttachmentStoreOp(store_action, true);
66  desc.samples = vk::SampleCountFlagBits::e1;
67  desc.finalLayout = ComputeFinalLayout(is_swapchain, SampleCount::kCount1);
68  color0_resolve_ = desc;
69  } else {
70  color0_resolve_ = std::nullopt;
71  }
72  } else {
73  colors_[index] = desc;
74  if (performs_resolves) {
75  desc.storeOp = ToVKAttachmentStoreOp(store_action, true);
76  desc.samples = vk::SampleCountFlagBits::e1;
77  desc.finalLayout = ComputeFinalLayout(is_swapchain, SampleCount::kCount1);
78  resolves_[index] = desc;
79  } else {
80  resolves_.erase(index);
81  }
82  }
83  return *this;
84 }
85 
87  PixelFormat format,
88  SampleCount sample_count,
89  LoadAction load_action,
90  StoreAction store_action) {
91  vk::AttachmentDescription desc;
92  desc.format = ToVKImageFormat(format);
93  desc.samples = ToVKSampleCount(sample_count);
94  desc.loadOp = ToVKAttachmentLoadOp(load_action);
95  desc.storeOp = ToVKAttachmentStoreOp(store_action, false);
96  desc.stencilLoadOp = desc.loadOp; // Not separable in Impeller.
97  desc.stencilStoreOp = desc.storeOp; // Not separable in Impeller.
98  desc.initialLayout = vk::ImageLayout::eUndefined;
99  desc.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
100  depth_stencil_ = desc;
101  return *this;
102 }
103 
105  PixelFormat format,
106  SampleCount sample_count,
107  LoadAction load_action,
108  StoreAction store_action) {
109  vk::AttachmentDescription desc;
110  desc.format = ToVKImageFormat(format);
111  desc.samples = ToVKSampleCount(sample_count);
112  desc.loadOp = vk::AttachmentLoadOp::eDontCare;
113  desc.storeOp = vk::AttachmentStoreOp::eDontCare;
114  desc.stencilLoadOp = ToVKAttachmentLoadOp(load_action);
115  desc.stencilStoreOp = ToVKAttachmentStoreOp(store_action, false);
116  desc.initialLayout = vk::ImageLayout::eUndefined;
117  desc.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
118  depth_stencil_ = desc;
119  return *this;
120 }
121 
122 vk::UniqueRenderPass RenderPassBuilderVK::Build(
123  const vk::Device& device) const {
124  // This must be less than `VkPhysicalDeviceLimits::maxColorAttachments` but we
125  // are not checking.
126  auto color_attachments_count =
127  colors_.empty() ? 0u : colors_.rbegin()->first + 1u;
128  if (color0_.has_value()) {
129  color_attachments_count++;
130  }
131 
132  std::array<vk::AttachmentDescription, kMaxAttachments> attachments;
133  std::array<vk::AttachmentReference, kMaxColorAttachments> color_refs;
134  std::array<vk::AttachmentReference, kMaxColorAttachments> resolve_refs;
135  vk::AttachmentReference depth_stencil_ref = kUnusedAttachmentReference;
136  size_t attachments_index = 0;
137  size_t color_index = 0;
138  size_t resolve_index = 0;
139 
140  if (color0_.has_value()) {
141  vk::AttachmentReference color_ref;
142  color_ref.attachment = attachments_index;
143  color_ref.layout = vk::ImageLayout::eGeneral;
144  color_refs.at(color_index++) = color_ref;
145  attachments.at(attachments_index++) = color0_.value();
146 
147  if (color0_resolve_.has_value()) {
148  vk::AttachmentReference resolve_ref;
149  resolve_ref.attachment = attachments_index;
150  resolve_ref.layout = vk::ImageLayout::eGeneral;
151  resolve_refs.at(resolve_index++) = resolve_ref;
152  attachments.at(attachments_index++) = color0_resolve_.value();
153  } else {
154  resolve_refs.at(resolve_index++) = kUnusedAttachmentReference;
155  }
156  }
157 
158  for (const auto& color : colors_) {
159  vk::AttachmentReference color_ref;
160  color_ref.attachment = attachments_index;
161  color_ref.layout = vk::ImageLayout::eGeneral;
162  color_refs.at(color_index++) = color_ref;
163  attachments.at(attachments_index++) = color.second;
164 
165  if (auto found = resolves_.find(color.first); found != resolves_.end()) {
166  vk::AttachmentReference resolve_ref;
167  resolve_ref.attachment = attachments_index;
168  resolve_ref.layout = vk::ImageLayout::eGeneral;
169  resolve_refs.at(resolve_index++) = resolve_ref;
170  attachments.at(attachments_index++) = found->second;
171  } else {
172  resolve_refs.at(resolve_index++) = kUnusedAttachmentReference;
173  }
174  }
175 
176  if (depth_stencil_.has_value()) {
177  depth_stencil_ref.attachment = attachments_index;
178  depth_stencil_ref.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
179  attachments.at(attachments_index++) = depth_stencil_.value();
180  }
181 
182  vk::SubpassDescription subpass0;
183  subpass0.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
184  subpass0.setPInputAttachments(color_refs.data());
185  subpass0.setInputAttachmentCount(color_index);
186  subpass0.setPColorAttachments(color_refs.data());
187  subpass0.setColorAttachmentCount(color_index);
188  subpass0.setPResolveAttachments(resolve_refs.data());
189 
190  subpass0.setPDepthStencilAttachment(&depth_stencil_ref);
191 
192  vk::SubpassDependency deps[3];
193  // Incoming dependency. If the attachments were previously used
194  // as attachments for a render pass, or sampled from/transfered to,
195  // then these operations must complete before we resolve anything
196  // to the onscreen.
197  deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
198  deps[0].dstSubpass = 0u;
199  deps[0].srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput |
200  vk::PipelineStageFlagBits::eFragmentShader;
201  deps[0].srcAccessMask = vk::AccessFlagBits::eShaderRead |
202  vk::AccessFlagBits::eColorAttachmentWrite;
203  deps[0].dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
204  deps[0].dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
205  deps[0].dependencyFlags = kSelfDependencyFlags;
206 
207  // Self dependency for reading back the framebuffer, necessary for
208  // programmable blend support / framebuffer fetch.
209  deps[1].srcSubpass = 0u; // first subpass
210  deps[1].dstSubpass = 0u; // to itself
211  deps[1].srcStageMask = kSelfDependencySrcStageMask;
212  deps[1].srcAccessMask = kSelfDependencySrcAccessMask;
213  deps[1].dstStageMask = kSelfDependencyDstStageMask;
214  deps[1].dstAccessMask = kSelfDependencyDstAccessMask;
215  deps[1].dependencyFlags = kSelfDependencyFlags;
216 
217  // Outgoing dependency. The resolve step or color attachment must complete
218  // before we can sample from the image. This dependency is ignored for the
219  // onscreen as we will already insert a barrier before presenting the
220  // swapchain.
221  deps[2].srcSubpass = 0u; // first subpass
222  deps[2].dstSubpass = VK_SUBPASS_EXTERNAL;
223  deps[2].srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
224  deps[2].srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
225  deps[2].dstStageMask = vk::PipelineStageFlagBits::eFragmentShader;
226  deps[2].dstAccessMask = vk::AccessFlagBits::eShaderRead;
227  deps[2].dependencyFlags = kSelfDependencyFlags;
228 
229  vk::RenderPassCreateInfo render_pass_desc;
230  render_pass_desc.setPAttachments(attachments.data());
231  render_pass_desc.setAttachmentCount(attachments_index);
232  render_pass_desc.setSubpasses(subpass0);
233  render_pass_desc.setPDependencies(deps);
234  render_pass_desc.setDependencyCount(3);
235 
236  auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
237  if (result != vk::Result::eSuccess) {
238  VALIDATION_LOG << "Failed to create render pass: " << vk::to_string(result);
239  return {};
240  }
241  return std::move(pass);
242 }
243 
244 void InsertBarrierForInputAttachmentRead(const vk::CommandBuffer& buffer,
245  const vk::Image& image) {
246  // This barrier must be a subset of the masks specified in the subpass
247  // dependency setup.
248  vk::ImageMemoryBarrier barrier;
249  barrier.srcAccessMask = kSelfDependencySrcAccessMask;
250  barrier.dstAccessMask = kSelfDependencyDstAccessMask;
251  barrier.oldLayout = vk::ImageLayout::eGeneral;
252  barrier.newLayout = vk::ImageLayout::eGeneral;
253  barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
254  barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
255  barrier.image = image;
256 
257  vk::ImageSubresourceRange image_levels;
258  image_levels.aspectMask = vk::ImageAspectFlagBits::eColor;
259  image_levels.baseArrayLayer = 0u;
260  image_levels.baseMipLevel = 0u;
261  image_levels.layerCount = VK_REMAINING_ARRAY_LAYERS;
262  image_levels.levelCount = VK_REMAINING_MIP_LEVELS;
263  barrier.subresourceRange = image_levels;
264 
265  buffer.pipelineBarrier(kSelfDependencySrcStageMask, //
268  {}, //
269  {}, //
270  barrier //
271  );
272 }
273 
274 const std::map<size_t, vk::AttachmentDescription>&
276  return colors_;
277 }
278 
279 const std::map<size_t, vk::AttachmentDescription>&
281  return resolves_;
282 }
283 
284 const std::optional<vk::AttachmentDescription>&
286  return depth_stencil_;
287 }
288 
289 // Visible for testing.
290 std::optional<vk::AttachmentDescription> RenderPassBuilderVK::GetColor0()
291  const {
292  return color0_;
293 }
294 
295 // Visible for testing.
296 std::optional<vk::AttachmentDescription> RenderPassBuilderVK::GetColor0Resolve()
297  const {
298  return color0_resolve_;
299 }
300 
301 } // namespace impeller
std::optional< vk::AttachmentDescription > GetColor0() const
RenderPassBuilderVK & SetDepthStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
const std::map< size_t, vk::AttachmentDescription > & GetColorAttachments() const
const std::map< size_t, vk::AttachmentDescription > & GetResolves() const
RenderPassBuilderVK & SetStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
const std::optional< vk::AttachmentDescription > & GetDepthStencil() const
RenderPassBuilderVK & SetColorAttachment(size_t index, PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action, vk::ImageLayout current_layout=vk::ImageLayout::eUndefined, bool is_swapchain=false)
vk::UniqueRenderPass Build(const vk::Device &device) const
std::optional< vk::AttachmentDescription > GetColor0Resolve() const
Vector3 e1
static constexpr vk::AttachmentReference kUnusedAttachmentReference
Definition: formats_vk.h:438
constexpr auto kSelfDependencyDstAccessMask
constexpr auto kSelfDependencySrcAccessMask
constexpr bool StoreActionPerformsResolve(StoreAction store_action)
Definition: formats_vk.h:343
constexpr vk::AttachmentLoadOp ToVKAttachmentLoadOp(LoadAction load_action)
Definition: formats_vk.h:306
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
constexpr vk::AttachmentStoreOp ToVKAttachmentStoreOp(StoreAction store_action, bool is_resolve_texture)
Definition: formats_vk.h:319
constexpr auto kSelfDependencySrcStageMask
constexpr auto kSelfDependencyDstStageMask
LoadAction
Definition: formats.h:202
StoreAction
Definition: formats.h:208
constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count)
Definition: formats_vk.h:214
constexpr vk::Format ToVKImageFormat(PixelFormat format)
Definition: formats_vk.h:146
constexpr auto kSelfDependencyFlags
void InsertBarrierForInputAttachmentRead(const vk::CommandBuffer &buffer, const vk::Image &image)
Inserts the appropriate barriers to ensure that subsequent commands can read from the specified image...
SampleCount
Definition: formats.h:295
#define VALIDATION_LOG
Definition: validation.h:91