66
77#include < cstdint>
88
9+ #include " impeller/renderer/backend/vulkan/barrier_vk.h"
910#include " impeller/renderer/backend/vulkan/command_encoder_vk.h"
1011#include " impeller/renderer/backend/vulkan/texture_vk.h"
12+ #include " vulkan/vulkan_core.h"
13+ #include " vulkan/vulkan_enums.hpp"
14+ #include " vulkan/vulkan_structs.hpp"
1115
1216namespace impeller {
1317
18+ static 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+
1449BlitEncodeVK::~BlitEncodeVK () = default ;
1550
1651// ------------------------------------------------------------------------------
@@ -240,37 +275,6 @@ std::string BlitGenerateMipmapCommandVK::GetLabel() const {
240275 return label;
241276}
242277
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-
274278bool BlitGenerateMipmapCommandVK::Encode (CommandEncoderVK& encoder) const {
275279 auto & src = TextureVK::Cast (*texture);
276280
@@ -288,55 +292,73 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const {
288292 return false ;
289293 }
290294
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+ // 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.
294300 InsertImageMemoryBarrier (
295301 cmd, // command buffer
296302 image, // image
297303 vk::AccessFlagBits::eTransferWrite, // src access mask
298304 vk::AccessFlagBits::eTransferRead, // dst access mask
299305 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
311306 vk::ImageLayout::eTransferDstOptimal, // new layout
312307 vk::PipelineStageFlagBits::eTransfer, // src stage
313308 vk::PipelineStageFlagBits::eTransfer, // dst stage
314- 1u , // mip level
315- mip_count - 1 // mip level count
309+ 0u , // mip level
310+ mip_count // mip level count
316311 );
317312
318- // Blit from the base mip level to all other levels.
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 ;
319325 for (size_t mip_level = 1u ; mip_level < mip_count; mip_level++) {
320- vk::ImageBlit blit;
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});
321339
340+ vk::ImageBlit blit;
322341 blit.srcSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
323342 blit.srcSubresource .baseArrayLayer = 0u ;
324343 blit.srcSubresource .layerCount = 1u ;
325- blit.srcSubresource .mipLevel = 0u ;
344+ blit.srcSubresource .mipLevel = mip_level - 1 ;
326345
327346 blit.dstSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
328347 blit.dstSubresource .baseArrayLayer = 0u ;
329348 blit.dstSubresource .layerCount = 1u ;
330349 blit.dstSubresource .mipLevel = mip_level;
331350
332351 // offsets[0] is origin.
333- blit.srcOffsets [1 ].x = size. width ;
334- blit.srcOffsets [1 ].y = size. height ;
352+ blit.srcOffsets [1 ].x = std::max< int32_t >( width, 1u ) ;
353+ blit.srcOffsets [1 ].y = std::max< int32_t >( height, 1u ) ;
335354 blit.srcOffsets [1 ].z = 1u ;
336355
356+ width = width / 2 ;
357+ height = height / 2 ;
358+
337359 // 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 );
360+ blit.dstOffsets [1 ].x = std::max<int32_t >(width, 1u );
361+ blit.dstOffsets [1 ].y = std::max<int32_t >(height, 1u );
340362 blit.dstOffsets [1 ].z = 1u ;
341363
342364 cmd.blitImage (image, // src image
@@ -347,33 +369,29 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const {
347369 &blit, // regions
348370 vk::Filter::eLinear // filter
349371 );
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});
350384 }
351385
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- );
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});
377395
378396 // We modified the layouts of this image from underneath it. Tell it its new
379397 // state so it doesn't try to perform redundant transitions under the hood.
0 commit comments