@@ -669,9 +669,15 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
669669 return result;
670670 }
671671
672- std::shared_ptr<CommandBuffer> command_buffer =
672+ // Note: The code below uses three different command buffers when it would be
673+ // possible to combine the operations into a single buffer. From testing and
674+ // user bug reports (see https://github.com/flutter/flutter/issues/154046 ),
675+ // this sometimes causes deviceLost errors on older Adreno devices. Breaking
676+ // the work up into three different command buffers seems to prevent this
677+ // crash.
678+ std::shared_ptr<CommandBuffer> command_buffer_1 =
673679 renderer.GetContext ()->CreateCommandBuffer ();
674- if (!command_buffer ) {
680+ if (!command_buffer_1 ) {
675681 return std::nullopt ;
676682 }
677683
@@ -680,7 +686,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
680686 source_expanded_coverage_hint, inputs[0 ], snapshot_entity);
681687
682688 fml::StatusOr<RenderTarget> pass1_out = MakeDownsampleSubpass (
683- renderer, command_buffer , input_snapshot->texture ,
689+ renderer, command_buffer_1 , input_snapshot->texture ,
684690 input_snapshot->sampler_descriptor , downsample_pass_args, tile_mode_);
685691
686692 if (!pass1_out.ok ()) {
@@ -692,8 +698,14 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
692698
693699 Quad blur_uvs = {Point (0 , 0 ), Point (1 , 0 ), Point (0 , 1 ), Point (1 , 1 )};
694700
701+ std::shared_ptr<CommandBuffer> command_buffer_2 =
702+ renderer.GetContext ()->CreateCommandBuffer ();
703+ if (!command_buffer_2) {
704+ return std::nullopt ;
705+ }
706+
695707 fml::StatusOr<RenderTarget> pass2_out = MakeBlurSubpass (
696- renderer, command_buffer , /* input_pass=*/ pass1_out.value (),
708+ renderer, command_buffer_2 , /* input_pass=*/ pass1_out.value (),
697709 input_snapshot->sampler_descriptor , tile_mode_,
698710 BlurParameters{
699711 .blur_uv_offset = Point (0.0 , pass1_pixel_size.y ),
@@ -709,14 +721,20 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
709721 return std::nullopt ;
710722 }
711723
724+ std::shared_ptr<CommandBuffer> command_buffer_3 =
725+ renderer.GetContext ()->CreateCommandBuffer ();
726+ if (!command_buffer_3) {
727+ return std::nullopt ;
728+ }
729+
712730 // Only ping pong if the first pass actually created a render target.
713731 auto pass3_destination = pass2_out.value ().GetRenderTargetTexture () !=
714732 pass1_out.value ().GetRenderTargetTexture ()
715733 ? std::optional<RenderTarget>(pass1_out.value ())
716734 : std::optional<RenderTarget>(std::nullopt );
717735
718736 fml::StatusOr<RenderTarget> pass3_out = MakeBlurSubpass (
719- renderer, command_buffer , /* input_pass=*/ pass2_out.value (),
737+ renderer, command_buffer_3 , /* input_pass=*/ pass2_out.value (),
720738 input_snapshot->sampler_descriptor , tile_mode_,
721739 BlurParameters{
722740 .blur_uv_offset = Point (pass1_pixel_size.x , 0.0 ),
@@ -734,7 +752,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
734752
735753 if (!renderer.GetContext ()
736754 ->GetCommandQueue ()
737- ->Submit (/* buffers=*/ {command_buffer})
755+ ->Submit (/* buffers=*/ {command_buffer_1, command_buffer_2,
756+ command_buffer_3})
738757 .ok ()) {
739758 return std::nullopt ;
740759 }
0 commit comments