@@ -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,125 @@ 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->Get ();
205+
206+ vk::CommandBufferBeginInfo begin_info;
207+ begin_info.setFlags (vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
208+ auto begin_res = gen_mip_cmd.begin (begin_info);
209+
210+ if (begin_res != vk::Result::eSuccess) {
211+ VALIDATION_LOG << " Failed to begin command buffer: "
212+ << vk::to_string (begin_res);
213+ return false ;
214+ }
215+
216+ // transition all layers to transfer dst optimal
217+ for (uint32_t i = 0 ; i < mip_count; i++) {
218+ barrier.subresourceRange .baseMipLevel = i;
219+ barrier.oldLayout = vk::ImageLayout::eUndefined;
220+ barrier.newLayout = vk::ImageLayout::eTransferDstOptimal;
221+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
222+ barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
223+
224+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
225+ vk::PipelineStageFlagBits::eTransfer, {},
226+ nullptr , nullptr , barrier);
227+ }
228+
229+ for (uint32_t i = 1 ; i < mip_count; i++) {
230+ barrier.subresourceRange .baseMipLevel = i - 1 ;
231+ barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal;
232+ barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal;
233+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
234+ barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead;
235+
236+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
237+ vk::PipelineStageFlagBits::eTransfer, {},
238+ nullptr , nullptr , barrier);
239+
240+ vk::ImageBlit blit{};
241+
242+ // src
243+ blit.srcOffsets [0 ] = vk::Offset3D (0 , 0 , 0 );
244+ blit.srcOffsets [1 ] = vk::Offset3D (mip_width, mip_height, 1 );
245+ blit.srcSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
246+ blit.srcSubresource .mipLevel = i - 1 ;
247+ blit.srcSubresource .baseArrayLayer = 0 ;
248+ blit.srcSubresource .layerCount = 1 ;
249+
250+ // dst
251+ blit.dstOffsets [0 ] = vk::Offset3D (0 , 0 , 0 );
252+ blit.dstOffsets [1 ] = vk::Offset3D (mip_width > 1 ? mip_width / 2 : 1 ,
253+ mip_height > 1 ? mip_height / 2 : 1 , 1 );
254+ blit.dstSubresource .aspectMask = vk::ImageAspectFlagBits::eColor;
255+ blit.dstSubresource .mipLevel = i;
256+ blit.dstSubresource .baseArrayLayer = 0 ;
257+ blit.dstSubresource .layerCount = 1 ;
258+
259+ gen_mip_cmd.blitImage (source_image, vk::ImageLayout::eTransferSrcOptimal,
260+ source_image, vk::ImageLayout::eTransferDstOptimal,
261+ blit, vk::Filter::eLinear);
262+
263+ // transition the previous mip level to shader read only optimal
264+ barrier.oldLayout = vk::ImageLayout::eUndefined;
265+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
266+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
267+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
268+
269+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
270+ vk::PipelineStageFlagBits::eFragmentShader, {},
271+ nullptr , nullptr , barrier);
272+
273+ if (mip_width > 1 ) {
274+ mip_width /= 2 ;
275+ }
276+
277+ if (mip_height > 1 ) {
278+ mip_height /= 2 ;
279+ }
280+ }
281+
282+ // transition the last mip level to shader read only optimal
283+ barrier.subresourceRange .baseMipLevel = mip_count - 1 ;
284+ barrier.oldLayout = vk::ImageLayout::eUndefined;
285+ barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
286+ barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead;
287+ barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
288+
289+ gen_mip_cmd.pipelineBarrier (vk::PipelineStageFlagBits::eTransfer,
290+ vk::PipelineStageFlagBits::eFragmentShader, {},
291+ nullptr , nullptr , barrier);
292+
293+ // submit the command buffer
294+ auto res = gen_mip_cmd.end ();
295+ if (res != vk::Result::eSuccess) {
296+ VALIDATION_LOG << " Failed to end command buffer: " << vk::to_string (res);
297+ return false ;
298+ }
299+
177300 return true ;
178301}
179302
0 commit comments