@@ -860,25 +860,34 @@ void Engine::WarmupSkps(
860860 SkISize size,
861861 std::shared_ptr<flutter::AssetManager> asset_manager,
862862 std::optional<const std::vector<std::string>> skp_names,
863- std::optional<std::function<void (uint32_t )>> completion_callback) {
864- // We use a raw pointer here because we want to keep this alive until all gpu
865- // work is done and the callbacks skia takes for this are function pointers
866- // so we are unable to use a lambda that captures the smart pointer.
867- SurfaceProducerSurface* skp_warmup_surface =
868- surface_producer->ProduceOffscreenSurface (size).release ();
869- if (!skp_warmup_surface) {
870- FML_LOG (ERROR) << " Failed to create offscreen warmup surface" ;
871- // Tell client that zero shaders were warmed up because warmup failed.
872- if (completion_callback.has_value () && completion_callback.value ()) {
873- completion_callback.value ()(0 );
863+ std::optional<std::function<void (uint32_t )>> maybe_completion_callback) {
864+ // Wrap the optional validity checks up in a lambda to simplify the various
865+ // callsites below
866+ auto completion_callback = [maybe_completion_callback](uint32_t skp_count) {
867+ if (maybe_completion_callback.has_value () &&
868+ maybe_completion_callback.value ()) {
869+ maybe_completion_callback.value ()(skp_count);
874870 }
875- return ;
876- }
871+ };
872+
873+ // We use this bizzare raw pointer to a smart pointer thing here because we
874+ // want to keep the surface alive until all gpu work is done and the
875+ // callbacks skia takes for this are function pointers so we are unable to
876+ // use a lambda that captures the smart pointer. We need two levels of
877+ // indirection because it needs to be the same across all invocations of the
878+ // raster task lambda from a single invocation of WarmupSkps, but be
879+ // different across different invocations of WarmupSkps (so we cant
880+ // statically initialialize it in the lambda itself). Basically the result
881+ // of a mashup of wierd call dynamics, multithreading, and lifecycle
882+ // management with C style Skia callbacks.
883+ std::unique_ptr<SurfaceProducerSurface>* skp_warmup_surface =
884+ new std::unique_ptr<SurfaceProducerSurface>(nullptr );
877885
878886 // tell concurrent task runner to deserialize all skps available from
879887 // the asset manager
880- concurrent_task_runner->PostTask ([raster_task_runner, skp_warmup_surface,
881- surface_producer, asset_manager, skp_names,
888+ concurrent_task_runner->PostTask ([raster_task_runner, size,
889+ skp_warmup_surface, surface_producer,
890+ asset_manager, skp_names,
882891 completion_callback]() {
883892 TRACE_DURATION (" flutter" , " DeserializeSkps" );
884893 std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
@@ -895,6 +904,13 @@ void Engine::WarmupSkps(
895904 skp_mappings = asset_manager->GetAsMappings (" .*\\ .skp$" , " shaders" );
896905 }
897906
907+ if (skp_mappings.size () == 0 ) {
908+ FML_LOG (WARNING)
909+ << " Engine::WarmupSkps got zero SKP mappings, returning early" ;
910+ completion_callback (0 );
911+ return ;
912+ }
913+
898914 size_t total_size = 0 ;
899915 for (auto & mapping : skp_mappings) {
900916 total_size += mapping->GetSize ();
@@ -920,20 +936,35 @@ void Engine::WarmupSkps(
920936
921937 // Tell raster task runner to warmup have the compositor
922938 // context warm up the newly deserialized picture
923- raster_task_runner->PostTask ([skp_warmup_surface, picture ,
939+ raster_task_runner->PostTask ([picture, skp_warmup_surface, size ,
924940 surface_producer, completion_callback, i,
925941 count = skp_mappings.size ()] {
926942 TRACE_DURATION (" flutter" , " WarmupSkp" );
927- skp_warmup_surface->GetSkiaSurface ()->getCanvas ()->drawPicture (picture);
943+ if (*skp_warmup_surface == nullptr ) {
944+ skp_warmup_surface->reset (
945+ surface_producer->ProduceOffscreenSurface (size).release ());
946+
947+ if (*skp_warmup_surface == nullptr ) {
948+ FML_LOG (ERROR) << " Failed to create offscreen warmup surface" ;
949+ // Tell client that zero shaders were warmed up because warmup
950+ // failed.
951+ completion_callback (0 );
952+ return ;
953+ }
954+ }
955+
956+ // Do the actual warmup
957+ (*skp_warmup_surface)
958+ ->GetSkiaSurface ()
959+ ->getCanvas ()
960+ ->drawPicture (picture);
928961
929962 if (i == count - 1 ) {
930963 // We call this here instead of inside fFinishedProc below because
931964 // we want to unblock the dart animation code as soon as the raster
932965 // thread is free to enque work, rather than waiting for the GPU work
933966 // itself to finish.
934- if (completion_callback.has_value () && completion_callback.value ()) {
935- completion_callback.value ()(count);
936- }
967+ completion_callback (count);
937968 }
938969
939970 if (surface_producer->gr_context ()) {
0 commit comments