Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ImageSharp.Drawing.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,6 @@ Global
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{061582c2-658f-40ae-a978-7d74a4eb2c0a}*SharedItemsImports = 5
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{2e33181e-6e28-4662-a801-e2e7dc206029}*SharedItemsImports = 5
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{68a8cc40-6aed-4e96-b524-31b1158fdeea}*SharedItemsImports = 13
EndGlobalSection
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp.Drawing.WebGPU/GpuSceneDrawTag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static class GpuSceneDrawTag
{
// These values are not a plain enum because each word also encodes the path-count, clip-count,
// scene-word-count, and info-word-count increments consumed by the scan/reduction stages.
// Visible-fill tags carry five extra info words: coverage threshold plus raster interest. Must match drawtag.wgsl.
// Visible-fill tags carry five extra info words: coverage data plus raster interest. Must match drawtag.wgsl.
public const uint Nop = 0U;
public const uint FillColor = 0x188U;
public const uint FillRecolor = 0x184U;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@
<PackageReference Include="Silk.NET.Windowing.Sdl" Version="2.23.0" PrivateAssets="compile;build;analyzers;contentfiles;buildtransitive" />
</ItemGroup>

<Import Project="..\..\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems" Label="Shared" />

<ItemGroup>
<ProjectReference Include="..\ImageSharp.Drawing\ImageSharp.Drawing.csproj" />
<ProjectReference Include="..\ImageSharp.Drawing.WebGPU.ShaderGen\ImageSharp.Drawing.WebGPU.ShaderGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that initializes every per-path bounding box to an empty (inverted) box so
/// that flatten can accumulate extents with atomic min/max. Wraps <c>bbox_clear.wgsl</c>.
/// that path lowering can accumulate extents with atomic min/max. Wraps <c>bbox_clear.wgsl</c>.
/// </summary>
internal static unsafe class BboxClearComputeShader
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ public static unsafe bool TryCreateBindGroupLayout(
// 6 gradients (sampled gradient ramp texture)
// 7 image_atlas (sampled image atlas texture)
// 8 backdrop_texture (sampled existing target contents)
WGPUBindGroupLayoutEntry* entries = stackalloc WGPUBindGroupLayoutEntry[9];
// 9 scene_data (read-only profile ranges and contour links in the packed scene stream)
// 10 path_tiles (read-only neighboring segment-slice indices for aliased row halos)
WGPUBindGroupLayoutEntry* entries = stackalloc WGPUBindGroupLayoutEntry[11];
entries[0] = CreateUniformEntry(0, (nuint)sizeof(GpuSceneConfig));
entries[1] = CreateStorageEntry(1, WGPUBufferBindingType.ReadOnlyStorage, 0);
entries[2] = CreateStorageEntry(2, WGPUBufferBindingType.ReadOnlyStorage, 0);
Expand All @@ -113,10 +115,12 @@ public static unsafe bool TryCreateBindGroupLayout(
entries[6] = CreateSampledTextureEntry(6);
entries[7] = CreateSampledTextureEntry(7);
entries[8] = CreateSampledTextureEntry(8);
entries[9] = CreateStorageEntry(9, WGPUBufferBindingType.ReadOnlyStorage, 0);
entries[10] = CreateStorageEntry(10, WGPUBufferBindingType.ReadOnlyStorage, 0);

WGPUBindGroupLayoutDescriptor descriptor = new()
{
entryCount = 9,
entryCount = 11,
entries = entries
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that counts, per tile, how many flattened line segments cross it: one thread per
/// GPU stage that counts, per tile, how many final line segments cross it: one thread per
/// line walks the line's tile crossings, bumps tile segment counts and backdrops, and emits one
/// SegmentCount record per crossing for path-tiling. Wraps <c>path_count.wgsl</c>.
/// </summary>
Expand All @@ -29,7 +29,7 @@ internal static unsafe class PathCountComputeShader
/// ceil(<paramref name="lineCount"/> / 256). At runtime the stage is normally driven by
/// the indirect count written by path-count-setup using the same divisor.
/// </summary>
/// <param name="lineCount">The number of flattened lines.</param>
/// <param name="lineCount">The number of final lines.</param>
/// <returns>The X dispatch dimension in workgroups.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint GetDispatchX(uint lineCount)
Expand All @@ -52,7 +52,7 @@ public static bool TryCreateBindGroupLayout(
// Bindings match path_count.wgsl:
// 0 config uniform
// 1 bump allocators (read-write; lines read, seg_counts bump-allocated)
// 2 lines (read-only LineSoup from flatten)
// 2 lines (read-only LineSoup from path lowering)
// 3 paths (read-only Path records from path_row_alloc)
// 4 rows (read-only PathRow spans finalized by tile_alloc)
// 5 tile (read-write; backdrop and segment counts updated atomically)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that computes the indirect dispatch size for the per-line stages
/// (path-row-span and path-count) by dividing the flattened line count by the workgroup
/// (path-row-span and path-count) by dividing the final line count by the workgroup
/// size, or zero workgroups after an upstream allocation failure. Wraps
/// <c>path_count_setup.wgsl</c>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that flattens encoded path segments into a device-space line soup, expands
/// strokes via the CPU PolygonStroker port, and accumulates per-path bounding boxes for the
/// downstream stages. Wraps <c>flatten.wgsl</c>.
/// GPU stage that lowers encoded path segments into device-space lines and expands strokes
/// with the CPU PolygonStroker port. The stage also accumulates per-path bounding boxes for
/// downstream stages. It wraps <c>path_lowering.wgsl</c>.
/// </summary>
internal static unsafe class FlattenComputeShader
internal static unsafe class PathLoweringComputeShader
{
/// <summary>
/// Gets the generated WGSL source bytes for the flatten stage.
/// Gets the generated WGSL source bytes for the path-lowering stage.
/// </summary>
public static ReadOnlySpan<byte> ShaderCode => GeneratedWgslShaderSources.FlattenCode;
public static ReadOnlySpan<byte> ShaderCode => GeneratedWgslShaderSources.PathLoweringCode;

/// <summary>
/// Gets the WGSL entry point used by this shader.
Expand All @@ -35,7 +35,7 @@ public static uint GetDispatchX(uint pathTagCount)
=> (pathTagCount + 255U) / 256U;

/// <summary>
/// Creates the bind-group layout required by the flatten stage.
/// Creates the bind-group layout required by the path-lowering stage.
/// </summary>
/// <param name="api">The WebGPU API facade.</param>
/// <param name="device">The device that owns the staged-scene pipelines.</param>
Expand All @@ -48,7 +48,7 @@ public static bool TryCreateBindGroupLayout(
out WGPUBindGroupLayoutImpl* layout,
out string? error)
{
// Bindings match flatten.wgsl:
// Bindings match path_lowering.wgsl:
// 0 config uniform
// 1 scene (read-only path tags, points, styles and transforms)
// 2 tag_monoids (read-only pathtag prefix sums from the scan stages)
Expand All @@ -72,7 +72,7 @@ public static bool TryCreateBindGroupLayout(
layout = api.DeviceCreateBindGroupLayout(device, in descriptor);
if (layout is null)
{
error = "Failed to create the flatten bind-group layout.";
error = "Failed to create the path-lowering bind-group layout.";
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,19 @@ public static bool TryCreateBindGroupLayout(
// 3 bump allocators (read-write; path_rows bump-allocated, failure bit set on overflow)
// 4 paths (read-write; Path record written per draw object)
// 5 rows (read-write; PathRow records initialized to empty spans)
WGPUBindGroupLayoutEntry* entries = stackalloc WGPUBindGroupLayoutEntry[6];
// 6 path_bboxes (read-only path bounds before clipping to the drawing bounds)
WGPUBindGroupLayoutEntry* entries = stackalloc WGPUBindGroupLayoutEntry[7];
entries[0] = SceneShaderBindingLayoutHelper.CreateUniformEntry(0, (nuint)sizeof(GpuSceneConfig));
entries[1] = SceneShaderBindingLayoutHelper.CreateStorageEntry(1, WGPUBufferBindingType.ReadOnlyStorage);
entries[2] = SceneShaderBindingLayoutHelper.CreateStorageEntry(2, WGPUBufferBindingType.ReadOnlyStorage);
entries[3] = SceneShaderBindingLayoutHelper.CreateStorageEntry(3, WGPUBufferBindingType.Storage, (nuint)sizeof(GpuSceneBumpAllocators));
entries[4] = SceneShaderBindingLayoutHelper.CreateStorageEntry(4, WGPUBufferBindingType.Storage);
entries[5] = SceneShaderBindingLayoutHelper.CreateStorageEntry(5, WGPUBufferBindingType.Storage);
entries[6] = SceneShaderBindingLayoutHelper.CreateStorageEntry(6, WGPUBufferBindingType.ReadOnlyStorage);

WGPUBindGroupLayoutDescriptor descriptor = new()
{
entryCount = 6,
entryCount = 7,
entries = entries
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that derives sparse per-row tile column spans from the flattened line stream:
/// GPU stage that derives sparse per-row tile column spans from the final line stream:
/// one thread per line replays the tile-crossing traversal, atomically growing each touched
/// row's span and accumulating per-row winding backdrops for tile-alloc. Wraps
/// <c>path_row_span.wgsl</c>.
Expand Down Expand Up @@ -40,7 +40,7 @@ public static bool TryCreateBindGroupLayout(
// Bindings match path_row_span.wgsl:
// 0 config uniform
// 1 bump allocators (read-write because the buffer is atomic; this stage only reads the lines counter)
// 2 lines (read-only LineSoup from flatten)
// 2 lines (read-only LineSoup from path lowering)
// 3 paths (read-only Path records from path_row_alloc)
// 4 rows (read-write; spans, backdrops and flags accumulated atomically)
WGPUBindGroupLayoutEntry* entries = stackalloc WGPUBindGroupLayoutEntry[5];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static bool TryCreateBindGroupLayout(
// Bindings match path_tiling.wgsl:
// 0 bump allocators (read-write because the buffer is atomic; this stage only reads the seg_counts total)
// 1 seg_counts (read-only SegmentCount records from path_count)
// 2 lines (read-only LineSoup from flatten)
// 2 lines (read-only LineSoup from path lowering)
// 3 paths (read-only Path records)
// 4 rows (read-only sparse PathRow records)
// 5 tiles (read-only; segment_count_or_ix holds the inverted segment base index from coarse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Drawing.Processing.Backends;

/// <summary>
/// GPU stage that finishes the pathtag scan, writing an exclusive prefix TagMonoid per 4-byte
/// tag word for flatten to locate path data in the scene stream. Two generated variants share
/// tag word for path lowering to locate path data in the scene stream. Two generated variants share
/// this wrapper: the small variant scans the pathtag-reduce partials directly, while the large
/// variant reads per-workgroup prefixes precomputed by pathtag-scan1. Wraps
/// <c>pathtag_scan.wgsl</c>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,28 @@

// Per-path device-space bounding box record.
//
// Cleared by bbox_clear.wgsl, atomically widened by flatten.wgsl (via its
// Cleared by bbox_clear.wgsl, atomically widened by path_lowering.wgsl (via its
// field-compatible AtomicPathBbox view of the same buffer), then consumed by
// binning.wgsl, clip_reduce.wgsl, clip_leaf.wgsl, and draw_leaf.wgsl.
// Ported from Vello's shader/shared/bbox.wgsl (linebender/vello) with
// ImageSharp additions (coverage_threshold, interest).
// ImageSharp additions (coverage_data, interest).

// The annotated bounding box for a transformed path.
// Coordinates are integer pixels (for the convenience of atomic update)
// but will probably become fixed-point fractions for rectangles.
//
// `draw_flags` is propagated to the draw info stream and carries fill-rule, aliasing, and blend state.
// Field layout must mirror AtomicPathBbox in flatten.wgsl.
// Field layout must mirror AtomicPathBbox in path_lowering.wgsl.
struct PathBbox {
x0: i32, // min bounds; i32 max while empty (see bbox_clear)
y0: i32,
x1: i32, // max bounds; x0 > x1 denotes an empty box
y1: i32,
draw_flags: u32,
trans_ix: u32, // index of the path's transform in the scene stream
// Per-fill coverage parameter, propagated from the style record to the fine pass.
// For aliased fills this is the quantization cutoff in [0,1]; for antialiased fills it
// carries the perceptual coverage boost for text (zero when disabled). The draw-flags
// aliased bit selects the interpretation; the two uses are mutually exclusive.
coverage_threshold: f32,
// Per-fill antialiased coverage adjustment propagated from the style record to the fine pass.
// Aliased fills use exact centre sampling and leave this value at zero.
coverage_data: f32,
_padding: u32,
interest: vec4<f32>, // raster interest rect (x0, y0, x1, y1) in pixels
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// compare the result against the capacity in Config; on overflow they set
// their STAGE_* bit in `failed` and the C# side reads the block back, grows
// the buffers, and retries the render. Imported by most compute stages
// (binning, flatten, tile/row allocation, counting, coarse, chunk_reset,
// (binning, path lowering, tile/row allocation, counting, coarse, chunk_reset,
// prepare, and the indirect-dispatch setup shaders).
//
// Ported from Vello's shader/shared/bump.wgsl (linebender/vello), where the
Expand All @@ -16,7 +16,7 @@
// Bitflags for each stage that can fail allocation.
const STAGE_BINNING: u32 = 0x1u;
const STAGE_TILE_ALLOC: u32 = 0x2u;
const STAGE_FLATTEN: u32 = 0x4u;
const STAGE_PATH_LOWERING: u32 = 0x4u;
const STAGE_PATH_COUNT: u32 = 0x8u;
const STAGE_COARSE: u32 = 0x10u;

Expand All @@ -33,7 +33,7 @@ struct BumpAllocators {
seg_counts: atomic<u32>, // SegmentCount records
segments: atomic<u32>, // Segment records
blend_spill: atomic<u32>, // blend stack slots spilled past BLEND_STACK_SPLIT
lines: atomic<u32>, // LineSoup records from flattening
lines: atomic<u32>, // final LineSoup records from path lowering
}

// Workgroup counts for dispatchWorkgroupsIndirect, written by the setup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,16 @@ struct Config {
segments_size: u32,
blend_size: u32,
ptcl_size: u32,
// Scene-wide coverage cutoff consumed by the aliased fine pass; per-fill
// thresholds (CmdFill.coverage_threshold) override it where set.
fine_coverage_threshold: f32,

// Word offset of the segment-profile tag table, or zero when the table is absent. Each encoded
// point pair has one slot, which lets a fill segment find its X and Y profile identifiers.
profile_slots_base: u32,
// Word offset of the profile record table, or zero when the table is absent. The table starts
// with the X and Y record counts. Each record then stores two axis limits and one contour link.
profile_records_base: u32,
profile_pad0: u32,
profile_pad1: u32,
profile_pad2: u32,
}

// Geometry of tiles and bins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Draw tag stream decoding: the draw monoid, tag values, and draw-flag bits.
//
// Imported by binning.wgsl, clip_leaf.wgsl, coarse.wgsl, draw_leaf.wgsl,
// draw_reduce.wgsl, fine.wgsl, flatten.wgsl, and path_row_alloc.wgsl.
// draw_reduce.wgsl, fine.wgsl, path_lowering.wgsl, and path_row_alloc.wgsl.
// Ported from Vello's shader/shared/drawtag.wgsl (linebender/vello) with
// ImageSharp additions (recolor, elliptic and path gradient tags, the
// aliased-coverage bit, and the blend mode/alpha draw-flag fields).
Expand All @@ -28,7 +28,7 @@ struct DrawMonoid {
// Each draw object has a 32-bit draw tag, which is a bit-packed
// version of the draw monoid: bit 0 = clip count, bits 2..4 = scene words,
// bits 6..9 = info words (see map_draw_tag).
// Visible-fill draw tags carry five extra info words: coverage threshold plus raster interest.
// Visible-fill draw tags carry five extra info words: coverage data plus raster interest.
const DRAWTAG_NOP = 0u;
const DRAWTAG_FILL_COLOR = 0x188u;
const DRAWTAG_FILL_RECOLOR = 0x184u;
Expand All @@ -45,9 +45,8 @@ const DRAWTAG_END_CLIP = 0x21u;
// draw object stream but is used after the draw objects have been reduced on the GPU.
// 0 represents a non-zero fill. 1 represents an even-odd fill.
const DRAW_INFO_FLAGS_FILL_RULE_BIT = 1u;
// Per-fill coverage rule. When set, the fill is rasterized aliased (coverage quantized against
// config.fine_coverage_threshold) instead of using analytic area coverage. Carried in a free
// high bit of the draw-flags word alongside the fill-rule bit.
// Per-fill coverage rule. When set, the fill is rasterized using exact centre sampling instead
// of analytic area coverage. Carried in a free high bit alongside the fill-rule bit.
const DRAW_INFO_FLAGS_ALIASED_BIT = 0x40000000u;
// Blend state packed into the draw-flags word by the C# encoder
// (WebGPUSceneEncoder.PackStyleDrawFlags): bits 1..13 hold the (mix << 8) | compose
Expand All @@ -59,10 +58,8 @@ const DRAW_FLAGS_BLEND_ALPHA_MASK = 0x3fffc000u;

// Flag bits carried in the high bits of the clip blend word, set by the C# encoder
// (WebGPUSceneEncoder.AppendClipBeginData). DIFFERENCE marks an ImageSharp Difference
// clip so fine inverts the mask; HARD marks a hard-edge (aliased) clip mask. Declared
// here because every consumer (draw_leaf, coarse, fine) imports this module.
// clip so fine inverts the mask. Declared here because every consumer imports this module.
const CLIP_DIFFERENCE_MASK_BIT = 0x80000000u;
const CLIP_HARD_MASK_BIT = 0x40000000u;
// Marks an ISOLATED group (a layer). Isolated groups seed with transparent content and
// composite back with blend_mix_compose, matching the CPU backend's clean layer targets.
// Non-isolated groups (canvas clips) seed with a copy of the current tile content and pop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
//
// The scene encodes each path as a byte stream of tags (one per segment,
// plus transform/style/path markers). The pathtag_reduce/scan stages compute
// a prefix sum of TagMonoid over that stream so flatten.wgsl can locate each
// a prefix sum of TagMonoid over that stream so path_lowering.wgsl can locate each
// segment's point data, transform, and style in O(1). Imported by
// flatten.wgsl, pathtag_reduce.wgsl, pathtag_reduce2.wgsl, pathtag_scan.wgsl,
// path_lowering.wgsl, pathtag_reduce.wgsl, pathtag_reduce2.wgsl, pathtag_scan.wgsl,
// and pathtag_scan1.wgsl.
//
// Ported from Vello's shader/shared/pathtag.wgsl (linebender/vello). Tag
Expand Down Expand Up @@ -43,7 +43,7 @@ const STYLE_SIZE_IN_WORDS: u32 = 10u;
// Flag bits of the first word of a Style record, packed by the C# encoder.
// STYLE marks a stroke (vs fill) and FILL marks the even-odd fill rule
// (clear = non-zero); the cap and join fields drive the GPU stroker in
// flatten.wgsl.
// path_lowering.wgsl.
const STYLE_FLAGS_STYLE: u32 = 0x80000000u;
const STYLE_FLAGS_FILL: u32 = 0x40000000u;

Expand Down
Loading
Loading