[Impeller] use device private on non-iOS devices. (#164601)

Redo of https://github.com/flutter/flutter/pull/164573

Fixes https://github.com/flutter/flutter/issues/136365
Fixes https://github.com/flutter/flutter/issues/134399

We should avoid using "host visible" textures outside of iOS, which
besides arm macs, is the only place they are supported. Deletes a test
that was completely invalid because it was testing a feature "the gpu
sync switch aka iOS background check" that was never used in mutli_frame
image codecs.
This commit is contained in:
Jonah Williams 2025-03-05 16:32:20 -08:00 committed by GitHub
parent 27030bb245
commit 80913c3389
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 33 additions and 170 deletions

View File

@ -405,7 +405,7 @@ void ImageDecoderImpeller::UploadTextureToPrivate(
const SkImageInfo& image_info,
const std::shared_ptr<SkBitmap>& bitmap,
const std::optional<SkImageInfo>& resize_info,
const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) {
const std::shared_ptr<const fml::SyncSwitch>& gpu_disabled_switch) {
TRACE_EVENT0("impeller", __FUNCTION__);
if (!context) {
result(nullptr, "No Impeller context is available");

View File

@ -88,7 +88,7 @@ class ImageDecoderImpeller final : public ImageDecoder {
const SkImageInfo& image_info,
const std::shared_ptr<SkBitmap>& bitmap,
const std::optional<SkImageInfo>& resize_info,
const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch);
const std::shared_ptr<const fml::SyncSwitch>& gpu_disabled_switch);
/// @brief Create a texture from the provided bitmap.
/// @param context The Impeller graphics context.

View File

@ -385,6 +385,9 @@ TEST_F(ImageDecoderFixtureTest, ImpellerUploadToSharedNoGpu) {
ASSERT_EQ(no_gpu_access_context->command_buffer_count_, 0ul);
ASSERT_EQ(result.second, "");
EXPECT_EQ(no_gpu_access_context->DidDisposeResources(), true);
EXPECT_EQ(
result.first->impeller_texture()->GetTextureDescriptor().storage_mode,
impeller::StorageMode::kHostVisible);
no_gpu_access_context->FlushTasks(/*fail=*/true);
}
@ -1007,174 +1010,6 @@ TEST_F(ImageDecoderFixtureTest,
PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
}
TEST_F(ImageDecoderFixtureTest, MultiFrameCodecDidAccessGpuDisabledSyncSwitch) {
auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
auto vm_data = vm_ref.GetVMData();
auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
ASSERT_TRUE(gif_mapping);
ImageGeneratorRegistry registry;
std::shared_ptr<ImageGenerator> gif_generator =
registry.CreateCompatibleGenerator(gif_mapping);
ASSERT_TRUE(gif_generator);
TaskRunners runners(GetCurrentTestName(), // label
CreateNewThread("platform"), // platform
CreateNewThread("raster"), // raster
CreateNewThread("ui"), // ui
CreateNewThread("io") // io
);
std::unique_ptr<TestIOManager> io_manager;
fml::RefPtr<MultiFrameCodec> codec;
fml::AutoResetWaitableEvent latch;
auto validate_frame_callback = [&latch](Dart_NativeArguments args) {
EXPECT_FALSE(Dart_IsNull(Dart_GetNativeArgument(args, 0)));
latch.Signal();
};
AddNativeCallback("ValidateFrameCallback",
CREATE_NATIVE_ENTRY(validate_frame_callback));
// Setup the IO manager.
PostTaskSync(runners.GetIOTaskRunner(), [&]() {
io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
});
auto isolate = RunDartCodeInIsolate(vm_ref, settings, runners, "main", {},
GetDefaultKernelFilePath(),
io_manager->GetWeakIOManager());
PostTaskSync(runners.GetUITaskRunner(), [&]() {
fml::AutoResetWaitableEvent isolate_latch;
EXPECT_TRUE(isolate->RunInIsolateScope([&]() -> bool {
Dart_Handle library = Dart_RootLibrary();
if (Dart_IsError(library)) {
isolate_latch.Signal();
return false;
}
Dart_Handle closure =
Dart_GetField(library, Dart_NewStringFromCString("frameCallback"));
if (Dart_IsError(closure) || !Dart_IsClosure(closure)) {
isolate_latch.Signal();
return false;
}
EXPECT_FALSE(io_manager->did_access_is_gpu_disabled_sync_switch_);
codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(gif_generator));
codec->getNextFrame(closure);
isolate_latch.Signal();
return true;
}));
isolate_latch.Wait();
});
PostTaskSync(runners.GetIOTaskRunner(), [&]() {
EXPECT_TRUE(io_manager->did_access_is_gpu_disabled_sync_switch_);
});
latch.Wait();
// Destroy the Isolate
isolate = nullptr;
// Destroy the MultiFrameCodec
PostTaskSync(runners.GetUITaskRunner(), [&]() { codec = nullptr; });
// Destroy the IO manager
PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
}
TEST_F(ImageDecoderFixtureTest, MultiFrameCodecIsPausedWhenGPUIsUnavailable) {
auto settings = CreateSettingsForFixture();
settings.enable_impeller = true;
auto vm_ref = DartVMRef::Create(settings);
auto vm_data = vm_ref.GetVMData();
auto gif_mapping = flutter::testing::OpenFixtureAsSkData("hello_loop_2.gif");
ASSERT_TRUE(gif_mapping);
ImageGeneratorRegistry registry;
std::shared_ptr<ImageGenerator> gif_generator =
registry.CreateCompatibleGenerator(gif_mapping);
ASSERT_TRUE(gif_generator);
TaskRunners runners(GetCurrentTestName(), // label
CreateNewThread("platform"), // platform
CreateNewThread("raster"), // raster
CreateNewThread("ui"), // ui
CreateNewThread("io") // io
);
std::unique_ptr<TestIOManager> io_manager;
fml::RefPtr<MultiFrameCodec> codec;
fml::AutoResetWaitableEvent latch;
auto validate_frame_callback = [&latch](Dart_NativeArguments args) {
EXPECT_FALSE(Dart_IsNull(Dart_GetNativeArgument(args, 0)));
latch.Signal();
};
AddNativeCallback("ValidateFrameCallback",
CREATE_NATIVE_ENTRY(validate_frame_callback));
// Setup the IO manager.
PostTaskSync(runners.GetIOTaskRunner(), [&]() {
io_manager = std::make_unique<TestIOManager>(runners.GetIOTaskRunner());
// Mark GPU disabled.
io_manager->SetGpuDisabled(true);
});
auto isolate = RunDartCodeInIsolate(vm_ref, settings, runners, "main", {},
GetDefaultKernelFilePath(),
io_manager->GetWeakIOManager());
PostTaskSync(runners.GetUITaskRunner(), [&]() {
fml::AutoResetWaitableEvent isolate_latch;
EXPECT_TRUE(isolate->RunInIsolateScope([&]() -> bool {
Dart_Handle library = Dart_RootLibrary();
if (Dart_IsError(library)) {
isolate_latch.Signal();
return false;
}
Dart_Handle closure =
Dart_GetField(library, Dart_NewStringFromCString("frameCallback"));
if (Dart_IsError(closure) || !Dart_IsClosure(closure)) {
isolate_latch.Signal();
return false;
}
EXPECT_FALSE(io_manager->did_access_is_gpu_disabled_sync_switch_);
codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(gif_generator));
codec->getNextFrame(closure);
isolate_latch.Signal();
return true;
}));
isolate_latch.Wait();
});
PostTaskSync(runners.GetIOTaskRunner(), [&]() {
EXPECT_TRUE(io_manager->did_access_is_gpu_disabled_sync_switch_);
});
latch.Wait();
// Destroy the Isolate
isolate = nullptr;
// Destroy the MultiFrameCodec
PostTaskSync(runners.GetUITaskRunner(), [&]() { codec = nullptr; });
// Destroy the IO manager
PostTaskSync(runners.GetIOTaskRunner(), [&]() { io_manager.reset(); });
}
TEST_F(ImageDecoderFixtureTest, NullCheckBuffer) {
auto context = std::make_shared<impeller::TestImpellerContext>();
auto allocator = ImpellerAllocator(context->GetResourceAllocator());

View File

@ -6,10 +6,12 @@
#include <utility>
#include "display_list/image/dl_image.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/lib/ui/painting/display_list_image_gpu.h"
#include "flutter/lib/ui/painting/image.h"
#if IMPELLER_SUPPORTS_RENDERING
#include "flutter/impeller/renderer/context.h"
#include "flutter/lib/ui/painting/image_decoder_impeller.h"
#endif // IMPELLER_SUPPORTS_RENDERING
#include "third_party/dart/runtime/include/dart_api.h"
@ -144,10 +146,36 @@ MultiFrameCodec::State::GetNextFrameImage(
#if IMPELLER_SUPPORTS_RENDERING
if (is_impeller_enabled_) {
#ifdef FML_OS_IOS
// This is safe regardless of whether the GPU is available or not because
// without mipmap creation there is no command buffer encoding done.
return ImageDecoderImpeller::UploadTextureToStorage(
impeller_context, std::make_shared<SkBitmap>(bitmap));
#else
sk_sp<DlImage> dl_image;
std::string error_message;
auto mapping = std::make_unique<fml::NonOwnedMapping>(
reinterpret_cast<const uint8_t*>(bitmap.getAddr(0, 0)), // data
bitmap.dimensions().area() * info.bytesPerPixel(), // size
[bitmap](auto, auto) mutable { bitmap.reset(); } // proc
);
std::shared_ptr<impeller::DeviceBuffer> device_buffer =
impeller_context->GetResourceAllocator()->CreateBufferWithCopy(
*mapping);
if (!device_buffer) {
return std::make_pair(nullptr, "Failed to allocate staging buffer.");
}
ImageDecoderImpeller::UploadTextureToPrivate(
[&](sk_sp<DlImage> image, std::string message) {
dl_image = std::move(image);
error_message = std::move(message);
},
impeller_context, device_buffer, info,
std::make_shared<SkBitmap>(bitmap), std::nullopt,
gpu_disable_sync_switch);
return std::make_pair(dl_image, error_message);
#endif
}
#endif // IMPELLER_SUPPORTS_RENDERING