@@ -860,26 +860,36 @@ 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+ bool synchronous) {
865+ // Wrap the optional validity checks up in a lambda to simplify the various
866+ // callsites below
867+ auto completion_callback = [maybe_completion_callback](uint32_t skp_count) {
868+ if (maybe_completion_callback.has_value () &&
869+ maybe_completion_callback.value ()) {
870+ maybe_completion_callback.value ()(skp_count);
874871 }
875- return ;
876- }
872+ };
873+
874+ // We use this bizzare raw pointer to a smart pointer thing here because we
875+ // want to keep the surface alive until all gpu work is done and the
876+ // callbacks skia takes for this are function pointers so we are unable to
877+ // use a lambda that captures the smart pointer. We need two levels of
878+ // indirection because it needs to be the same across all invocations of the
879+ // raster task lambda from a single invocation of WarmupSkps, but be
880+ // different across different invocations of WarmupSkps (so we cant
881+ // statically initialialize it in the lambda itself). Basically the result
882+ // of a mashup of wierd call dynamics, multithreading, and lifecycle
883+ // management with C style Skia callbacks.
884+ std::unique_ptr<SurfaceProducerSurface>* skp_warmup_surface =
885+ new std::unique_ptr<SurfaceProducerSurface>(nullptr );
877886
878887 // tell concurrent task runner to deserialize all skps available from
879888 // the asset manager
880- concurrent_task_runner->PostTask ([raster_task_runner, skp_warmup_surface,
881- surface_producer, asset_manager, skp_names,
882- completion_callback]() {
889+ concurrent_task_runner->PostTask ([raster_task_runner, size,
890+ skp_warmup_surface, surface_producer,
891+ asset_manager, skp_names,
892+ completion_callback, synchronous]() {
883893 TRACE_DURATION (" flutter" , " DeserializeSkps" );
884894 std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
885895 if (skp_names) {
@@ -895,6 +905,13 @@ void Engine::WarmupSkps(
895905 skp_mappings = asset_manager->GetAsMappings (" .*\\ .skp$" , " shaders" );
896906 }
897907
908+ if (skp_mappings.size () == 0 ) {
909+ FML_LOG (WARNING)
910+ << " Engine::WarmupSkps got zero SKP mappings, returning early" ;
911+ completion_callback (0 );
912+ return ;
913+ }
914+
898915 size_t total_size = 0 ;
899916 for (auto & mapping : skp_mappings) {
900917 total_size += mapping->GetSize ();
@@ -920,20 +937,35 @@ void Engine::WarmupSkps(
920937
921938 // Tell raster task runner to warmup have the compositor
922939 // context warm up the newly deserialized picture
923- raster_task_runner->PostTask ([skp_warmup_surface, picture ,
940+ raster_task_runner->PostTask ([picture, skp_warmup_surface, size ,
924941 surface_producer, completion_callback, i,
925- count = skp_mappings.size ()] {
942+ count = skp_mappings.size (), synchronous ] {
926943 TRACE_DURATION (" flutter" , " WarmupSkp" );
927- skp_warmup_surface->GetSkiaSurface ()->getCanvas ()->drawPicture (picture);
944+ if (*skp_warmup_surface == nullptr ) {
945+ skp_warmup_surface->reset (
946+ surface_producer->ProduceOffscreenSurface (size).release ());
947+
948+ if (*skp_warmup_surface == nullptr ) {
949+ FML_LOG (ERROR) << " Failed to create offscreen warmup surface" ;
950+ // Tell client that zero shaders were warmed up because warmup
951+ // failed.
952+ completion_callback (0 );
953+ return ;
954+ }
955+ }
956+
957+ // Do the actual warmup
958+ (*skp_warmup_surface)
959+ ->GetSkiaSurface ()
960+ ->getCanvas ()
961+ ->drawPicture (picture);
928962
929963 if (i == count - 1 ) {
930964 // We call this here instead of inside fFinishedProc below because
931- // we want to unblock the dart animation code as soon as the raster
932- // thread is free to enque work, rather than waiting for the GPU work
933- // itself to finish.
934- if (completion_callback.has_value () && completion_callback.value ()) {
935- completion_callback.value ()(count);
936- }
965+ // we want to unblock the dart animation code as soon as the
966+ // raster thread is free to enque work, rather than waiting for
967+ // the GPU work itself to finish.
968+ completion_callback (count);
937969 }
938970
939971 if (surface_producer->gr_context ()) {
@@ -946,11 +978,12 @@ void Engine::WarmupSkps(
946978 struct GrFlushInfo flush_info;
947979 flush_info.fFinishedContext = skp_warmup_surface;
948980 flush_info.fFinishedProc = [](void * skp_warmup_surface) {
949- delete static_cast <SurfaceProducerSurface*>(skp_warmup_surface);
981+ delete static_cast <std::unique_ptr<SurfaceProducerSurface>*>(
982+ skp_warmup_surface);
950983 };
951984
952985 surface_producer->gr_context ()->flush (flush_info);
953- surface_producer->gr_context ()->submit ();
986+ surface_producer->gr_context ()->submit (synchronous );
954987 }
955988 } else {
956989 if (i == count - 1 ) {
0 commit comments