Skip to content

Commit 586fe94

Browse files
Refactor composition preparation and batching
1 parent 5a1c4ed commit 586fe94

21 files changed

Lines changed: 1846 additions & 3119 deletions

src/ImageSharp.Drawing/Processing/Backends/CompositionScenePlanner.cs renamed to src/ImageSharp.Drawing.WebGPU/CompositionBatchPlanner.cs

Lines changed: 16 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
namespace SixLabors.ImageSharp.Drawing.Processing.Backends;
88

99
/// <summary>
10-
/// Converts scene command streams into backend-ready prepared batches.
10+
/// Converts scene command streams into contiguous prepared batches for the WebGPU backend.
1111
/// </summary>
12-
public static class CompositionScenePlanner
12+
public static class CompositionBatchPlanner
1313
{
1414
/// <summary>
1515
/// Creates contiguous prepared batches grouped by coverage definition key.
@@ -40,7 +40,7 @@ public static List<CompositionBatch> CreatePreparedBatches(
4040
for (int index = runStart; index < runEnd; index++)
4141
{
4242
CompositionCommand command = commands[index];
43-
if (TryPrepareCommand(in command, in targetBounds, out PreparedCompositionCommand prepared))
43+
if (CompositionCommandPreparer.TryPrepareCommand(in command, in targetBounds, out PreparedCompositionCommand prepared))
4444
{
4545
preparedCommands.Add(prepared);
4646
}
@@ -66,29 +66,6 @@ public static List<CompositionBatch> CreatePreparedBatches(
6666
return batches;
6767
}
6868

69-
/// <summary>
70-
/// Estimates initial capacity for the outer batch list from total scene command count.
71-
/// </summary>
72-
/// <param name="commandCount">Total number of scene commands.</param>
73-
/// <returns>Suggested initial capacity for the batch list.</returns>
74-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
75-
private static int EstimateBatchCapacity(int commandCount)
76-
{
77-
// Typical scenes reuse coverage definitions, so batch count is usually
78-
// meaningfully lower than command count.
79-
if (commandCount <= 8)
80-
{
81-
return commandCount;
82-
}
83-
84-
if (commandCount <= 128)
85-
{
86-
return commandCount / 2;
87-
}
88-
89-
return commandCount / 4;
90-
}
91-
9269
/// <summary>
9370
/// Re-prepares batch commands after stroke expansion so destination regions
9471
/// and source offsets match the actual outline interest.
@@ -147,49 +124,23 @@ public static void ReprepareBatchCommands(
147124
}
148125

149126
/// <summary>
150-
/// Clips one scene command to target bounds and computes coverage source offset mapping.
127+
/// Estimates initial capacity for the outer batch list from total scene command count.
151128
/// </summary>
152-
/// <param name="command">The source command.</param>
153-
/// <param name="targetBounds">Target frame bounds in absolute coordinates.</param>
154-
/// <param name="prepared">Prepared command when clipping produces visible output.</param>
155-
/// <returns><see langword="true"/> when the command has visible output in target bounds.</returns>
156-
public static bool TryPrepareCommand(
157-
in CompositionCommand command,
158-
in Rectangle targetBounds,
159-
out PreparedCompositionCommand prepared)
129+
/// <param name="commandCount">Total number of scene commands.</param>
130+
/// <returns>Suggested initial capacity for the batch list.</returns>
131+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
132+
private static int EstimateBatchCapacity(int commandCount)
160133
{
161-
Rectangle interest = command.RasterizerOptions.Interest;
162-
Rectangle commandDestination = new(
163-
command.DestinationOffset.X + interest.X,
164-
command.DestinationOffset.Y + interest.Y,
165-
interest.Width,
166-
interest.Height);
167-
168-
Rectangle clippedDestination = Rectangle.Intersect(targetBounds, commandDestination);
169-
if (clippedDestination.Width <= 0 || clippedDestination.Height <= 0)
134+
if (commandCount <= 8)
135+
{
136+
return commandCount;
137+
}
138+
139+
if (commandCount <= 128)
170140
{
171-
prepared = default;
172-
return false;
141+
return commandCount / 2;
173142
}
174143

175-
Rectangle destinationLocalRegion = new(
176-
clippedDestination.X - targetBounds.X,
177-
clippedDestination.Y - targetBounds.Y,
178-
clippedDestination.Width,
179-
clippedDestination.Height);
180-
181-
Point sourceOffset = new(
182-
clippedDestination.X - commandDestination.X,
183-
clippedDestination.Y - commandDestination.Y);
184-
185-
prepared = new PreparedCompositionCommand(
186-
destinationLocalRegion,
187-
sourceOffset,
188-
command.Brush,
189-
command.BrushBounds,
190-
command.GraphicsOptions,
191-
command.DestinationOffset);
192-
193-
return true;
144+
return commandCount / 4;
194145
}
195146
}

src/ImageSharp.Drawing.WebGPU/WEBGPU_BACKEND_PROCESS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ DrawingCanvasBatcher.Flush()
1212
-> TryGetCompositeTextureFormat<TPixel>
1313
-> AreAllCompositionBrushesSupported<TPixel>
1414
-> if unsupported: staging fallback (see Fallback Behavior)
15-
-> CompositionScenePlanner.CreatePreparedBatches(commands, targetBounds)
15+
-> CompositionBatchPlanner.CreatePreparedBatches(commands, targetBounds)
1616
-> clip each command to target bounds
1717
-> group contiguous commands by DefinitionKey
1818
-> keep prepared destination/source offsets

src/ImageSharp.Drawing.WebGPU/WebGPUDrawingBackend.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ public void FlushCompositions<TPixel>(
339339

340340
TextureFormat textureFormat = WebGPUTextureFormatMapper.ToSilk(formatId);
341341

342-
List<CompositionBatch> preparedBatches = CompositionScenePlanner.CreatePreparedBatches(
342+
List<CompositionBatch> preparedBatches = CompositionBatchPlanner.CreatePreparedBatches(
343343
compositionScene.Commands,
344344
target.Bounds);
345345
if (preparedBatches.Count == 0)

0 commit comments

Comments
 (0)