@@ -162,13 +162,17 @@ public static bool TryCreateStagedScene<TPixel>(
162162
163163 try
164164 {
165+ System . Diagnostics . Stopwatch sw = System . Diagnostics . Stopwatch . StartNew ( ) ;
165166 if ( ! WebGPUSceneEncoder . TryEncode ( scene , flushContext . TargetBounds , flushContext . MemoryAllocator , out WebGPUEncodedScene createdScene , out error ) )
166167 {
167168 flushContext . Dispose ( ) ;
168169 stagedScene = default ;
169170 return false ;
170171 }
171172
173+ double encodeMs = sw . Elapsed . TotalMilliseconds ;
174+ sw . Restart ( ) ;
175+
172176 encodedScene = createdScene ;
173177 WebGPUSceneConfig config = WebGPUSceneConfig . Create ( encodedScene , bumpSizes ) ;
174178 uint baseColor = 0U ;
@@ -202,6 +206,9 @@ public static bool TryCreateStagedScene<TPixel>(
202206 return false ;
203207 }
204208
209+ double resourceMs = sw . Elapsed . TotalMilliseconds ;
210+ System . IO . File . AppendAllText ( "bump_debug.log" , $ "[TIMING] encode={ encodeMs : 0.000} ms resources={ resourceMs : 0.000} ms fills={ encodedScene . FillCount } paths={ encodedScene . PathCount } lines={ encodedScene . LineCount } \n ") ;
211+
205212 stagedScene = new WebGPUStagedScene ( flushContext , encodedScene , config , resources , segmentChunkingRequired ? bindingLimitFailure : BindingLimitFailure . None ) ;
206213 error = null ;
207214 return true ;
@@ -889,6 +896,8 @@ public static unsafe bool TryRenderStagedScene(
889896 return TryRenderSegmentChunkedStagedScene ( ref stagedScene , ref schedulingArena , out requiresGrowth , out grownBumpSizes , out error ) ;
890897 }
891898
899+ var sw = System . Diagnostics . Stopwatch . StartNew ( ) ;
900+
892901 if ( ! TryEnsureSchedulingArena (
893902 stagedScene . FlushContext ,
894903 stagedScene . Config . BufferSizes ,
@@ -899,31 +908,21 @@ public static unsafe bool TryRenderStagedScene(
899908 return false ;
900909 }
901910
911+ double arenaMs = sw . Elapsed . TotalMilliseconds ;
912+ sw . Restart ( ) ;
913+
902914 if ( ! TryDispatchSchedulingStages ( ref stagedScene , in schedulingArena , out WebGPUSceneSchedulingResources scheduling , out error ) )
903915 {
904916 return false ;
905917 }
906918
907- // Submit scheduling + readback copy so the GPU starts immediately.
908- // While the GPU runs scheduling, the CPU records the fine pass below.
909- if ( ! TryEnqueueSchedulingStatusReadback ( stagedScene . FlushContext , scheduling . BumpBuffer , schedulingArena . ReadbackBuffer , 0 , out error ) ||
910- ! WebGPUDrawingBackend . TrySubmit ( stagedScene . FlushContext ) )
911- {
912- return false ;
913- }
919+ double schedDispatchMs = sw . Elapsed . TotalMilliseconds ;
920+ sw . Restart ( ) ;
914921
915- // Record fine + output copy on a new command encoder while GPU runs scheduling.
916- // This CPU work overlaps with GPU scheduling execution.
917922 WebGPUFlushContext flushContext = stagedScene . FlushContext ;
918923 int targetWidth = encodedScene . TargetSize . Width ;
919924 int targetHeight = encodedScene . TargetSize . Height ;
920925
921- if ( ! flushContext . EnsureCommandEncoder ( ) )
922- {
923- error = "Failed to create a command encoder for the staged-scene fine pass." ;
924- return false ;
925- }
926-
927926 if ( ! WebGPUDrawingBackend . TryCreateCompositionTexture ( flushContext , targetWidth , targetHeight , out Texture * outputTexture , out TextureView * outputTextureView , out error ) )
928927 {
929928 return false ;
@@ -954,16 +953,24 @@ public static unsafe bool TryRenderStagedScene(
954953 targetWidth ,
955954 targetHeight ) ;
956955
957- // NOW sync-readback the scheduling bumps. By this point the GPU has been
958- // running scheduling while the CPU was recording fine above, so the map
959- // blocks for minimal time (scheduling is usually done or nearly done).
960- if ( ! TryReadSchedulingStatus ( flushContext , schedulingArena . ReadbackBuffer , out GpuSceneBumpAllocators bumpAllocators , out error ) )
956+ double fineDispatchMs = sw . Elapsed . TotalMilliseconds ;
957+ sw . Restart ( ) ;
958+
959+ // Single submit: scheduling + fine + copy + readback all in one.
960+ if ( ! TryEnqueueSchedulingStatusReadback ( flushContext , scheduling . BumpBuffer , schedulingArena . ReadbackBuffer , 0 , out error ) ||
961+ ! WebGPUDrawingBackend . TrySubmit ( flushContext ) ||
962+ ! TryReadSchedulingStatus ( flushContext , schedulingArena . ReadbackBuffer , out GpuSceneBumpAllocators bumpAllocators , out error ) )
961963 {
962964 return false ;
963965 }
964966
967+ double submitReadbackMs = sw . Elapsed . TotalMilliseconds ;
968+ System . IO . File . AppendAllText ( "bump_debug.log" , $ "[RENDER] arena={ arenaMs : 0.000} ms schedDispatch={ schedDispatchMs : 0.000} ms fineDispatch={ fineDispatchMs : 0.000} ms submitReadback={ submitReadbackMs : 0.000} ms\n ") ;
969+
965970 if ( RequiresScratchReallocation ( in bumpAllocators , stagedScene . Config . BumpSizes ) )
966971 {
972+ // Overflow detected. The fine output is garbage but all bump allocators
973+ // now report the actual sizes needed. One retry with these sizes will succeed.
967974 requiresGrowth = true ;
968975 grownBumpSizes = GrowBumpSizes ( stagedScene . Config . BumpSizes , in bumpAllocators ) ;
969976 WebGPUSceneBumpSizes cfg = stagedScene . Config . BumpSizes ;
@@ -972,15 +979,7 @@ public static unsafe bool TryRenderStagedScene(
972979 return false ;
973980 }
974981
975- if ( string . Equals ( Environment . GetEnvironmentVariable ( "IMAGE_SHARP_WEBGPU_DEBUG_SCHED" ) , "1" , StringComparison . Ordinal ) )
976- {
977- WebGPUEncodedScene debugScene = stagedScene . EncodedScene ;
978- error = $ "scene fills={ debugScene . FillCount } paths={ debugScene . PathCount } lines={ debugScene . LineCount } pathtag_bytes={ debugScene . PathTagByteCount } pathtag_words={ debugScene . PathTagWordCount } drawtags={ debugScene . DrawTagCount } drawdata={ debugScene . DrawDataWordCount } transforms={ debugScene . TransformWordCount } styles={ debugScene . StyleWordCount } ; sched failed={ bumpAllocators . Failed } binning={ bumpAllocators . Binning } ptcl={ bumpAllocators . Ptcl } tile={ bumpAllocators . Tile } seg_counts={ bumpAllocators . SegCounts } segments={ bumpAllocators . Segments } blend={ bumpAllocators . BlendSpill } lines={ bumpAllocators . Lines } ";
979- return false ;
980- }
981-
982- // Scheduling passed. Persist the actual GPU usage so the next flush starts
983- // from sizes that are known to work, eliminating retries for similar scenes.
982+ // Persist the actual GPU usage so the next flush starts from known-good sizes.
984983 grownBumpSizes = new WebGPUSceneBumpSizes (
985984 Math . Max ( bumpAllocators . Lines , stagedScene . Config . BumpSizes . Lines ) ,
986985 Math . Max ( bumpAllocators . Binning , stagedScene . Config . BumpSizes . Binning ) ,
@@ -990,8 +989,7 @@ public static unsafe bool TryRenderStagedScene(
990989 Math . Max ( bumpAllocators . BlendSpill , stagedScene . Config . BumpSizes . BlendSpill ) ,
991990 Math . Max ( bumpAllocators . Ptcl , stagedScene . Config . BumpSizes . Ptcl ) ) ;
992991
993- // Submit the pre-recorded fine + copy. Fire-and-forget.
994- return WebGPUDrawingBackend . TrySubmit ( flushContext ) ;
992+ return true ;
995993 }
996994
997995 /// <summary>
0 commit comments