5#include "flutter/lib/ui/painting/multi_frame_codec.h"
9#include "flutter/fml/make_copyable.h"
10#include "flutter/lib/ui/painting/display_list_image_gpu.h"
11#include "flutter/lib/ui/painting/image.h"
12#if IMPELLER_SUPPORTS_RENDERING
13#include "flutter/lib/ui/painting/image_decoder_impeller.h"
15#include "third_party/dart/runtime/include/dart_api.h"
25 : state_(new
State(
std::move(generator))) {}
30 : generator_(
std::move(generator)),
31 frameCount_(generator_->GetFrameCount()),
32 repetitionCount_(generator_->GetPlayCount() ==
35 : generator_->GetPlayCount() - 1),
36 is_impeller_enabled_(
UIDartState::Current()->IsImpellerEnabled()) {}
41 const std::string& decode_error,
42 std::unique_ptr<tonic::DartPersistentValue>
callback,
44 std::shared_ptr<tonic::DartState> dart_state =
callback->dart_state().lock();
46 FML_DLOG(
ERROR) <<
"Could not acquire Dart state while attempting to fire "
47 "next frame callback.";
52 {tonic::ToDart(image), tonic::ToDart(duration),
53 tonic::ToDart(decode_error)});
56std::pair<sk_sp<DlImage>, std::string>
57MultiFrameCodec::State::GetNextFrameImage(
59 const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
60 const std::shared_ptr<impeller::Context>& impeller_context,
63 SkImageInfo info = generator_->GetInfo().makeColorType(kN32_SkColorType);
69 std::ostringstream ostr;
70 ostr <<
"Failed to allocate memory for bitmap of size "
71 <<
info.computeMinByteSize() <<
"B";
72 std::string decode_error = ostr.str();
74 return std::make_pair(
nullptr, decode_error);
77 ImageGenerator::FrameInfo frameInfo =
78 generator_->GetFrameInfo(nextFrameIndex_);
80 const int requiredFrameIndex =
87 if (!lastRequiredFrame_.has_value()) {
89 <<
"Frame " << nextFrameIndex_ <<
" depends on frame "
91 <<
" and no required frames are cached. Using blank slate instead.";
95 bitmap.writePixels(lastRequiredFrame_->pixmap());
96 if (restoreBGColorRect_.has_value()) {
105 nextFrameIndex_, requiredFrameIndex)) {
106 std::ostringstream ostr;
107 ostr <<
"Could not getPixels for frame " << nextFrameIndex_;
108 std::string decode_error = ostr.str();
110 return std::make_pair(
nullptr, decode_error);
113 const bool keep_current_frame =
115 const bool restore_previous_frame =
116 frameInfo.disposal_method ==
118 const bool previous_frame_available = lastRequiredFrame_.has_value();
130 if (keep_current_frame ||
131 (previous_frame_available && !restore_previous_frame)) {
134 lastRequiredFrame_ =
bitmap;
135 lastRequiredFrameIndex_ = nextFrameIndex_;
138 if (frameInfo.disposal_method ==
140 restoreBGColorRect_ = frameInfo.disposal_rect;
142 restoreBGColorRect_.reset();
145#if IMPELLER_SUPPORTS_RENDERING
146 if (is_impeller_enabled_) {
150 impeller_context, std::make_shared<SkBitmap>(
bitmap),
151 std::make_shared<fml::SyncSwitch>(),
159 gpu_disable_sync_switch->Execute(
161 .SetIfTrue([&skImage, &
bitmap] {
167 .SetIfFalse([&skImage, &resourceContext, &
bitmap] {
168 if (resourceContext) {
170 bitmap.pixelRef()->rowBytes());
172 resourceContext.
get(), pixmap,
true);
184 return std::make_pair(
nullptr,
"Unsupported backend.");
188void MultiFrameCodec::State::GetNextFrameAndInvokeCallback(
189 std::unique_ptr<tonic::DartPersistentValue>
callback,
193 const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
195 const std::shared_ptr<impeller::Context>& impeller_context) {
199 std::string decode_error;
200 std::tie(dlImage, decode_error) =
201 GetNextFrameImage(std::move(resourceContext), gpu_disable_sync_switch,
202 impeller_context, std::move(unref_queue));
205 image->set_image(dlImage);
206 ImageGenerator::FrameInfo frameInfo =
207 generator_->GetFrameInfo(nextFrameIndex_);
210 nextFrameIndex_ = (nextFrameIndex_ + 1) % frameCount_;
216 decode_error = std::move(decode_error),
duration, trace_id]()
mutable {
223 static size_t trace_counter = 1;
224 const size_t trace_id = trace_counter++;
232 const auto& task_runners = dart_state->GetTaskRunners();
234 if (state_->frameCount_ == 0) {
235 std::string decode_error(
"Could not provide any frame.");
238 [trace_id, decode_error = std::move(decode_error),
239 callback = std::make_unique<tonic::DartPersistentValue>(
248 [
callback = std::make_unique<tonic::DartPersistentValue>(
250 weak_state = std::weak_ptr<MultiFrameCodec::State>(state_), trace_id,
251 ui_task_runner = task_runners.GetUITaskRunner(),
252 io_manager = dart_state->GetIOManager()]()
mutable {
253 auto state = weak_state.lock();
255 ui_task_runner->PostTask(fml::MakeCopyable(
256 [callback = std::move(callback)]() { callback->Clear(); }));
259 state->GetNextFrameAndInvokeCallback(
260 std::move(
callback), ui_task_runner,
261 io_manager->GetResourceContext(), io_manager->GetSkiaUnrefQueue(),
262 io_manager->GetIsGpuDisabledSyncSwitch(), trace_id,
263 io_manager->GetImpellerContext());
272int MultiFrameCodec::frameCount()
const {
273 return state_->frameCount_;
276int MultiFrameCodec::repetitionCount()
const {
277 return state_->repetitionCount_;
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
constexpr SkColor SK_ColorTRANSPARENT
static constexpr int kNoFrame
static fml::RefPtr< CanvasImage > Create()
static sk_sp< DlImageGPU > Make(SkiaGPUObject< SkImage > image)
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToStorage(const std::shared_ptr< impeller::Context > &context, std::shared_ptr< SkBitmap > bitmap, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch, impeller::StorageMode storage_mode, bool create_mips=true)
Create a host visible texture from the provided bitmap.
The minimal interface necessary for defining a decoder that can be used for both single and multi-fra...
~MultiFrameCodec() override
MultiFrameCodec(std::shared_ptr< ImageGenerator > generator)
Dart_Handle getNextFrame(Dart_Handle args) override
static UIDartState * Current()
virtual void PostTask(const fml::closure &task) override
static DartState * Current()
struct _Dart_Handle * Dart_Handle
DART_EXPORT Dart_Handle Dart_Null(void)
DART_EXPORT bool Dart_IsClosure(Dart_Handle object)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_DLOG(severity)
#define FML_LOG(severity)
SK_API sk_sp< SkImage > CrossContextTextureFromPixmap(GrDirectContext *context, const SkPixmap &pixmap, bool buildMips, bool limitToMaxTextureSize=false)
SK_API sk_sp< SkImage > RasterFromBitmap(const SkBitmap &bitmap)
sk_sp< const SkImage > image
static void InvokeNextFrameCallback(const fml::RefPtr< CanvasImage > &image, int duration, const std::string &decode_error, std::unique_ptr< tonic::DartPersistentValue > callback, size_t trace_id)
internal::CopyableLambda< T > MakeCopyable(T lambda)
Dart_Handle ToDart(const T &object)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Represents the 2 code paths available when calling |SyncSwitch::Execute|.