@@ -860,26 +860,36 @@ void Engine::WarmupSkps(
860
860
SkISize size,
861
861
std::shared_ptr<flutter::AssetManager> asset_manager,
862
862
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);
874
871
}
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 );
877
886
878
887
// tell concurrent task runner to deserialize all skps available from
879
888
// 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]() {
883
893
TRACE_DURATION (" flutter" , " DeserializeSkps" );
884
894
std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
885
895
if (skp_names) {
@@ -895,6 +905,13 @@ void Engine::WarmupSkps(
895
905
skp_mappings = asset_manager->GetAsMappings (" .*\\ .skp$" , " shaders" );
896
906
}
897
907
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
+
898
915
size_t total_size = 0 ;
899
916
for (auto & mapping : skp_mappings) {
900
917
total_size += mapping->GetSize ();
@@ -920,20 +937,35 @@ void Engine::WarmupSkps(
920
937
921
938
// Tell raster task runner to warmup have the compositor
922
939
// 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 ,
924
941
surface_producer, completion_callback, i,
925
- count = skp_mappings.size ()] {
942
+ count = skp_mappings.size (), synchronous ] {
926
943
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);
928
962
929
963
if (i == count - 1 ) {
930
964
// 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);
937
969
}
938
970
939
971
if (surface_producer->gr_context ()) {
@@ -946,11 +978,12 @@ void Engine::WarmupSkps(
946
978
struct GrFlushInfo flush_info;
947
979
flush_info.fFinishedContext = skp_warmup_surface;
948
980
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);
950
983
};
951
984
952
985
surface_producer->gr_context ()->flush (flush_info);
953
- surface_producer->gr_context ()->submit ();
986
+ surface_producer->gr_context ()->submit (synchronous );
954
987
}
955
988
} else {
956
989
if (i == count - 1 ) {
0 commit comments