| Flutter Impeller |

blit_command_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/blit_command_vk.h"
6
7 #include <cstdint>
8
9 #include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
10 #include "impeller/renderer/backend/vulkan/texture_vk.h"
11
12 namespace impeller {
13
14 BlitEncodeVK::~BlitEncodeVK() = default;
15
16 //------------------------------------------------------------------------------
17 /// BlitCopyTextureToTextureCommandVK
18 ///
19
20 BlitCopyTextureToTextureCommandVK::~BlitCopyTextureToTextureCommandVK() =
21 default;
22
23 std::string BlitCopyTextureToTextureCommandVK::GetLabel() const {
24 return label;
25 }
26
27 bool BlitCopyTextureToTextureCommandVK::Encode(
28 CommandEncoderVK& encoder) const {
29 const auto& cmd_buffer = encoder.GetCommandBuffer();
30
31 const auto& src = TextureVK::Cast(*source);
32 const auto& dst = TextureVK::Cast(*destination);
33
34 if (!encoder.Track(source) || !encoder.Track(destination)) {
35 return false;
36 }
37
38 BarrierVK src_barrier;
39 src_barrier.cmd_buffer = cmd_buffer;
40 src_barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal;
41 src_barrier.src_access = vk::AccessFlagBits::eTransferWrite |
42 vk::AccessFlagBits::eShaderWrite |
43 vk::AccessFlagBits::eColorAttachmentWrite;
44 src_barrier.src_stage = vk::PipelineStageFlagBits::eTransfer |
45 vk::PipelineStageFlagBits::eFragmentShader |
46 vk::PipelineStageFlagBits::eColorAttachmentOutput;
47 src_barrier.dst_access = vk::AccessFlagBits::eTransferRead;
48 src_barrier.dst_stage = vk::PipelineStageFlagBits::eTransfer;
49
50 BarrierVK dst_barrier;
51 dst_barrier.cmd_buffer = cmd_buffer;
52 dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal;
53 dst_barrier.src_access = {};
54 dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
55 dst_barrier.dst_access =
56 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite;
57 dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader |
58 vk::PipelineStageFlagBits::eTransfer;
59
60 if (!src.SetLayout(src_barrier) || !dst.SetLayout(dst_barrier)) {
61 VALIDATION_LOG << "Could not complete layout transitions.";
62 return false;
63 }
64
65 vk::ImageCopy image_copy;
66
67 image_copy.setSrcSubresource(
68 vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1));
69 image_copy.setDstSubresource(
70 vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1));
71
72 image_copy.srcOffset =
73 vk::Offset3D(source_region.GetX(), source_region.GetY(), 0);
74 image_copy.dstOffset =
75 vk::Offset3D(destination_origin.x, destination_origin.y, 0);
76 image_copy.extent =
77 vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1);
78
79 // Issue the copy command now that the images are already in the right
80 // layouts.
81 cmd_buffer.copyImage(src.GetImage(), //
82 src_barrier.new_layout, //
83 dst.GetImage(), //
84 dst_barrier.new_layout, //
85 image_copy //
86 );
87
88 // If this is an onscreen texture, do not transition the layout
89 // back to shader read.
90 if (dst.IsSwapchainImage()) {
91 return true;
92 }
93
94 BarrierVK barrier;
95 barrier.cmd_buffer = cmd_buffer;
96 barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
97 barrier.src_access = {};
98 barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
99 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
100 barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
101
102 return dst.SetLayout(barrier);
103 }
104
105 //------------------------------------------------------------------------------
106 /// BlitCopyTextureToBufferCommandVK
107 ///
108
109 BlitCopyTextureToBufferCommandVK::~BlitCopyTextureToBufferCommandVK() = default;
110
111 std::string BlitCopyTextureToBufferCommandVK::GetLabel() const {
112 return label;
113 }
114
115 bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const {
116 const auto& cmd_buffer = encoder.GetCommandBuffer();
117
118 // cast source and destination to TextureVK
119 const auto& src = TextureVK::Cast(*source);
120
121 if (!encoder.Track(source) || !encoder.Track(destination)) {
122 return false;
123 }
124
125 BarrierVK barrier;
126 barrier.cmd_buffer = cmd_buffer;
127 barrier.new_layout = vk::ImageLayout::eTransferSrcOptimal;
128 barrier.src_access = vk::AccessFlagBits::eShaderWrite |
129 vk::AccessFlagBits::eTransferWrite |
130 vk::AccessFlagBits::eColorAttachmentWrite;
131 barrier.src_stage = vk::PipelineStageFlagBits::eFragmentShader |
132 vk::PipelineStageFlagBits::eTransfer |
133 vk::PipelineStageFlagBits::eColorAttachmentOutput;
134 barrier.dst_access = vk::AccessFlagBits::eShaderRead;
135 barrier.dst_stage = vk::PipelineStageFlagBits::eVertexShader |
136 vk::PipelineStageFlagBits::eFragmentShader;
137
138 const auto& dst = DeviceBufferVK::Cast(*destination);
139
140 vk::BufferImageCopy image_copy;
141 image_copy.setBufferOffset(destination_offset);
142 image_copy.setBufferRowLength(0);
143 image_copy.setBufferImageHeight(0);
144 image_copy.setImageSubresource(
145 vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1));
146 image_copy.setImageOffset(
147 vk::Offset3D(source_region.GetX(), source_region.GetY(), 0));
148 image_copy.setImageExtent(
149 vk::Extent3D(source_region.GetWidth(), source_region.GetHeight(), 1));
150
151 if (!src.SetLayout(barrier)) {
152 VALIDATION_LOG << "Could not encode layout transition.";
153 return false;
154 }
155
156 cmd_buffer.copyImageToBuffer(src.GetImage(), //
157 barrier.new_layout, //
158 dst.GetBuffer(), //
159 image_copy //
160 );
161
162 // If the buffer is used for readback, then apply a transfer -> host memory
163 // barrier.
164 if (destination->GetDeviceBufferDescriptor().readback) {
165 vk::MemoryBarrier barrier;
166 barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
167 barrier.dstAccessMask = vk::AccessFlagBits::eHostRead;
168
169 cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
170 vk::PipelineStageFlagBits::eHost, {}, 1,
171 &barrier, 0, {}, 0, {});
172 }
173
174 return true;
175 }
176
177 //------------------------------------------------------------------------------
178 /// BlitCopyBufferToTextureCommandVK
179 ///
180
181 BlitCopyBufferToTextureCommandVK::~BlitCopyBufferToTextureCommandVK() = default;
182
183 std::string BlitCopyBufferToTextureCommandVK::GetLabel() const {
184 return label;
185 }
186
187 bool BlitCopyBufferToTextureCommandVK::Encode(CommandEncoderVK& encoder) const {
188 const auto& cmd_buffer = encoder.GetCommandBuffer();
189
190 // cast destination to TextureVK
191 const auto& dst = TextureVK::Cast(*destination);
192 const auto& src = DeviceBufferVK::Cast(*source.buffer);
193
194 if (!encoder.Track(source.buffer) || !encoder.Track(destination)) {
195 return false;
196 }
197
198 BarrierVK dst_barrier;
199 dst_barrier.cmd_buffer = cmd_buffer;
200 dst_barrier.new_layout = vk::ImageLayout::eTransferDstOptimal;
201 dst_barrier.src_access = {};
202 dst_barrier.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
203 dst_barrier.dst_access =
204 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferWrite;
205 dst_barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader |
206 vk::PipelineStageFlagBits::eTransfer;
207
208 vk::BufferImageCopy image_copy;
209 image_copy.setBufferOffset(source.range.offset);
210 image_copy.setBufferRowLength(0);
211 image_copy.setBufferImageHeight(0);
212 image_copy.setImageSubresource(
213 vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1));
214 image_copy.setImageOffset(
215 vk::Offset3D(destination_origin.x, destination_origin.y, 0));
216 image_copy.setImageExtent(vk::Extent3D(destination->GetSize().width,
217 destination->GetSize().height, 1));
218
219 if (!dst.SetLayout(dst_barrier)) {
220 VALIDATION_LOG << "Could not encode layout transition.";
221 return false;
222 }
223
224 cmd_buffer.copyBufferToImage(src.GetBuffer(), //
225 dst.GetImage(), //
226 dst_barrier.new_layout, //
227 image_copy //
228 );
229
230 return true;
231 }
232
233 //------------------------------------------------------------------------------
234 /// BlitGenerateMipmapCommandVK
235 ///
236
237 BlitGenerateMipmapCommandVK::~BlitGenerateMipmapCommandVK() = default;
238
239 std::string BlitGenerateMipmapCommandVK::GetLabel() const {
240 return label;
241 }
242
243 static void InsertImageMemoryBarrier(const vk::CommandBuffer& cmd,
244 const vk::Image& image,
245 vk::AccessFlags src_access_mask,
246 vk::AccessFlags dst_access_mask,
247 vk::ImageLayout old_layout,
248 vk::ImageLayout new_layout,
249 vk::PipelineStageFlags src_stage,
250 vk::PipelineStageFlags dst_stage,
251 uint32_t base_mip_level,
252 uint32_t mip_level_count = 1u) {
253 if (old_layout == new_layout) {
254 return;
255 }
256
257 vk::ImageMemoryBarrier barrier;
258 barrier.srcAccessMask = src_access_mask;
259 barrier.dstAccessMask = dst_access_mask;
260 barrier.oldLayout = old_layout;
261 barrier.newLayout = new_layout;
262 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
263 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
264 barrier.image = image;
265 barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
266 barrier.subresourceRange.baseMipLevel = base_mip_level;
267 barrier.subresourceRange.levelCount = mip_level_count;
268 barrier.subresourceRange.baseArrayLayer = 0u;
269 barrier.subresourceRange.layerCount = 1u;
270
271 cmd.pipelineBarrier(src_stage, dst_stage, {}, nullptr, nullptr, barrier);
272 }
273
274 bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const {
275 auto& src = TextureVK::Cast(*texture);
276
277 const auto size = src.GetTextureDescriptor().size;
278 uint32_t mip_count = src.GetTextureDescriptor().mip_count;
279
280 if (mip_count < 2u) {
281 return true;
282 }
283
284 const auto& image = src.GetImage();
285 const auto& cmd = encoder.GetCommandBuffer();
286
287 if (!encoder.Track(texture)) {
288 return false;
289 }
290
291 // Transition the base mip level to transfer-src layout so we can read from
292 // it and transition the rest to dst-optimal since they are going to be
293 // written to.
294 InsertImageMemoryBarrier(
295 cmd, // command buffer
296 image, // image
297 vk::AccessFlagBits::eTransferWrite, // src access mask
298 vk::AccessFlagBits::eTransferRead, // dst access mask
299 src.GetLayout(), // old layout
300 vk::ImageLayout::eTransferSrcOptimal, // new layout
301 vk::PipelineStageFlagBits::eTransfer, // src stage
302 vk::PipelineStageFlagBits::eTransfer, // dst stage
303 0u // mip level
304 );
305 InsertImageMemoryBarrier(
306 cmd, // command buffer
307 image, // image
308 {}, // src access mask
309 vk::AccessFlagBits::eTransferWrite, // dst access mask
310 vk::ImageLayout::eUndefined, // old layout
311 vk::ImageLayout::eTransferDstOptimal, // new layout
312 vk::PipelineStageFlagBits::eTransfer, // src stage
313 vk::PipelineStageFlagBits::eTransfer, // dst stage
314 1u, // mip level
315 mip_count - 1 // mip level count
316 );
317
318 // Blit from the base mip level to all other levels.
319 for (size_t mip_level = 1u; mip_level < mip_count; mip_level++) {
320 vk::ImageBlit blit;
321
322 blit.srcSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
323 blit.srcSubresource.baseArrayLayer = 0u;
324 blit.srcSubresource.layerCount = 1u;
325 blit.srcSubresource.mipLevel = 0u;
326
327 blit.dstSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
328 blit.dstSubresource.baseArrayLayer = 0u;
329 blit.dstSubresource.layerCount = 1u;
330 blit.dstSubresource.mipLevel = mip_level;
331
332 // offsets[0] is origin.
333 blit.srcOffsets[1].x = size.width;
334 blit.srcOffsets[1].y = size.height;
335 blit.srcOffsets[1].z = 1u;
336
337 // offsets[0] is origin.
338 blit.dstOffsets[1].x = std::max<int32_t>(size.width >> mip_level, 1u);
339 blit.dstOffsets[1].y = std::max<int32_t>(size.height >> mip_level, 1u);
340 blit.dstOffsets[1].z = 1u;
341
342 cmd.blitImage(image, // src image
343 vk::ImageLayout::eTransferSrcOptimal, // src layout
344 image, // dst image
345 vk::ImageLayout::eTransferDstOptimal, // dst layout
346 1u, // region count
347 &blit, // regions
348 vk::Filter::eLinear // filter
349 );
350 }
351
352 // Transition all mip levels to shader read. The base mip level has a
353 // different "old" layout than the rest now.
354 InsertImageMemoryBarrier(
355 cmd, // command buffer
356 image, // image
357 vk::AccessFlagBits::eTransferWrite, // src access mask
358 vk::AccessFlagBits::eShaderRead, // dst access mask
359 vk::ImageLayout::eTransferSrcOptimal, // old layout
360 vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
361 vk::PipelineStageFlagBits::eTransfer, // src stage
362 vk::PipelineStageFlagBits::eFragmentShader, // dst stage
363 0u // mip level
364 );
365 InsertImageMemoryBarrier(
366 cmd, // command buffer
367 image, // image
368 vk::AccessFlagBits::eTransferWrite, // src access mask
369 vk::AccessFlagBits::eShaderRead, // dst access mask
370 vk::ImageLayout::eTransferDstOptimal, // old layout
371 vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
372 vk::PipelineStageFlagBits::eTransfer, // src stage
373 vk::PipelineStageFlagBits::eFragmentShader, // dst stage
374 1u, // mip level
375 mip_count - 1 // mip level count
376 );
377
378 // We modified the layouts of this image from underneath it. Tell it its new
379 // state so it doesn't try to perform redundant transitions under the hood.
380 src.SetLayoutWithoutEncoding(vk::ImageLayout::eShaderReadOnlyOptimal);
381 src.SetMipMapGenerated();
382
383 return true;
384 }
385
386 } // namespace impeller
impeller::BarrierVK::dst_access
vk::AccessFlags dst_access
Definition: barrier_vk.h:50
impeller::TPoint::y
Type y
Definition: point.h:31
command_encoder_vk.h
impeller::BarrierVK::new_layout
vk::ImageLayout new_layout
Definition: barrier_vk.h:30
impeller::BarrierVK::cmd_buffer
vk::CommandBuffer cmd_buffer
Definition: barrier_vk.h:29
impeller::BlitGenerateMipmapCommandVK::GetLabel
std::string GetLabel() const override
Definition: blit_command_vk.cc:239
impeller::Range::offset
size_t offset
Definition: range.h:15
impeller::BlitCopyTextureToTextureCommand::destination
std::shared_ptr< Texture > destination
Definition: blit_command.h:20
impeller::BlitGenerateMipmapCommandVK::Encode
bool Encode(CommandEncoderVK &encoder) const override
Definition: blit_command_vk.cc:274
impeller::TRect::GetX
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition: rect.h:300
impeller::BufferView::range
Range range
Definition: buffer_view.h:17
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:314
impeller::BlitCopyTextureToTextureCommand::destination_origin
IPoint destination_origin
Definition: blit_command.h:22
impeller::BlitCopyTextureToTextureCommandVK::Encode
bool Encode(CommandEncoderVK &encoder) const override
Definition: blit_command_vk.cc:27
impeller::BlitCopyTextureToTextureCommandVK::GetLabel
std::string GetLabel() const override
Definition: blit_command_vk.cc:23
impeller::BlitGenerateMipmapCommand::texture
std::shared_ptr< Texture > texture
Definition: blit_command.h:39
impeller::BlitCopyBufferToTextureCommandVK::Encode
bool Encode(CommandEncoderVK &encoder) const override
Definition: blit_command_vk.cc:187
impeller::BlitCommand::label
std::string label
Definition: blit_command.h:15
impeller::BarrierVK
Defines an operations and memory access barrier on a resource.
Definition: barrier_vk.h:28
impeller::BlitCopyBufferToTextureCommand::source
BufferView source
Definition: blit_command.h:33
impeller::CommandEncoderVK::Track
bool Track(std::shared_ptr< SharedObjectVK > object)
Definition: command_encoder_vk.cc:112
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:308
impeller::BlitCopyTextureToBufferCommand::destination_offset
size_t destination_offset
Definition: blit_command.h:29
impeller::BlitGenerateMipmapCommandVK::~BlitGenerateMipmapCommandVK
~BlitGenerateMipmapCommandVK() override
blit_command_vk.h
impeller::BlitCopyTextureToBufferCommandVK::GetLabel
std::string GetLabel() const override
Definition: blit_command_vk.cc:111
impeller::BarrierVK::src_access
vk::AccessFlags src_access
Definition: barrier_vk.h:40
impeller::BlitCopyTextureToBufferCommand::destination
std::shared_ptr< DeviceBuffer > destination
Definition: blit_command.h:27
impeller::InsertImageMemoryBarrier
static void InsertImageMemoryBarrier(const vk::CommandBuffer &cmd, const vk::Image &image, vk::AccessFlags src_access_mask, vk::AccessFlags dst_access_mask, vk::ImageLayout old_layout, vk::ImageLayout new_layout, vk::PipelineStageFlags src_stage, vk::PipelineStageFlags dst_stage, uint32_t base_mip_level, uint32_t mip_level_count=1u)
Definition: blit_command_vk.cc:243
impeller::BlitCopyTextureToBufferCommandVK::Encode
bool Encode(CommandEncoderVK &encoder) const override
Definition: blit_command_vk.cc:115
impeller::BlitCopyTextureToTextureCommand::source
std::shared_ptr< Texture > source
Definition: blit_command.h:19
texture_vk.h
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::BarrierVK::dst_stage
vk::PipelineStageFlags dst_stage
Definition: barrier_vk.h:45
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::BackendCast< TextureVK, Texture >::Cast
static TextureVK & Cast(Texture &base)
Definition: backend_cast.h:13
impeller::BufferView::buffer
std::shared_ptr< const DeviceBuffer > buffer
Definition: buffer_view.h:16
impeller::BlitCopyTextureToBufferCommand::source
std::shared_ptr< Texture > source
Definition: blit_command.h:26
impeller::BlitCopyBufferToTextureCommandVK::~BlitCopyBufferToTextureCommandVK
~BlitCopyBufferToTextureCommandVK() override
impeller::BlitCopyTextureToTextureCommand::source_region
IRect source_region
Definition: blit_command.h:21
impeller::BlitCopyBufferToTextureCommand::destination_origin
IPoint destination_origin
Definition: blit_command.h:35
impeller::BlitCopyTextureToBufferCommandVK::~BlitCopyTextureToBufferCommandVK
~BlitCopyTextureToBufferCommandVK() override
impeller::BlitCopyTextureToTextureCommandVK::~BlitCopyTextureToTextureCommandVK
~BlitCopyTextureToTextureCommandVK() override
impeller::CommandEncoderVK
Definition: command_encoder_vk.h:50
impeller::TRect::GetY
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition: rect.h:304
impeller
Definition: aiks_blur_unittests.cc:20
impeller::BlitCopyTextureToBufferCommand::source_region
IRect source_region
Definition: blit_command.h:28
impeller::BlitEncodeVK::~BlitEncodeVK
virtual ~BlitEncodeVK()
impeller::CommandEncoderVK::GetCommandBuffer
vk::CommandBuffer GetCommandBuffer() const
Definition: command_encoder_vk.cc:98
impeller::BarrierVK::src_stage
vk::PipelineStageFlags src_stage
Definition: barrier_vk.h:35
impeller::BlitCopyBufferToTextureCommand::destination
std::shared_ptr< Texture > destination
Definition: blit_command.h:34
impeller::BlitCopyBufferToTextureCommandVK::GetLabel
std::string GetLabel() const override
Definition: blit_command_vk.cc:183