@@ -72,26 +72,6 @@ public sealed class DrawingCanvas<TPixel> : DrawingCanvas
7272 /// </summary>
7373 private readonly DrawingTextCache textCache ;
7474
75- /// <summary>
76- /// Reusable operation list handed to each text renderer. Hosted by the text cache because
77- /// canvases are per-frame objects; sharing the cache-owned list keeps its capacity across
78- /// frames instead of regrowing a fresh list of large operation structs per draw.
79- /// </summary>
80- private readonly List < DrawingOperation > textOperations ;
81-
82- /// <summary>
83- /// Reusable sort buffer for <see cref="DrawTextOperations"/>, hosted by the text cache for
84- /// the same reason as <see cref="textOperations"/>. Only pass and index pairs are sorted;
85- /// the operations themselves stay in place so the per-draw sort moves eight bytes per
86- /// entry instead of the full operation struct.
87- /// </summary>
88- private readonly List < ( byte RenderPass , int Sequence ) > textOperationSortBuffer ;
89-
90- /// <summary>
91- /// Reusable stack pairing the begin and end commands for nested text composite layers.
92- /// </summary>
93- private readonly List < DrawingCanvasLayer > textCompositeLayerStack ;
94-
9575 /// <summary>
9676 /// Initializes a new instance of the <see cref="DrawingCanvas{TPixel}"/> class.
9777 /// </summary>
@@ -303,9 +283,6 @@ private DrawingCanvas(
303283 this . targetFrame = targetFrame ;
304284 this . batcher = batcher ;
305285 this . textCache = textCache ;
306- this . textOperations = textCache . OperationScratch ;
307- this . textOperationSortBuffer = textCache . OperationSortScratch ;
308- this . textCompositeLayerStack = textCache . CompositeLayerScratch ;
309286 this . ownsBatcher = ownsBatcher ;
310287 this . ownsTextCache = ownsTextCache ;
311288 this . pendingImageResources = pendingImageResources ;
@@ -869,11 +846,11 @@ configuredOptions.VisibleBounds is null &&
869846 } ;
870847 }
871848
872- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , configuredPath , pen , brush , this . textCache , this . textOperations ) ;
849+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , configuredPath , pen , brush , this . textCache ) ;
873850 TextRenderer renderer = new ( glyphRenderer ) ;
874851 renderer . Render ( text , configuredOptions ) ;
875852
876- this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions ) ;
853+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , effectiveOptions ) ;
877854 }
878855
879856 /// <inheritdoc />
@@ -900,7 +877,7 @@ public override void DrawText(
900877 Matrix4x4 . CreateTranslation ( location . X , location . Y , 0 ) * effectiveOptions . Transform ,
901878 effectiveOptions . TextContrast ) ;
902879
903- using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . textCache , this . textOperations ) ;
880+ using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . textCache ) ;
904881 if ( TryGetVisibleTextBounds ( state , placedOptions . Transform , out FontRectangle visibleBounds ) )
905882 {
906883 textBlock . RenderTo ( glyphRenderer , wrappingLength , visibleBounds ) ;
@@ -910,7 +887,7 @@ public override void DrawText(
910887 textBlock . RenderTo ( glyphRenderer , wrappingLength ) ;
911888 }
912889
913- this . DrawTextOperations ( glyphRenderer . DrawingOperations , placedOptions ) ;
890+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , placedOptions ) ;
914891 }
915892
916893 /// <inheritdoc />
@@ -929,10 +906,10 @@ public override void DrawText(
929906 DrawingCanvasState state = this . ResolveState ( ) ;
930907 DrawingOptions effectiveOptions = state . Options ;
931908
932- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . textCache , this . textOperations ) ;
909+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . textCache ) ;
933910 textBlock . RenderTo ( glyphRenderer , wrappingLength ) ;
934911
935- this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions ) ;
912+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , effectiveOptions ) ;
936913 }
937914
938915 /// <inheritdoc />
@@ -958,10 +935,10 @@ public override void DrawText(
958935 Matrix4x4 . CreateTranslation ( location . X , location . Y , 0 ) * effectiveOptions . Transform ,
959936 effectiveOptions . TextContrast ) ;
960937
961- using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . textCache , this . textOperations ) ;
938+ using RichTextGlyphRenderer glyphRenderer = new ( placedOptions , path : null , pen , brush , this . textCache ) ;
962939 lineLayout . RenderTo ( glyphRenderer ) ;
963940
964- this . DrawTextOperations ( glyphRenderer . DrawingOperations , placedOptions ) ;
941+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , placedOptions ) ;
965942 }
966943
967944 /// <inheritdoc />
@@ -979,10 +956,10 @@ public override void DrawText(
979956 DrawingCanvasState state = this . ResolveState ( ) ;
980957 DrawingOptions effectiveOptions = state . Options ;
981958
982- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . textCache , this . textOperations ) ;
959+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path , pen , brush , this . textCache ) ;
983960 lineLayout . RenderTo ( glyphRenderer ) ;
984961
985- this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions ) ;
962+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , effectiveOptions ) ;
986963 }
987964
988965 /// <inheritdoc />
@@ -999,11 +976,11 @@ public override void DrawText(
999976 DrawingCanvasState state = this . ResolveState ( ) ;
1000977 DrawingOptions effectiveOptions = state . Options ;
1001978
1002- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path : null , pen , brush , this . textCache , this . textOperations ) ;
979+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path : null , pen , brush , this . textCache ) ;
1003980 TextRenderer renderer = new ( glyphRenderer ) ;
1004981 renderer . Render ( glyphId , options ) ;
1005982
1006- this . DrawTextOperations ( glyphRenderer . DrawingOperations , effectiveOptions ) ;
983+ this . DrawTextOperations ( glyphRenderer . DrawingOperations , glyphRenderer . Scratch , effectiveOptions ) ;
1007984 }
1008985
1009986 /// <inheritdoc />
@@ -1023,11 +1000,11 @@ public override void DrawText(ReadOnlySpan<ushort> glyphIds, ReadOnlySpan<Vector
10231000 DrawingCanvasState state = this . ResolveState ( ) ;
10241001 DrawingOptions effectiveOptions = state . Options ;
10251002
1026- using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path : null , pen , brush , this . textCache , this . textOperations ) ;
1003+ using RichTextGlyphRenderer glyphRenderer = new ( effectiveOptions , path : null , pen , brush , this . textCache ) ;
10271004 TextRenderer renderer = new ( glyphRenderer ) ;
10281005 renderer . Render ( glyphIds , points , options ) ;
10291006
1030- this . DrawTextOperations ( this . BatchGlyphRunOperations ( glyphRenderer . DrawingOperations ) , effectiveOptions ) ;
1007+ this . DrawTextOperations ( this . BatchGlyphRunOperations ( glyphRenderer . DrawingOperations ) , glyphRenderer . Scratch , effectiveOptions ) ;
10311008 }
10321009
10331010 /// <inheritdoc />
@@ -1801,17 +1778,20 @@ private static IPath GetPositionedGlyphPath(DrawingTextCache.RunPathCacheEntry e
18011778 /// Converts rendered text operations to composition commands and submits them to the batcher.
18021779 /// </summary>
18031780 /// <param name="operations">Text drawing operations produced by glyph layout/rendering.</param>
1781+ /// <param name="scratch">The working buffers leased by this draw's renderer.</param>
18041782 /// <param name="drawingOptions">Drawing options applied to each operation.</param>
1805- private void DrawTextOperations ( List < DrawingOperation > operations , DrawingOptions drawingOptions )
1783+ private void DrawTextOperations (
1784+ List < DrawingOperation > operations ,
1785+ DrawingTextCache . DrawingScratch scratch ,
1786+ DrawingOptions drawingOptions )
18061787 {
18071788 // Enforce render-pass ordering while preserving original emission order inside each
18081789 // pass. This preserves overlapping color-font layer compositing semantics (for
18091790 // example emoji mouth/teeth layers) and keeps the composite group markers paired
18101791 // with the fill operations they contain.
1811- // The cache-owned buffer keeps its capacity across draws; draw calls never overlap on
1812- // one canvas.
1813- List < ( byte RenderPass , int Sequence ) > entries = this . textOperationSortBuffer ;
1814- entries . Clear ( ) ;
1792+ // The renderer leases these buffers until command submission completes. Other canvases
1793+ // sharing the cache rent different buffers, while sequential draws retain capacity.
1794+ List < ( byte RenderPass , int Sequence ) > entries = scratch . SortBuffer ;
18151795
18161796 // Queued glyph commands never carry the canvas transform: glyph geometry arrives with
18171797 // it already applied, and the sub-pixel remainder rides the command itself. One shared
@@ -1832,8 +1812,7 @@ private void DrawTextOperations(List<DrawingOperation> operations, DrawingOption
18321812 return cmp != 0 ? cmp : a . Sequence . CompareTo ( b . Sequence ) ;
18331813 } ) ;
18341814
1835- List < DrawingCanvasLayer > compositeLayers = this . textCompositeLayerStack ;
1836- compositeLayers . Clear ( ) ;
1815+ List < DrawingCanvasLayer > compositeLayers = scratch . CompositeLayers ;
18371816 DrawingCanvasState state = this . ResolveState ( ) ;
18381817
18391818 for ( int i = 0 ; i < entries . Count ; i ++ )
@@ -1879,11 +1858,6 @@ private void DrawTextOperations(List<DrawingOperation> operations, DrawingOption
18791858 this . batcher . AddStrokePath ( ( ( StrokePathCompositionSceneCommand ) command ) . Command ) ;
18801859 }
18811860 }
1882-
1883- // The buffers outlive the canvas (the text cache hosts them), so drop the layer
1884- // references now rather than rooting the final draw's state until the next draw.
1885- entries . Clear ( ) ;
1886- compositeLayers . Clear ( ) ;
18871861 }
18881862
18891863 /// <summary>
0 commit comments