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 
6 
7 #include <cstdint>
8 
11 
12 namespace impeller {
13 
14 BlitEncodeVK::~BlitEncodeVK() = default;
15 
16 //------------------------------------------------------------------------------
17 /// BlitCopyTextureToTextureCommandVK
18 ///
19 
21  default;
22 
24  return label;
25 }
26 
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 
110 
112  return label;
113 }
114 
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 
182 
184  return label;
185 }
186 
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 
238 
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 
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.
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  );
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.
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  );
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