Warnock: Harnessing GPU Geometry Amplification for Vector Graphics
Mark J. Kilgard, NVIDIA, USA
Brian Barran, NVIDIA, USA
stroking steps: single unified GPU-resident buffer for filling and stroking control point positions common link topology cap & join link topology implicit close link topology fill anchor positions fill cover positions fill contour index ranges
tessellated stroke geometry (stencil step) identical tessellation conservative stroke geometry (cover step) stroke result (after stencil, then cover) both using same single stroke shader
filling steps: tessellated fill winding geometry (stencil step) conservative cover geometry (cover step) fill result (after stencil, then cover) stroked-then-filled color result both using same single fill shader
less overall storage since control points & links are common to both
Fig. 1. Warnock’s rendering flow starts with a single unified GPU-resident data representation ( leftmost) of the HPG 2026 logo and first strokes the logo’s path ( top) and then fills it ( bottom) in four steps to complete the result ( rightmost) using polar tessellation implemented by either GPU tessellation or mesh shaders.
Warnock is a novel 2D vector graphics library harnessing the programmable geometry amplification features of GPUs. Warnock refines the theory of polar stroking by providing a practical pixel-space quality metric; furthermore, it extends polar stroking to also fill paths. Warnock converts a path into a single compact GPU buffer so this one buffer has all the necessary data to both fill and stroke the path. Unlike prior art, this one GPU buffer handles all variations in transformation, stroke width, capping, and join styles. Warnock supports older DirectX 11-class GPUs with tessellation shaders, but recent GPUs with mesh shading perform best.
CCS Concepts: • Computing methodologies → Rasterization; Graphics processors; Non-photorealistic rendering.
Additional Key Words and Phrases: path rendering, vector graphics, polar stroking, polar filling, geometry amplification
ACM Reference Format:
Mark J. Kilgard and Brian Barran. 2026. Warnock: Harnessing GPU Geometry Amplification for Vector Graphics. *Proc. ACM Comput. Graph. Interact. Tech.*9, 4, Article 57 (July 2026), 21 pages. https://doi.org/10.1145/3820012
Authors’ Contact Information: Mark J. Kilgard, NVIDIA, Austin, TX, USA, mjk@nvidia.com; Brian Barran, NVIDIA, Boulder, CO, USA, bbarran@nvidia.com.
57:2
1 Introduction
Warnock and Wyatt’s foundational work [1982] on two-dimensional (2D) vector graphics established the basic rendering operations for 2D resolution-independent graphics, specifically the filling and stroking of curvilinear paths. Early implementations of their approach rendered images with CPU-based scan-line rasterizers.
AdvancementsintheprogrammabilityofGPUsmakeitpossibleforgraphicshardware—originally designed for 3D graphics—to be cleverly adapted to render 2D vector graphics. This capability is now broadly deployed worldwide in web browsers and other applications.
1.1 GPU Geometry Amplification for Path Tessellation
However, these existing approaches have not harnessed the geometry amplification features of GPUs, notably GPU tessellation and, more recently, mesh shading. The GPU tessellation and mesh shading techniques we present offload the geometry expansion steps of path rendering entirely to the GPU and, importantly, do so for both filling and stroking from a single compact GPU buffer.
We describe our novel GPU-accelerated system called Warnock, named as an homage to the late John Warnock [Beach 1989; Risen 2023] who first systematized 2D vector graphics. Our Warnock software library aggressively harnesses the geometry amplification features of GPUs for path rendering by applying novel tessellation algorithms well suited to GPU parallelism. Converting a particular path from its usual CPU representation (a list of path commands and corresponding control points) to its GPU representation within Warnock is done once as a linear-time conversion. Once a path’s GPU representation is converted, downloaded to the GPU, and bound within the graphics pipeline, then a bare minimum of 3D API commands launches programmable GPU shaders to fill or stroke the original path as shown in Fig. 1.
Unlike prior art, no change to the path’s GPU buffer is needed when changing render state such as the coordinate space transform, fill rule, stroke width, pen shape, join style, end caps, or shading state. Instead, inexpensive buffer binds and possibly binding a different shader program are all that is required to change common 2D vector graphics modes. This is possible because all the required path tessellation happens entirely within the GPU, thereby reducing the involvement of the CPU in drawing paths and completely eliminating the CPU’s involvement in path tessellation.
No prior published path rendering methods operating within the GPU graphics pipeline have:
(1) A single compact GPU buffer representation for any path for both filling and stroking.
(2) Geometry amplification,culling,and apixel-spaceerrorbound computationoperatingentirely within the GPU’s efficient programmable graphics pipeline.
(3) The ability to support the wide variety of standard 2D vector graphics rendering modes ( even projective transforms and texture-based dashing) merely by changing the bound shader program, textures, or GPU buffers.
Warnock achieves—in combination—these three properties because the theory of polar stroking [Kilgard 2020c] and its adaptation for polar filling enable the GPU during an initial setup step for each path segment, join, or cap in a path to compute the amount of geometry amplification needed to tessellate the path’s filled or stroked geometry to satisfy the specified pixel-space quality metric prior to actual geometric expansion.
1.2 Paper Contributions and Organization
1.2.1 Our contributions:
(1) Develop and implement polar filling, a GPU-accelerated method to fill paths that shares the same polar evaluation theory as polar stroking and is
• adapted for programmable GPU tessellation,
57:3
• adapted for mesh shading, and
• designed to take as input the same compact GPU representation for both filling and stroking.
(2) Introduce a pixel-space tessellation metric for polar tessellation and implement it for both polar stroking and filling.
1.2.2 Organization. Section 2 reviews prior work on GPU-accelerated vector graphics. Section 3 explains our general approach to decomposing paths into links, geometry amplification via polar tessellation, and our pixel-space error metric. Section 4 explains our implementation of polar filling and stroking for both GPU tessellation and mesh shaders, managing render state with bindable buffers, and other details. Section 5 experimentally assesses how effectively Warnock meets its goal of harnessing GPU geometry amplification for vector graphics. Section 6 concludes.
2 Prior Work
2.1 CPU-Based Vector Graphics Rendering
Early path rendering software relied on CPU-based scan-line rasterizers. Even today, CPU-based path rendering systems predominantly rely on scan-line rasterizers.
Scan-line rasterizers [Ackland and Weste 1981; Kallio 2007; Wallis 1990] can be implemented with fairly miserly memory requirements. The term “scan-line” refers to the fact that each path is rasterized one horizontal scan-line at a time.
To fill inside the boundary of curvilinear segments, paths are typically first flattened into approximating strips of line segments. To stroke a path, stroke offsetting displaces the path boundary orthogonally to its tangent in both directions by the stroke radius so that the offset stroke region can then be filled. Offsetting quadratic and cubic Bézier segments is mathematically challenging [Farouki and Neff 1990a,b] so various approximation methods have been proposed [Elber et al. 1997] with Yzerman [2020] and Levien and Uguray [2024] offering recent approaches.
2.2 GPU-Based Vector Graphics Rendering
While dedicated hardware implementations of scan-line renderers have been proposed [Huang and Chae 2006; Kim et al. 2008; Lin et al. 2012; Shen et al. 2010], the additional hardware expense for a dedicated 2D vector graphics engine has proven difficult to justify compared to high-performance approaches built atop the established GPU graphics pipeline.
2.2.1 GPU Graphics Pipeline Methods. The prior work most akin to our work consists of methods for filling and stroking paths using the conventional GPU graphics pipeline. Microsoft’s Direct2D [Kerr 2009] API is layered upon Direct3D and breaks filled and stroked paths into trapezoids that are rendered by the GPU as batches of triangle pairs. However, because the tessellation of paths into trapezoids happens on the CPU, Direct2D is arguably more GPU-assisted than GPU-accelerated.
Loop and Blinn [2005] proposed an efficient evaluation scheme for curvilinear edge rasterization performed within a fragment shader. Kokojima et al. [2006] applied the Loop-Blinn scheme in conjunction with the stencil buffer [Akeley and Foran 1995] to compute the winding number of framebuffer samples with respect to TrueType glyph outlines. Slug [Lengyel 2017] is particularly efficient at rendering filled glyphs from outline fonts. Combining mesh shader geometric amplification of pre-tessellated TrueType glyphs with conditional quadratic Bézier edge rasterization can render text [Meyer et al. 2024]. Kilgard and Bolz [2012] generalized Kokojima’s approach to the full range of path rendering functionality including elliptical path segments, stroking, dashing, and clipping to arbitrary paths. Their “stencil, then cover” approach is exposed as an OpenGL extension called NV_path_rendering [Kilgard 2012]. Batra et al. [2015] built upon NV_path_rendering to
57:4
support required PDF [Adobe Systems 2008] capabilities including layers, CMYK for print, and gradient meshes.
Today, the dominant GPU-accelerated system for 2D vector graphics is Google’s Skia [Skia team 2025] that provides the rendering for Android, Chrome browser, and Microsoft’s .NET framework [SkiaSharp team 2025]. Skia has evolved over time using various tessellation and “stencil, then cover” approaches for filling and stroking.
Skia’s most sophisticated shaders use instanced vertex shaders to tessellate filled and stroked paths. With instanced vertex shaders [Gold et al. 2008], a single drawing command on the CPU launches 𝑛 copies of the same geometry on the GPU and each of the 𝑛 batches can be transformed differently by the current vertex shader. The specific value of 𝑛 must be computed and specified by the CPU. Vertex shader instancing is in contrast to GPU geometry amplification features that provide an initial GPU shader stage (a task shader for mesh shaders; a control or hull shader for GPU tessellation) to compute the necessary batch size and setup parameters completely within the GPU. Compared to geometry amplification approaches, instanced vertex shaders involve redundant work and require the CPU to anticipate the worst case expansion.
2.2.2 GPU Compute Methods. The advent of programmable parallel computation within the GPU but outside the GPU’s traditional graphics pipeline (e.g., NVIDIA’s CUDA [Nickolls et al. 2008]) provides a different avenue for GPU-acceleration of path rendering. This approach grew out of vector texture methods [Nehab and Hoppe 2008; Parilov and Zorin 2008; Qin et al. 2008] whereby resolution-independent boundaries are evaluated within GPU fragment shaders. By harnessing general-purpose GPU compute capabilities, research vector graphics systems [Dokter et al. 2019; Ganacim et al. 2014; Li et al. 2016] build GPU-resident acceleration structures for an entire vector graphics scene from which the scene can be programmatically rasterized. A hybrid approach runs a compute shader for parallel stroke evaluation and then renders the resulting approximation relying on lines and circular arcs with the conventional graphics pipeline [Levien and Uguray 2024]. However, these approaches tend to suffer from slow scene build times (problematic for dynamic scenes), unpredictable memory bounds, poor load balancing, incomplete feature sets (i.e., lack of stroking, dashing, clipping, layers, or other essential features), and difficulty integrating with applications already using existing graphics libraries.
3 Our Approach
3.1 Generalizing Polar Tessellation of Paths
GPUs harness a great deal of parallel computation in the service of computer graphics, but this computation is designed to draw streams of uniform 3D triangles rather than varying 2D paths with their unbounded size, serial interleaving of various path commands and associated control points, and many geometric complications (holes, concavity, overlaps, curvilinear shape, caps, joins, and cusps).
Accurately tessellating the coverage regions of filled and stroked 2D paths is surprisingly tricky [Fabris et al. 1997; Kilgard 2020a; Nehab 2020] due to the mentioned geometric complications. Naive tessellation with uniform parametric evaluation is prone to either over- or under-tessellate even within a single curvilinear segment and does not guarantee a bound on the pixel-space tessellation error. While recursive curve splitting algorithms can provide good error bounds—as done in CPU-based scan-line path renderers—their recursive nature is anathema to GPU shader parallelism.
3.1.1 Polar Stroking. The method of polar stroking [Kilgard 2020c] relies on sound theory to compute uniform steps in gradient angle change. The polar in the name refers to how a curved
57:5
for filling & stroking for filling only for stroking only
Segment Link Junction Connecting junction Non-connecting junction Join Cusp implicit close line segment
(a) link type taxonomy
(b) cap styles
(c) join geometry
None Miter Triangular Triangular Truncated Miter Miter Round
Fig. 2. The taxonomy of different kinds of link types (a) possible within a path; each cap position is given its (b) cap style while the join style decides (c) each join’s geometry.
path segment’s gradients, expressed in polar coordinates, are evaluated in uniform steps of polar coordinate angle to advance tessellation along that curve by uniform turning angle deltas. Bounding the gradient angle change also bounds the facet angle of the tessellation [Kilgard 2020b] to twice the gradient angle change. One notable improvement made in Warnock’s implementation of polar stroking is adding a tessellated half-step in gradient angle change at either end of curved segment intervals used for polar stroking because the cases where the facet angle can be twice the gradient angle change are near inflection points, hence at the end of intervals. These half-steps practically improve the facet angle bounding.
However, such an angular bound does not and cannot provide a bound on the pixel-space displacement error. So, we propose and implement an effective, recursion-free strategy to compute the gradient angle change that does reasonably bound the tessellation’s pixel-space displacement error (see Sec. 3.6). Fig. 1 shows stroking done this way labeled in green as stroking steps.
3.1.2 Polar Filling. Warnock adapts polar stroking to generate an anchored triangle fan for each path contour when filling a path and bounds the pixel-space displacement error in the same manner as done for stroking. Assuming a stencil buffer is initialized to a constant value, then rasterizing the anchored triangle fans for all the contours in the path while stencil incrementing frontfacing triangles and stencil decrementing backfacing triangles resolves the filled coverage of the path in the stencil buffer [Neider et al. 1993]. Then a precomputed convex polygon that conservatively covers all the path’s contours (the cover geometry) is rasterized to shade all the covered pixels within the path as well as reset the stencil buffer for the next path to render. Fig. 1 shows filling done this way labeled in orange as filling steps.
3.2 Decomposing Paths into Links
Before the GPU can tessellate and rasterize a filled or stroked path, Warnock must first break apart the path into simpler constituents called links. This process, called path baking, decomposes each path into two arrays: (1) a link array, and (2) a control point coordinate array. Each link consists of the link’s type and six indices into the control point coordinate array. Each link type (shown organized into a taxonomy in Fig. 2) determines how these indices are interpreted. Warnock enumerates ten link types:
• Cubic Bézier segment links, including degenerate cubics to encode line segments;
• Quadratic Bézier segment links;
• Conic links parameterized as normalized rational quadratic Bézier segments [Lee 1987];
• Cap links: InitialPathCap, TerminalPathCap, InitialDashCap, and TerminalDashCap;
• Join links;
• Cusp links (same as Join links but ignore join style and are always round); and
57:6
• ImplicitClose links for implicitly closed contours.
Each link in the path’s link array completely and independently specifies what is required to tessellateitspathusingtheGPU’sgeometryamplificationfeatures.ThespecificsabouthowWarnock encodes links are different for (1) GPU tessellation versus (2) mesh shading, but conceptually the two encodings both decode into a link type and array of coordinate indices supplying the link’s associated control points from the path’s control point coordinate array. While there are six control point indices per link, four unique (𝑥, 𝑦) control point positions are specified at most.
The Join and various cap (InitialPathCap, etc.) link types generate joins and caps respectively for stroking but are skipped when filling. An ImplicitClose link expands to an anchored line segment to close filled contours not otherwise explicitly closed with a ClosePath command. In contrast to join and cap links, the ImplicitClose link is processed when filling but is skipped when stroking. The actual style of a cap (flat, triangular, square, or round) is determined by the shader based on shader state providing a mapping from cap position to cap style. Likewise, the style of a join (none, bevel, triangular, or mitered) also depends on shader state.
3.2.1 Position versus Gradient Control Points. Once each link’s type is determined, the link’s control point indices into the path’s coordinate array are assigned. While a cubic Bézier segment needs just four control points, six total control point indices allow the initial and terminal gradient for a link to be specified independently from the segment’s control points. In the case of the Cubic link type, there are four control points for the cubic Bézier curve, but two additional control points for the initial and terminal gradient control points. Typically, the gradient control points simply repeat the index of the two middle (second and third) position control points; however, when position control points are colocated, the gradient control points indicate the first non-colocated control point suitable for differencing to compute a proper (non-degenerate) initial or terminal gradient for the cubic segment.
For a line segment, the first two and last two position control points are colocated while the gradient control points are the terminal and initial position control points respectively for the initial and terminal gradients. For a Quadratic link, only three position control points are used, but the gradient control points still provide the initial and terminal gradient to account for colocated control points. For a Conic link, the second (middle) control point is stored as a 2D homogeneous (𝑥, 𝑦, 𝑤) position—so with a 𝑤 coordinate. Cusp configurations for a cubic segment, or conic with an infinite 𝑤 value, have four colocated position control points (at the cusp location) but then have gradient control points indicating the initial (entering) and terminal (exiting) gradients of the cusp. Join and cap links too have all four position control points colocated. For joins, the gradient control points indicate the entry and exit directions for the join. For caps, a single gradient control point determines the cap’s negative and positive normal directions.
3.2.2 Handling Arcs as Conic Splines. During baking, the various circular and elliptical arc parameterizations in path rendering standards are decomposed into an equivalent sequence of Conic and Join links. For numerical reasons, degenerate conics with a 𝑤 value nearly or equal to zero or infinity must be decomposed into a sequence of Cubic links for lines and cusps.
3.2.3 Additional Filling State. The path baking for filling also includes (1) an array of (𝑥, 𝑦) anchor control points, one per contour in the path; (2) an extra sequence of one to six links to represent a convex hull over the path’s segment links; and (3) the (𝑥, 𝑦) control point coordinates for this cover geometry. Each contour in a filled path has its own per-contour range of baked path links and the anchor control point for the contour. Section 3.5 explains how this state is used during filling.
The aggregate baked state for polar stroking and filling is then placed into a single unified GPU-resident buffer as labeled in Fig. 1.
57:7
launch patch see polar control pointstessellation CPU indices vertex flowchart making 3D API shader in Fig. 9 calls transformed control points see polar patch layout parameters tessellation tessellation control flowchart shader in Fig. 10 patch polar tessellation setup & topology control points generator tessellation rectangular patch or iso-lines evaluation parametric (u,v) shader vertex feed yes geometry see polarline strip shader? tessellation geometry no flowcharttessellated in Fig. 11 shader (optional) triangles stroking: quadrilaterals filling: anchored (triangle pair) triangle (triangle pair) rasterization rasterized fragments color & stencil fixed function fragment updates pixel programmable stage shader operations
Fig. 3. High-level view of GPU tessellation in GPUs.
launch task shader CPUwork groups see polar making 3D API tessellation callsflowchart task in Fig. 12 shader see polar polar tessellation setup, tessellationcontrol points, and flowchartnumber of mesh shader work groups in Fig. 13 to spawn mesh shader index buffer (triangle topology), per-vertex aribute buffer, and per-primitive aributes buffer rasterization rasterized fragments color & stencil fixed function fragment updates pixel programmable stage shader operations
Fig. 4. High-level view of task and mesh shaders.
3.3 Geometry Amplification Approaches
While the ten link types are distinct in their general geometric appearance (segments vs. joins vs. caps) and how they must be processed, Warnock’s unified tessellation strategy based on polar evaluation allows all link types to be processed by a unified shader program. So, in practice, the GPU’s shader stages for geometric amplification execute efficiently using largely converged shader execution despite processing different types of links.
Both the setup for the path tessellation and the per-vertex evaluation using polar stroking or filling happen within the so-called geometry amplification stages of the standardized GPU graphics pipeline. Examples are OpenGL 4.0 or DirectX 11-style tessellation shaders, possibly using geometry shaders, and mesh shading for more recent GPU generations.
The specifics of how a path is baked in advance of polar tessellation are different for GPU tessellation compared to mesh shading. The details of path baking are involved but are discussed at length in our supplemental document [Kilgard and Barran 2026b].
3.3.1 GPU Tessellation. The two-stage processing of tessellation shaders [Purcell 2010] (diagrammed in Fig. 3) spawns the initial control (OpenGL) or hull (DirectX 11) shader that accepts a six control point input patch corresponding to a link within the path and computes the polar evaluation parameters including the number of polar evaluations based on a quality-metric that can be a pixel-space bound. Then the follow-on evaluation (OpenGL) or domain (DirectX 11) shader instances perform the per-vertex polar evaluation and output a patch vertex. Warnock hijacks the conventional quadrilateral output patch geometry with a novel technique we call NaN-poisoning so the patch output geometry is “cut into strips” to form a continuous connected strip of triangles for stroking (Fig. 5) or “cut into fans” for filling. Alternatively, an iso-line tessellation shader can feed a geometry shader to form the triangle strip. The triangles either form an anchored triangle fan (for filling) or a quadrilateral strip of triangle pairs (for stroking) that feeds the rasterizer. The
57:8
GPU tessellation mesh view frustum clipping post-clipping mesh
Legend • regular mesh vertex example clip-space position: (x, y, z, w) • NaN-poisoned vertex example clip-space position : (NaN, y, z, w)
initial cap nearly straight cubic round join loop cubic round join serpentine cubic terminal cap
Fig. 5. GPUs discard any primitive assembled from one or more vertices with a NaN (not-a-number) position coordinate prior to rasterization ( left) according to Direct3D rules [Microsoft 2025] (15.16.1 Valid Position Range). An example stroked path ( right top); the GPU tessellation mesh in (𝑢, 𝑣) patch space for each link in the example ( right middle); and the end-to-end stitched GPU tessellation result of the example ( right bottom).
resulting rasterized fragments have shading and coverage computations prior to their stencil and color buffer updates.
3.3.2 Mesh Shading. With the mesh shading feature [Kubisch 2018; Kubisch and Brown 2018] of current generation GPUs, the two-stage tessellation (diagrammed in Fig. 4) is split between a task shader and follow-on mesh shaders. The task shader performs the same polar evaluation setup as the tessellation control shader, but rather than emitting level-of-detail parameters for a patch, the task shader generates a number of mesh shader work groups. When these mesh shader work groups spawn, they perform the polar evaluation and build an indexed vertex buffer for the anchored triangle fan (for filling) or triangle strip (for stroking). To make the mesh shader execution efficient, each task shader work group operates on a link pack that encodes up to 8 links.
The patch-based nature of GPU tessellation shaders and the Single Instruction Multiple Thread (SIMT) nature of mesh and task shader execution require a substantially different layout for the GPU representation for polar filling and stroking.
3.3.3 Common Approach: Setup, Polar Evaluation, Rasterization. During the rendering of a path by the GPU, the path’s links are parceled out for processing by the GPU’s parallel computation resources (i.e., shader threads), thereby allowing each link to be processed in parallel. Each link goes through a link setup process where the link is classified, its transformed control points are gathered, parameters for polar evaluation are computed, and the number of vertex evaluations needed for the link is determined based on a quality metric.
After this first stage of link setup, geometry amplification takes place. Downstream shader threads are initiated based on the computed tessellation required for each link’s subsequent polar evaluation and these threads perform that polar evaluation to compute the stroking or filling vertex geometry required for each link. Ultimately, the vertex geometry forms triangle strips (for stroking) or triangle fans (for filling) and this assembled geometry is fed to the GPU rasterizer, converted to fragments that are then colored and used to update the framebuffer’s stencil and color buffers.
For proper antialiasing and to abide by path rendering’s blend-once-and-only-once rule, this processing happens twice to rasterize a particular path. The first pass, called the “stencil” step,
rasterizes the path’s filled or stroked coverage into the stencil buffer. No color writes happen during this first step. Then a second rendering pass, called the “cover” step, tests against the stencil
57:9
coverage generated by the first pass, resets the stencil value back to a neutral state (normally zero), colors the fragment, and blends the fragment with its corresponding pixel color.
Changing the current shader program is a relatively expensive operation so avoiding program changes is advantageous. The anchor and cover geometry for polar filling are generated from the same path encoding and use the same polar filling shader program so no shader change occurs between the “stencil” and “cover” steps. The “stencil” and “cover” steps for polar stroking also use the same polar stroking shader program.
3.4 Polar Stroking with Links
When polar stroking, the shader program discards any ImplicitClose links. Other links may also be discarded if a trivial culling check can prove the geometry for the stroked link is completely outside the view frustum. This check requires computing trivial clip codes for all the control points dilated by the stroke radius and proving they are all outside at least one view frustum clip plane. If miter joins are active, the dilation must also account for the miter limit. Discarding a link for either reason means no further processing of the link occurs (and no geometry is rasterized for this link).
Surviving links are then tessellated into a stream of triangles approximating the path’s stroke as described by Kilgard [2020c]. A single bound GPU program performs the “stencil” and then “cover” steps so no program bind occurs between the steps; the minimal intervening state changes are (1) an inexpensive buffer bind to change the program’s mode of operation and (2) changing the 1 graphics pipeline’s stencil and color configuration.
3.5 Polar Filling with Links
When polar filling, the shader program discards all join and cap links (as such links only matter for stroking). The trivial culling check is simpler because the control points for filling are not dilated by the stroke width.
Whereas for path stroking, the tessellation is a sequence of quadrilaterals (output as triangle pairs), for path filling the tessellation of each closed contour in a path becomes an anchored closed triangle fan. By closed fan, we mean the first non-anchor vertex of the fan is duplicated as the last vertex of the fan, thereby looping around the complete contour. If the subpath was not explicitly closed, an ImplicitClose link provides the necessary closure.
So-called indirect draw commands allow an arbitrarily complex path to be stenciled or covered in 2 just one API call. For the “stencil” step of polar filling, polar evaluation happens just as in stroking, but rather than offsetting from the generator curve of each segment, each generating curve contour is anchored to a centroid position within the contour to form the contour’s anchored closed fan. For the “cover” step of polar filling, an epilogue of 1 to 7 anchored line segment links form a convex polygon with 3 to 8 sides constructed to cover conservatively all the “stencil” step geometry.
3.6 Pixel-Space Error Metric for Polar Tessellation
As originally presented, polar stroking provides an error bound on the maximum tessellated facet angle (see Fig. 6). Such a conformal guarantee is independent of pixel resolution and—for that reason—does not guarantee the tessellated boundary to be within some small pixel displacement (ideally subpixel) from the true stroked (or filled) boundary of a path segment.
To remedy this, Warnock builds upon the theory of polar stroking to introduce a novel error metric that reasonably bounds-without-minimizing the Fréchet distance [Bringmann et al. 2019]
57:10
observable tessellation error water cumps
observable tessellation error
observable tessellation error
Fig. 6. A cubic Bézier segment tessellated by polar stroking with a maximum turning angle error metric of 4 degrees. Being a resolution-independent (conformal) metric, zooming in does not affect the tessellation. When zoomed into boundary regions with the lowest curvature, there is a slight but observable gap between the tessellated stroke (olive quadrilateral outline) and the true stroked boundary (cyan and magenta curves). (To help accentuate the error, the half-step of tessellation mentioned in Sec. 3.1.1 is disabled for this image.)
inner cusps
Fig. 7. Maximum pixel displacement error metric of 0.75 pixels for the same segment in Fig. 6. Being a resolution-dependent metric, zooming in automatically increases the tessellation. This metric leaves no discernible error between the tessellated stroke and the true stroked boundary because any displacement error is smaller than a pixel. The high-curvature region of the stroke (the top hump) is arguably overtessellated, but this is a consequence of bounding the displacement error so the low-curvature regions (the segment ends) have sufficient tessellation.
between a polyline approximation of some portion of the boundary produced by polar stroking (or filling) and its corresponding subcurve that is both strictly convex and monotonic. These subcurves connect end-to-end to form the true curvilinear stroked (or filled) boundary of each curved path segment in a path. The phrase bounds-without-minimizing means Warnock aims to keep the maximum pixel displacement error at or below some specified positive pixel-space bound 𝑑𝑏 but also recognizes there is a cost to over-tessellating path geometry without a compensating quality benefit once the error is below the scale of a pixel.
$$ d _{b} $$
We are careful to emphasize we are not claiming to compute the Fréchet distance of the entire path with its complete polyline tessellation. Instead we claim to ensure that all the Fréchet distances between the strictly convex and monotonic subcurves—that connect together with any straight boundary segments to form the complete stroked (or filled) path boundary—and Warnock’s corresponding polyline approximations are reasonably bounded by a configurable maximum pixel-space displacement.
To accomplish this, Warnock’s shader implementation estimates a maximum turning angle, computed independently for every link interval, to achieve this aim. With this maximum turning angle configured, the subsequent polar stroking (or filling) tessellation is performed normally (meaning with no other modifications) using the number of steps each link interval’s computed maximum turning angle requires. All the computations for this pixel-space error metric are implemented entirely within the control shader for GPU tessellation or the task shader for mesh shading.
3.6.1 Measuring Curve Approximation Similarity. The Fréchet distance serves as a measure of similarity between two curves considering both the location and order of points. Formally, the Fréchet distance between two curves 𝐴 ∶ [0, 1] → 𝑋 and 𝐵 ∶ [0, 1] → 𝑋 in a metric space (𝑋 , 𝑑) is define by Alt and Godau [1995] as:
$$ \delta _{F} (A, B) = \inf _{r, s} \max _{t \in [ 0, 1 ]} d \left(A (r (t)), B (s (t))\right) $$
57:11
where 𝑟, 𝑠 ∶ [0, 1] → [0, 1] are continuous, non-decreasing surjections with common endpoints meaning 𝑟(0) = 𝑠(0) = 0 and 𝑟(1) = 𝑠(1) = 1.
$$ r,\mathfrak{s}:\left[0,1\right]\rightarrow\left[0,1\right] $$
$$ r00=mathfrak s00=0 $$
$$ r(1)=s(1)=1 $$
This general definition is framed as an optimization over infinite-dimensional functions so is far too unwieldy for Warnock’s purposes. Therefore, we narrowly restrict how we apply the Fréchet distance to make it useful and practical.
For Warnock, the metric space (𝑋 , 𝑑) is 2D Euclidean pixel space; the curve 𝐴 is a 2D strictly convex and monotonic curve that is a subcurve of a curved link’s stroked (or filled) boundary; 𝐵 is a polyline boundary resulting from polar stroking (or filling) intended to approximate 𝐴; and 𝐴 and 𝐵 have distinct and common endpoints. Distinct endpoints mean 𝐴(0) ≠ 𝐴(1) while common endpoints mean 𝐴(0) = 𝐵(0) and 𝐴(1) = 𝐵(1). Importantly, all polyline vertices of 𝐵 are points on 𝐴.
$$ A; $$
$$ A(0)\neq A(1) $$
$$ A(0)=B(0) $$
$$ A(1)=B(1) $$
When a curved link is not both strictly convex and monotonic, we assume the curved link’s ideal boundary is split into subcurve intervals that are strictly convex and monotonic. The polar 3 tessellation setup already performs this splitting. The split subcurves are then each approximated by a polyline such that the subcurve and its approximating polyline share common end-points. When a link consists of straight edges only (e.g., a square cap, miter or bevel join, or line segment), a line or polyline exactly represents the boundary so polar tessellation involves no approximation in these cases and no further discussion is warranted (the Fréchet distance is zero so trivially less than 𝑑𝑏).
$$ d _{b}) $$
While the Fréchet distance in its general form demands continuous optimization over arbitrary reparameterizations, our simplifying assumptions make practical statements about the Fréchet distance in the context of polar tessellation possible.
3.6.2 Bounding the Tangent Angle Step to Bound the Fréchet distance. In designing a pixel-space metric, we seek to develop an iterative (non-recursive) process that efficiently computes the “quality knob” maximum tangent angle step threshold 𝑞𝑖 for a link interval 𝑖 that reasonably bounds the maximum pixel-space Fréchet distance between the polyline tessellated by the polar evaluation process for that interval given 𝑞𝑖 and some offset 𝑟 from a link’s generator curve. When filling, 𝑟 = 0, but when stroking, 𝑟 is the stroke radius.
$$ q _{i} $$
$$ q _{i} $$
Adopting the notation of Kilgard [2020c], the setup for polar evaluation determines a function t Ψ,Ψ where [Ψ𝑘, Ψ𝑘+1] is a particular tangent angle interval range [𝑘, 𝑘 + 1] with either all-positive or all-negative curvature within the range (since strictly convex) and an angle change of less than 180° (since monotonic). In this interval range, there is one and only one 𝑡 value, that we call 𝑡𝐹, in this interval with an angle that matches the angle of the chord from p𝑘 to p𝑘+1.
$$ t _{[\Psi _{k},\Psi _{k+1}]}(\psi) $$
$$ \left[\Psi _{k},\Psi _{k+1}\right] $$
$$ \left[k boldsymbol,k+1\right] $$
$$ 180^{\circ} $$
$$ t _{F}, $$
$$ \mathbf{p} _{k} $$
$$ \mathbf{p} _{k+1} $$
As the curve of interval [𝑘, 𝑘 + 1] is strictly convex and monotonic, the interval’s orientation 𝜔 is:
$$ \left[k boldsymbol k+1\right] $$
$$ \omega=\mathfrak{s g n}\bigl(\sin(\Psi _{k+1}-\Psi _{k})\bigr) $$
interval orientation ( −1 or +1_*)
Any point on the interval’s curve is uniquely identified by a triple ⟨𝜃, 𝑡, p⟩ composed of that point’s tangent angle 𝜃, parametric 𝑡, and position p such that g(𝑡) = p𝑡 and g′(𝑡)⋅⟨− sin 𝜃𝑡, cos 𝜃𝑡⟩ = 0 meaning the curve’s gradient is orthogonal to the tangent angle rotated 90°.
$$ \langle\theta,t,\mathbf{p}\rangle $$
$$ \theta, $$
$$ \mathfrak{g}}(t)={\mathfrak{p}} _{t} $$
$$ \mathfrak{g}}^{\prime}(t){\cdot}\langle-\sin\theta _{t},\cos\theta _{t}\rangle=0 $$
Ultimately,weareinterestedinhowwelleverylinkinterval 𝑘 from ⟨Ψ𝑘, 𝑡𝑘, p𝑘⟩ to ⟨Ψ𝑘+1, 𝑡𝑘+1, p𝑘+1⟩ where 𝑡𝑘 𝑑𝑏, we can split the generator and offset subcurves at 𝑡𝐹 and recompute 𝑑𝐹 for the left [𝑎, 𝐹 ] and right [𝐹 , 𝑏] subintervals where 𝐹 = ⟨Ψ𝑘, 𝑡𝑘, p𝑘⟩. We could then recursively explore both the left and right subintervals until 𝑑𝐹 ≤ 𝑑𝑏 for all recursively split subintervals. Then, the maximum tangent angle step threshold 𝑞 to guarantee the pixel-space error bound is the smallest absolute angle difference between 𝜃𝑎 and 𝜃𝑏 for all the encountered subintervals where 𝑑𝐹 ≤ 𝑑𝑏.
$$ d _{F}\leq d _{b} $$
$$ d _{F},d _{b} $$
$$ t _{F} $$
$$ d _{F} $$
$$ [F,b] $$
$$ [a,F] $$
$$ F=\langle\theta _{F},t _{F},\mathbf{p} _{F} \rangle $$
$$ d _{F}\leq d _{b} $$
$$ \theta _{a} $$
$$ \theta _{b} $$
$$ d _{F}\leq d _{b} $$
If subintervals are recursively split in this fashion, how can we reason about the Fréchet distance of the full interval in terms of the resulting multiple subintervals? Lemma 3 in our supplemental document [Kilgard and Barran 2026a] proves that if a strictly convex and monotonic 2D curve is split in two at a common point (as polar tessellation guarantees), the Fréchet distance of the entire curve is the maximum of the Fréchet distance for either of the split curves. Applying this lemma recursively means our recursive process results in a polyline tessellation of the complete interval having a Fréchet distance that is the maximum Fréchet distance of all its constituent subinterval Fréchet distances.
Unfortunately, being recursive, this approach is not practical within a shader—but it is also not necessary.
Because every interval is strictly convex and monotonic, the problematic subintervals where 𝑑𝐹 > 𝑑𝑏 after splitting are regions of lowest curvature. These regions are necessarily on the extrema of the range. So, an iterative approach need only explore, and keep splitting as necessary, the lower curvature subinterval of the two as long as 𝑑𝐹 > 𝑑𝑏 is still true.
$$ d _{F}>d _{b} $$
$$ d _{F}!d _{b} $$
A digression about inner bend cusps: When stroking, there are two subcurve boundaries N and P, each being the negative and positive offset curves from g when 𝑟 > 0 with one being the outer bend and the other being the inner bend depending on 𝜔. If g is strictly convex and monotonic, the outer bend will be too, but the inner bend is prone to cusps for sufficiently large values of 𝑟 so would no longer be strictly convex nor monotonic. We already consider these inner cusp points extraordinary because the facet angle is not bounded here [Kilgard 2020b]. We simply ignore the pixel-space displacement error when straddling such inner cusps (e.g., labeled in Figs. 6 and 7) knowing the error is likely “tucked within” the original curve’s stroke (or join or cap). The easily observable displacement error is on the outer offset and that subcurve stays strictly convex and monotonic.
$$ r>0 $$
3.6.3 Iterative Approach. So, due to the strictly convex and monotonic nature of the subintervals, we can bound the displacement error by simply exploring iteratively the left or right split with the smaller 𝑑𝐹 rather than both sides recursively. Intuitively, it might seem desirable to iterate on the side with the larger 𝑑𝐹 because our goal is to reduce 𝑑𝐹 below the 𝑑𝑏 threshold. However, the smaller 𝑑𝐹 indicates which side has the lower overall curvature. When curvature is high, each iteration reduces 𝑑𝐹 faster, but when curvature is low, 𝑑𝐹 is reduced less proportionally with every iteration. Hence, the side with smaller 𝑑𝐹 is the one to iterate on.
$$ d _{F} $$
$$ d _{F} $$
$$ d _{F} $$
$$ d _{b} $$
$$ d _{F} $$
$$ d _{F} $$
$$ d _{F} $$
$$ d _{F} $$
Warnock starts by initializing an iteration count 𝑗 = 0 and computing O𝐹 and 𝑑𝐹 as described above given 𝑎0 = ⟨Ψ𝑘, 𝑡𝑘, p𝑘⟩ and 𝑏0 = ⟨Ψ𝑘+1, 𝑡𝑘+1, p𝑘+1⟩. If 𝑑𝐹 ≤ 𝑑𝑏, no more iterations are needed. Only 1 step is needed.
$$ a _{0}=\langle\Psi _{k},t _{k},\mathbf{p} _{k}\rangle $$
$$ j=0 $$
$$
_{F} $$
$$ b _{0}=\langle\Psi _{k+1},t _{k+1},\pm b{p} _{k+1}\rangle $$
$$ d _{F} $$
$$ d _{F}\leq d _{b}. $$
Otherwise,compute leftand rightversionsof O𝐹 and 𝑑𝐹 forthe leftand rightside ofthe subinterval split at ⟨Ψ𝐹, 𝑡𝐹, p𝐹⟩. For the left side, compute O𝐹 ,leftand 𝑑𝐹 ,leftfor the left side of the subinterval [𝑎, ⟨Ψ𝐹, 𝑡𝐹, p𝐹⟩]. For the right side, compute O𝐹 ,rightand 𝑑𝐹 ,rightfor the right side of the subinterval [⟨Ψ𝐹, 𝑡𝐹, p𝐹⟩, 𝑏]. If both 𝑑𝐹 ,left≤ 𝑑𝑏 and 𝑑𝐹 ,right≤ 𝑑𝑏, the iteration ends at iteration 𝑗. If not done, then 𝑗 is incremented and the subinterval [𝑎, ⟨Ψ𝐹, 𝑡𝐹, p𝐹⟩] is explored if 𝑑𝐹 ,left< 𝑑𝐹 ,rightand otherwise the
$$ \langle\Psi _{F},t _{F},\mathfrak{p} _{F}\rangle $$
$$ \mathbf{o{} _{F} $$
$$ d _{F} $$
$$ \mathbf{O} _{F,\mathrm{lef}} $$
$$ d _{F,\mathrm{lef}} $$
$$ [a,\langle\Psi _{F},t _{F},\mathbf{p} _{F}\rangle] $$
$$
_{{F,\mathrm{right}}} $$
$$ d _{F,\mathrm{right}} $$
$$ [\langle\Psi _{F},t _{F},\mathbf{p} _{F}\rangle,b] $$
$$ d _{F,\mathrm{left}}\leq d _{b} $$
$$ d _{F,\mathrm{right}}\leq d _{b}. $$
$$ d _{F,\mathrm{left}}<d _{F,\mathrm{right}} $$
$$ [a,\langle\Psi _{F},t _{F},\mathbf{p} _{F}\rangle] $$
57:14
[⟨Ψ𝐹, 𝑡𝐹, p𝐹⟩, 𝑏] is explored. This repeats until 𝑑𝐹 ≤ 𝑑𝑏 is found (or an iteration count is exceeded). In practice, the pixel-space displacement decreases roughly geometrically.
$$ d _{F}\leq d _{b} $$
$$ [\langle\Psi _{F},t _{F},\mathbf{p} _{F}\rangle,b] $$
To determine the maximum tangent angle step threshold 𝑞, we increment the iteration count 𝑗 with each iteration until 𝑑𝐹 ≤ 𝑑𝑏. At each iteration 𝑗 of interval 𝑖, we save 𝑑𝐹 and the sine of the facet angle as (where × is the scalar cross product and V̂ is vector normalization of V):
$$ q _{i} $$
$$ d _{F}\leq d _{b} $$
$$ d _{F} $$
$$ \widehat{\mathbf{v}} $$
$$ \begin{array}{l}{d _{j}=d _{F}} {s _{j}=\sin(\theta _{\mathrm{facet}})=\left|\widehat{\left(\mathbf{O} _{F}-\mathbf{O} _{a}\right)}\times\widehat{\left(\mathbf{O} _{b}-\mathbf{O} _{F}\right)}\right|} \end{array} $$
When the threshold is met, for some terminal iteration 𝑗, Warnock computes an intermediate facet angle with log-linear interpolation (to account for the error decreasing geometrically between the two iterations):
$$ q _{i}=\sin^{-1}\exp _{2}\left(\log _{2}s _{j-1}+{\frac{\log _{2}d _{b}-\log _{2}d _{j-1}}{\log _{2}d _{j}-\log _{2}d _{j-1}}},\left(\log _{2}s _{j}-\log _{2}s _{j-1}\right)\right) $$
(1)
4 With 𝑞𝑖 computed for interval 𝑖, the number of steps Δ𝑖 needed is computed as:
$$ q _{i} $$
$$ \Delta _{i} $$
$$ \Delta _{i}=\left\lceil\frac{|\delta _{i}|}{q _{i}}\right\rceil $$
Fig. 7 shows this error metric applied to the same content as Fig. 6.
The choice to use log-linear interpolation for the facet angle computation (Eq. 1) deserves discussion. Alternatively, we could simply use sin−1 𝑠𝑗 as the facet angle, but this is often too conservative—and tends to cause “power-of-two cascades” in the tessellation. By this we mean, changes in view scaling may cause several intervals to all need more (or less) tessellation in a monolithic jump because one more splitting iteration was needed.
$$ \sin^{-1}s _{j} $$
This is undesirable for two reasons: (1) by scaling up the tessellation quickly due to a cascade, rendering stutters or performance cliffs emerge, and (2) visual popping due to abrupt tessellation changes can happen. We find log-linear interpolation of the facet angle results in more continuous changes in the tessellation level. This has the mild side-effect that, rarely, the maximum pixel-space displacement error bound is not completely strict. It is possible numerically for a pixel-space displacement slightly above 𝑑𝑏 to slip through. When 𝑑𝑏 is already subpixel (Warnock defaults to 0.75), there is no noticeable consequence and the continuous changes in the tessellation level are well worth it. Adjusting 𝑑𝑏 slightly lower would compensate for the introduced numerical inaccuracy.
$$ d _{b} $$
$$ d _{b} $$
$$ d _{b} $$
To understand the dynamics of this pixel-space error metric, our supplemental material includes a video that visualizes the tessellation of the metric and compares it to the maximum turning angle metric. Because the actual pixel displacement error is a distribution of small distances below the bound, a dynamic histogram shows how this distribution changes as the view transform of a path changes.
4 Implementation
The Warnock library is written in C++ using OpenGL. Warnock has bindings for C, C++, and Python. Core to Warnock are its shaders written in GLSL for GPU tessellation and mesh shading to implement polar filling and stroking.
57:15
static shader selectionno output START path contains transform transform control points vertex conic path (x,y) control position anchor position to control shader segments? position position shader transform (x,y,w) control position yes yes position END vertex is vertex ID force w shader dynamic odd? no component to 1 per-vertex selection
Fig. 9. Vertex shader operation for polar GPU tessellation; one vertex per control point.
STARTsetupSTART tessellationpolarPolar setup tessellation does (u,v) solve for “t” control math in § 3.3.4, evaluation classify as no map integer corresponding shader tessellation shader no step to θ 3.3.5, 3.3.6 of an anchor? to θ compute control trivial determine [Kilgard 2020c] point & anchor cull of no link type entire does (u,v) yesevaluate clip codes link? of link compute classify (u,v) classify as Polar setup Polar setup Polar setup outputinvalid? position at “t” control points & level-path of-detail transform math in math in math in §§§ yes anchor parameters anchor position4.2.1, 4.2.2 of 4.2.1, 4.2.2 of 4.2.1, 4.2.2 of [Kilgard [Kilgard [Kilgard to clip space transform position when output output 2020c] 2020c] 2020c] to clip space filling, is no polar path output NaN output anchor link type tessellation level-of-detail poisoned vertex for a cap parameters parameters position position in clip space or join?END yes set level-of-detail ENDtessellation parameters to tessellation control control shader evaluation shader
Fig. 10. Tessellation control (hull) shader operation for polar GPU tessellation; one patch per link.
Fig. 11. Tessellation evaluation domain shader operation for polar GPU tessellation; two evaluated vertices per rib vertex pair ( quad patch) or one vertex per rib ( isoline).
START compute control trivial cull of determine setup task point & anchor entire link link type polar shader clip codes pack? no of link tessellation yes fetch Link Pack Polar setup output output math in § polar control points & 3.3.4, 3.3.5, tessellation parameters 3.3.6 of [Kilgard compute load control points 2020c] number of mesh output & anchor position of shaders needed thread-to-link all links and thread-to-map link map transform all link END control points to task clip space shader
Fig. 12. Task shader for polar GPU tessellation; up to 8 links per work group.
Polar Polar Polar evaluation evaluation evaluation math in math in math in §§§ 4.2.1, 4.2.2 of 4.2.1, 4.2.2 of 4.2.1, 4.2.2 of [Kilgard [Kilgard [Kilgard 2020c] 2020c] 2020c] START map thread to link transform anchor write each map integer solve for “t” mesh and an integer positions anchor position step to θ corresponding shader step to clip space to vertex buffer to θ write triangle fan topology into write other per-write evaluated index buffer and output primitive count per-attribute to vertex buffer to clip space position at “t” outputs optional: optimize END triangle fan topology mesh shader
Fig. 13. Mesh shader for polar GPU tessellation; one thread per rib.
4.1 GPU Tessellation
Fig. 9 shows the flow chart for the vertex shader used for GPU tessellation. Fig. 10 shows the flow chart for the tessellation control (hull) shader used for GPU tessellation. Fig. 11 shows the flow chart for the tessellation evaluation (domain) shader used for GPU tessellation. When in iso-line mode, a simple geometry shader expands each line segment into a triangle pair. Consult Fig. 3 to see how these different shader stages operate within the GPU graphics pipeline.
4.2 Mesh Shading
Fig. 12 shows the flow chart for the task shader used for mesh shading. Fig. 13 shows the flow chart for the mesh shader used for mesh shading. Consult Fig. 4 to see how these task and mesh shader stages operate within the GPU graphics pipeline.
4Using Eq. 12 in § 4.2.1 ( Building a Discrete Interval Range) in Kilgard [2020c].
57:16
tiger cougar dragon star butterfly Arial (TrueType) Pacifico (Type 1) Wingdings (TrueType) dogs girl
Fig. 14. Visualizations of the paths baked in Table 1.
4.3 Bindable Buffers Control Rendering Modes
Uniform buffer bindings control the operation of the polar tessellation process. Warnock relies on ten uniform buffer bindings to control these broad categories of state: settings, surface, transform, paint, pen, polygonal shape, arc length queue, per-pass control, transform correction, and instanced transforms.
To input the link and control point data, GPU tessellation relies on vertex arrays and vertex shader transformation to ingest links as 6-vertex patches; the per-contour anchor is fetched by 5 abusing instancing. One trick for conics is using an odd vertex ID to indicate an extrapolating control point with a 𝑤 component (see Fig. 9). However, mesh shading forgoes vertex arrays and vertex shaders so an additional set of shader storage buffer object (SSBO) bindings bind access to fetching control points, link packs, and per-contour anchors.
4.4 Rasterization, Interpolation, and Shading Care
4.4.1 Rasterization and Interpolation. Warnocktakesconsiderablecareofthefragmentrasterization due to how projective transforms, arc length texturing, and more coverage samples than color 6 samples interact. Warnock has fragment shader functionality to provide perspective-correct or quadrilateral interpolation [Hormann and Tarini 2004] as appropriate.
4.4.2 Position-Invariant Shading. Warnock supports the standard (non-programmable) shading functionality in vector graphics standards for constant color, linear gradient, radial gradient, image gradients, and even two-point conical gradients [Skia team 2021]. We refer to these shading modes as position-invariant in that they depend only on the (𝑥, 𝑦) position of the shaded sample subject to whatever linear transformation is appropriate. Due to the standard “blend once and only once” rule for filling and stroking, the order of rendering is irrelevant for position-invariant shading.
5 Experiments
Our primary experiments investigate the memory footprint of the baked on-GPU paths and how Warnock’s rendering performance broadly compares to alternatives. To further characterize Warnock’s culling and task-level parallelism, our supplemental document [Kilgard and Barran 2026c] characterizes link culling eff




