@@ -59,10 +59,13 @@ std::string BlitCopyTextureToTextureCommandVK::GetLabel() const {
5959 return false ;
6060 }
6161
62+ uint32_t mip_count = source_tex_vk.GetTextureDescriptor ().mip_count ;
63+
6264 // transition the source image to transfer source optimal
6365 TransitionImageLayoutCommandVK transition_source_cmd =
6466 TransitionImageLayoutCommandVK (source_image, vk::ImageLayout::eUndefined,
65- vk::ImageLayout::eTransferSrcOptimal);
67+ vk::ImageLayout::eTransferSrcOptimal,
68+ mip_count);
6669 bool success = transition_source_cmd.Submit (fenced_command_buffer);
6770 if (!success) {
6871 VALIDATION_LOG << " Failed to transition source image layout" ;
@@ -72,7 +75,8 @@ std::string BlitCopyTextureToTextureCommandVK::GetLabel() const {
7275 // transition the destination image to transfer destination optimal
7376 TransitionImageLayoutCommandVK transition_dest_cmd =
7477 TransitionImageLayoutCommandVK (dest_image, vk::ImageLayout::eUndefined,
75- vk::ImageLayout::eTransferDstOptimal);
78+ vk::ImageLayout::eTransferDstOptimal,
79+ mip_count);
7680 success = transition_dest_cmd.Submit (fenced_command_buffer);
7781 if (!success) {
7882 VALIDATION_LOG << " Failed to transition destination image layout" ;
@@ -127,10 +131,13 @@ std::string BlitCopyTextureToBufferCommandVK::GetLabel() const {
127131 image_copy.setImageExtent (
128132 vk::Extent3D (source_region.size .width , source_region.size .height , 1 ));
129133
134+ uint32_t mip_count = source_tex_vk.GetTextureDescriptor ().mip_count ;
135+
130136 // transition the source image to transfer source optimal
131137 TransitionImageLayoutCommandVK transition_source_cmd =
132138 TransitionImageLayoutCommandVK (source_image, vk::ImageLayout::eUndefined,
133- vk::ImageLayout::eTransferSrcOptimal);
139+ vk::ImageLayout::eTransferSrcOptimal,
140+ mip_count);
134141 bool success = transition_source_cmd.Submit (fenced_command_buffer);
135142 if (!success) {
136143 return false ;
@@ -171,9 +178,102 @@ std::string BlitGenerateMipmapCommandVK::GetLabel() const {
171178
172179[[nodiscard]] bool BlitGenerateMipmapCommandVK::Encode (
173180 FencedCommandBufferVK* fenced_command_buffer) const {
174- // TODO(https://github.com/flutter/flutter/issues/120134): Support generating
175- // mipmaps on Vulkan.
176- IMPELLER_UNIMPLEMENTED;
181+ const auto & source_tex_vk = TextureVK::Cast (*texture);
182+ const auto source_image = source_tex_vk.GetImage ();
183+
184+ const auto size = source_tex_vk.GetTextureDescriptor ().size ;
185+ uint32_t mip_count = source_tex_vk.GetTextureDescriptor ().mip_count ;
186+
187+ uint32_t mip_width = size.width ;
188+ uint32_t mip_height = size.height ;
189+
190+ // create the subresource range
191+ vk::ImageSubresourceRange subresource_range{};
192+ subresource_range.setAspectMask (vk::ImageAspectFlagBits::eColor);
193+ subresource_range.setBaseArrayLayer (0 );
194+ subresource_range.setLayerCount (1 );
195+ subresource_range.setLevelCount (1 );
196+
197+ // create a barrier to transition the image to transfer source optimal
198+ vk::ImageMemoryBarrier barrier{};
199+ barrier.setImage (source_image);
200+ barrier.setSrcQueueFamilyIndex (VK_QUEUE_FAMILY_IGNORED);
201+ barrier.setDstQueueFamilyIndex (VK_QUEUE_FAMILY_IGNORED);
202+ barrier.setSubresourceRange (subresource_range);
203+
204+ auto gen_mip_cmd = fenced_command_buffer->GetSingleUseChild ();
205+
206+ for (uint32_t i = 1 ; i < mip_count; i++) {
207+ barrier.subresourceRange .baseMipLevel = i - 1 ;
208+ barrier.oldLayout = vk::ImageLayout::eUndefined;
209+ barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
210+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
211+ barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
212+
213+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
214+ vk::PipelineStageFlagBits::eTransfer, {},
215+ nullptr , nullptr , barrier);
216+
217+ vk::ImageBlit blit{};
218+
219+ // src
220+ blit.srcOffsets [0 ] = vk::Offset3D (0 , 0 , 0 );
221+ blit.srcOffsets [1 ] = vk::Offset3D (mip_width, mip_height, 1 );
222+ blit.srcSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
223+ blit.srcSubresource .mipLevel = i - 1 ;
224+ blit.srcSubresource .baseArrayLayer = 0 ;
225+ blit.srcSubresource .layerCount = 1 ;
226+
227+ // dst
228+ blit.dstOffsets [0 ] = vk::Offset3D (0 , 0 , 0 );
229+ blit.dstOffsets [1 ] = vk::Offset3D (mip_width > 1 ? mip_width / 2 : 1 ,
230+ mip_height > 1 ? mip_height / 2 : 1 , 1 );
231+ blit.dstSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
232+ blit.dstSubresource .mipLevel = i;
233+ blit.dstSubresource .baseArrayLayer = 0 ;
234+ blit.dstSubresource .layerCount = 1 ;
235+
236+ gen_mip_cmd.blitImage (source_image, vk::ImageLayout::eTransferSrcOptimal,
237+ source_image, vk::ImageLayout::eTransferDstOptimal,
238+ blit, vk::Filter::eLinear);
239+
240+ // transition the previous mip level to shader read only optimal
241+ barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
242+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
243+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
244+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
245+
246+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
247+ vk::PipelineStageFlagBits::eFragmentShader, {},
248+ nullptr , nullptr , barrier);
249+
250+ if (mip_width > 1 ) {
251+ mip_width /= 2 ;
252+ }
253+
254+ if (mip_height > 1 ) {
255+ mip_height /= 2 ;
256+ }
257+ }
258+
259+ // transition the last mip level to shader read only optimal
260+ barrier.subresourceRange .baseMipLevel = mip_count - 1 ;
261+ barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal;
262+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
263+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
264+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
265+
266+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
267+ vk::PipelineStageFlagBits::eFragmentShader, {},
268+ nullptr , nullptr , barrier);
269+
270+ // submit the command buffer
271+ auto res = gen_mip_cmd.end ();
272+ if (res != vk::Result::eSuccess) {
273+ VALIDATION_LOG << " Failed to end command buffer: " << vk::to_string (res);
274+ return false ;
275+ }
276+
177277 return true ;
178278}
179279
0 commit comments