[Impeller] Use multiple command buffers for blur submission. (flutter/engine#54846)

Fixes https://github.com/flutter/flutter/issues/154046

Use three different command buffers when it would be   possible to combine the operations into a single buffer. From testing and user bug reports (see https://github.com/flutter/flutter/issues/154046 ), this sometimes causes deviceLost errors on older Adreno devices. Breaking  the work up into three different command buffers seems to prevent this crash.

I suspect this is due to some internal timeouts we may be hitting in the adreno driver.
This commit is contained in:
Jonah Williams 2024-08-28 18:23:31 -07:00 committed by GitHub
parent 355475444a
commit 4385a96ee1

View File

@ -727,9 +727,15 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
return result;
}
std::shared_ptr<CommandBuffer> command_buffer =
// Note: The code below uses three different command buffers when it would be
// possible to combine the operations into a single buffer. From testing and
// user bug reports (see https://github.com/flutter/flutter/issues/154046 ),
// this sometimes causes deviceLost errors on older Adreno devices. Breaking
// the work up into three different command buffers seems to prevent this
// crash.
std::shared_ptr<CommandBuffer> command_buffer_1 =
renderer.GetContext()->CreateCommandBuffer();
if (!command_buffer) {
if (!command_buffer_1) {
return std::nullopt;
}
@ -738,7 +744,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
source_expanded_coverage_hint, inputs[0], snapshot_entity);
fml::StatusOr<RenderTarget> pass1_out = MakeDownsampleSubpass(
renderer, command_buffer, input_snapshot->texture,
renderer, command_buffer_1, input_snapshot->texture,
input_snapshot->sampler_descriptor, downsample_pass_args, tile_mode_);
if (!pass1_out.ok()) {
@ -750,8 +756,14 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
Quad blur_uvs = {Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)};
std::shared_ptr<CommandBuffer> command_buffer_2 =
renderer.GetContext()->CreateCommandBuffer();
if (!command_buffer_2) {
return std::nullopt;
}
fml::StatusOr<RenderTarget> pass2_out = MakeBlurSubpass(
renderer, command_buffer, /*input_pass=*/pass1_out.value(),
renderer, command_buffer_2, /*input_pass=*/pass1_out.value(),
input_snapshot->sampler_descriptor, tile_mode_,
BlurParameters{
.blur_uv_offset = Point(0.0, pass1_pixel_size.y),
@ -767,6 +779,12 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
return std::nullopt;
}
std::shared_ptr<CommandBuffer> command_buffer_3 =
renderer.GetContext()->CreateCommandBuffer();
if (!command_buffer_3) {
return std::nullopt;
}
// Only ping pong if the first pass actually created a render target.
auto pass3_destination = pass2_out.value().GetRenderTargetTexture() !=
pass1_out.value().GetRenderTargetTexture()
@ -774,7 +792,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
: std::optional<RenderTarget>(std::nullopt);
fml::StatusOr<RenderTarget> pass3_out = MakeBlurSubpass(
renderer, command_buffer, /*input_pass=*/pass2_out.value(),
renderer, command_buffer_3, /*input_pass=*/pass2_out.value(),
input_snapshot->sampler_descriptor, tile_mode_,
BlurParameters{
.blur_uv_offset = Point(pass1_pixel_size.x, 0.0),
@ -792,7 +810,8 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
if (!renderer.GetContext()
->GetCommandQueue()
->Submit(/*buffers=*/{command_buffer})
->Submit(/*buffers=*/{command_buffer_1, command_buffer_2,
command_buffer_3})
.ok()) {
return std::nullopt;
}