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