| 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
5 #include "impeller/renderer/backend/vulkan/render_pass_builder_vk.h"
6
7 #include "impeller/core/formats.h"
8 #include "impeller/renderer/backend/vulkan/formats_vk.h"
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
22 constexpr auto kSelfDependencySrcStageMask =
23 vk::PipelineStageFlagBits::eColorAttachmentOutput;
24 constexpr auto kSelfDependencySrcAccessMask =
25 vk::AccessFlagBits::eColorAttachmentWrite;
26
27 constexpr auto kSelfDependencyDstStageMask =
28 vk::PipelineStageFlagBits::eFragmentShader;
29 constexpr auto kSelfDependencyDstAccessMask =
30 vk::AccessFlagBits::eInputAttachmentRead;
31
32 constexpr auto kSelfDependencyFlags = vk::DependencyFlagBits::eByRegion;
33
34 RenderPassBuilderVK::RenderPassBuilderVK() = default;
35
36 RenderPassBuilderVK::~RenderPassBuilderVK() = default;
37
38 RenderPassBuilderVK& RenderPassBuilderVK::SetColorAttachment(
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
86 RenderPassBuilderVK& RenderPassBuilderVK::SetDepthStencilAttachment(
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
104 RenderPassBuilderVK& RenderPassBuilderVK::SetStencilAttachment(
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, //
266 kSelfDependencyDstStageMask, //
267 kSelfDependencyFlags, //
268 {}, //
269 {}, //
270 barrier //
271 );
272 }
273
274 const std::map<size_t, vk::AttachmentDescription>&
275 RenderPassBuilderVK::GetColorAttachments() const {
276 return colors_;
277 }
278
279 const std::map<size_t, vk::AttachmentDescription>&
280 RenderPassBuilderVK::GetResolves() const {
281 return resolves_;
282 }
283
284 const std::optional<vk::AttachmentDescription>&
285 RenderPassBuilderVK::GetDepthStencil() const {
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
impeller::RenderPassBuilderVK
Definition: render_pass_builder_vk.h:21
impeller::RenderPassBuilderVK::GetColor0
std::optional< vk::AttachmentDescription > GetColor0() const
Definition: render_pass_builder_vk.cc:290
impeller::RenderPassBuilderVK::SetDepthStencilAttachment
RenderPassBuilderVK & SetDepthStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
Definition: render_pass_builder_vk.cc:86
impeller::RenderPassBuilderVK::GetColorAttachments
const std::map< size_t, vk::AttachmentDescription > & GetColorAttachments() const
Definition: render_pass_builder_vk.cc:275
impeller::RenderPassBuilderVK::GetResolves
const std::map< size_t, vk::AttachmentDescription > & GetResolves() const
Definition: render_pass_builder_vk.cc:280
impeller::RenderPassBuilderVK::SetStencilAttachment
RenderPassBuilderVK & SetStencilAttachment(PixelFormat format, SampleCount sample_count, LoadAction load_action, StoreAction store_action)
Definition: render_pass_builder_vk.cc:104
impeller::RenderPassBuilderVK::RenderPassBuilderVK
RenderPassBuilderVK()
impeller::RenderPassBuilderVK::GetDepthStencil
const std::optional< vk::AttachmentDescription > & GetDepthStencil() const
Definition: render_pass_builder_vk.cc:285
impeller::RenderPassBuilderVK::SetColorAttachment
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)
Definition: render_pass_builder_vk.cc:38
impeller::RenderPassBuilderVK::Build
vk::UniqueRenderPass Build(const vk::Device &device) const
Definition: render_pass_builder_vk.cc:122
impeller::RenderPassBuilderVK::GetColor0Resolve
std::optional< vk::AttachmentDescription > GetColor0Resolve() const
Definition: render_pass_builder_vk.cc:296
impeller::RenderPassBuilderVK::~RenderPassBuilderVK
~RenderPassBuilderVK()
formats.h
formats_vk.h
e1
Vector3 e1
Definition: line_contents.cc:107
impeller
Definition: allocation.cc:12
impeller::kUnusedAttachmentReference
static constexpr vk::AttachmentReference kUnusedAttachmentReference
Definition: formats_vk.h:441
impeller::kSelfDependencyDstAccessMask
constexpr auto kSelfDependencyDstAccessMask
Definition: render_pass_builder_vk.cc:29
impeller::kSelfDependencySrcAccessMask
constexpr auto kSelfDependencySrcAccessMask
Definition: render_pass_builder_vk.cc:24
impeller::StoreActionPerformsResolve
constexpr bool StoreActionPerformsResolve(StoreAction store_action)
Definition: formats_vk.h:345
impeller::ToVKAttachmentLoadOp
constexpr vk::AttachmentLoadOp ToVKAttachmentLoadOp(LoadAction load_action)
Definition: formats_vk.h:308
impeller::PixelFormat
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
impeller::ToVKAttachmentStoreOp
constexpr vk::AttachmentStoreOp ToVKAttachmentStoreOp(StoreAction store_action, bool is_resolve_texture)
Definition: formats_vk.h:321
impeller::kSelfDependencySrcStageMask
constexpr auto kSelfDependencySrcStageMask
Definition: render_pass_builder_vk.cc:22
impeller::kSelfDependencyDstStageMask
constexpr auto kSelfDependencyDstStageMask
Definition: render_pass_builder_vk.cc:27
impeller::LoadAction
LoadAction
Definition: formats.h:205
impeller::LoadAction::kLoad
@ kLoad
impeller::StoreAction
StoreAction
Definition: formats.h:211
impeller::ToVKSampleCount
constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count)
Definition: formats_vk.h:216
impeller::ToVKImageFormat
constexpr vk::Format ToVKImageFormat(PixelFormat format)
Definition: formats_vk.h:146
impeller::kSelfDependencyFlags
constexpr auto kSelfDependencyFlags
Definition: render_pass_builder_vk.cc:32
impeller::InsertBarrierForInputAttachmentRead
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...
Definition: render_pass_builder_vk.cc:244
impeller::SampleCount
SampleCount
Definition: formats.h:298
impeller::SampleCount::kCount1
@ kCount1
render_pass_builder_vk.h
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:91