@@ -727,9 +727,15 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
727727 return result;
728728 }
729729
730- std::shared_ptr<CommandBuffer> command_buffer =
730+ // Note: The code below uses three different command buffers when it would be
731+ // possible to combine the operations into a single buffer. From testing and
732+ // user bug reports (see https://github.com/flutter/flutter/issues/154046 ),
733+ // this sometimes causes deviceLost errors on older Adreno devices. Breaking
734+ // the work up into three different command buffers seems to prevent this
735+ // crash.
736+ std::shared_ptr<CommandBuffer> command_buffer_1 =
731737 renderer.GetContext ()->CreateCommandBuffer ();
732- if (!command_buffer ) {
738+ if (!command_buffer_1 ) {
733739 return std::nullopt ;
734740 }
735741
@@ -738,7 +744,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
738744 source_expanded_coverage_hint, inputs[0 ], snapshot_entity);
739745
740746 fml::StatusOr<RenderTarget> pass1_out = MakeDownsampleSubpass (
741- renderer, command_buffer , input_snapshot->texture ,
747+ renderer, command_buffer_1 , input_snapshot->texture ,
742748 input_snapshot->sampler_descriptor , downsample_pass_args, tile_mode_);
743749
744750 if (!pass1_out.ok ()) {
@@ -750,8 +756,14 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
750756
751757 Quad blur_uvs = {Point (0 , 0 ), Point (1 , 0 ), Point (0 , 1 ), Point (1 , 1 )};
752758
759+ std::shared_ptr<CommandBuffer> command_buffer_2 =
760+ renderer.GetContext ()->CreateCommandBuffer ();
761+ if (!command_buffer_2) {
762+ return std::nullopt ;
763+ }
764+
753765 fml::StatusOr<RenderTarget> pass2_out = MakeBlurSubpass (
754- renderer, command_buffer , /* input_pass=*/ pass1_out.value (),
766+ renderer, command_buffer_2 , /* input_pass=*/ pass1_out.value (),
755767 input_snapshot->sampler_descriptor , tile_mode_,
756768 BlurParameters{
757769 .blur_uv_offset = Point (0.0 , pass1_pixel_size.y ),
@@ -767,14 +779,20 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
767779 return std::nullopt ;
768780 }
769781
782+ std::shared_ptr<CommandBuffer> command_buffer_3 =
783+ renderer.GetContext ()->CreateCommandBuffer ();
784+ if (!command_buffer_3) {
785+ return std::nullopt ;
786+ }
787+
770788 // Only ping pong if the first pass actually created a render target.
771789 auto pass3_destination = pass2_out.value ().GetRenderTargetTexture () !=
772790 pass1_out.value ().GetRenderTargetTexture ()
773791 ? std::optional<RenderTarget>(pass1_out.value ())
774792 : std::optional<RenderTarget>(std::nullopt );
775793
776794 fml::StatusOr<RenderTarget> pass3_out = MakeBlurSubpass (
777- renderer, command_buffer , /* input_pass=*/ pass2_out.value (),
795+ renderer, command_buffer_3 , /* input_pass=*/ pass2_out.value (),
778796 input_snapshot->sampler_descriptor , tile_mode_,
779797 BlurParameters{
780798 .blur_uv_offset = Point (pass1_pixel_size.x , 0.0 ),
@@ -792,7 +810,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
792810
793811 if (!renderer.GetContext ()
794812 ->GetCommandQueue ()
795- ->Submit (/* buffers=*/ {command_buffer})
813+ ->Submit (/* buffers=*/ {command_buffer_1, command_buffer_2,
814+ command_buffer_3})
796815 .ok ()) {
797816 return std::nullopt ;
798817 }
0 commit comments