NV_path_rendering is an OpenGL extension for GPU-accelerated path rendering. Recent functionality improvements provide better performance, better typography, rounded rectangles, conics, and OpenGL ES support. This functionality is available today with NVIDIA's 337.88 drivers.
The latest NV_path_rendering specification documents these new functional improvements:
https://www.opengl.org/registry/specs/NV/path_rendering.txt
You can find sample code here:
https://github.com/markkilgard/NVprSDK
2. Motivation for Improvements
• Make NV_path_rendering extension a
better match for web usage
– For Skia, Chromium browser, and web
standards generally
• Better performance
– Driven by profiling & usage experience
• OpenGL ES support
– NV_path_rendering intended for non-subset
OpenGL functionality (full OpenGL 4.4)
3. New Functionality
• More efficient GL commands
– One command for “stencil then cover”
– 2D matrix commands
• New path commands
– Rational quadratics
– Rounded rectangles
• Path objects from font’s glyph indices
• OpenGL ES support
4. Single Command
“Stencil then Cover”
• glStencilThenCover{Fill,Stroke}PathNV
– Does glStencil{Fill,Stroke}PathNV, then
glCover{Fill,Stroke}PathNV
– On the same path object
• Also instanced versions
– glStencilThenCover{Stroke,Stroke}PathInstancedNV
• 100% functionally identical to just calling
equivalent stencil & cover commands
sequentially
– (Only different if there is erroneous usage)
• Any error ignores steps of the command
5. Single Command
“Stencil then Cover” Details
• Minor performance advantage
– Halves object locking and name lookup overhead
– Instanced versions “display list” well since only one
set of per-path transform values
• Advice to programmers
– Easy to adopt if you keep your glStencil*Path* and
glCover*Path* commands in the same function
– Easy to emulate for older driver
• Just register helper function that calls old commands
sequentially
6. Single Command
“Stencil then Cover” API
• void glStencilThenCoverStrokePathNV
(GLuint path,
common path object
GLenum StrokeMode, GLuint mask,
GLenum coverMode);
• void glStencilThenCoverStrokePathNV
(GLuint path,
common path object
GLint reference, GLuint mask,
stencil params
GLenum coverMode);
cover params
stencil params
cover params
9. More Compact/Efficient 2D Matrix
Updates
• Existing OpenGL matrix load and multiply
assume 4x4
• But most path rendering relies on simpler 2D
matrix forms
– 3x2 affine, 3x3 projective
• Advantages of Compact 2D Matrix Commands
– Easier to process and analyze
– Smaller in display lists
– Selector-free, no glMatrixMode dependency
• Based on EXT_direct_state_access approach
• Easy to emulate for older drivers
– Substitute with 4x4 EXT_direct_state_access functions
11. Compact Matrix Commands by API
Standard Type Component order Corresponding Load command
Skia SkMatrix [0,1,2]
[3,4,5]
[6,7,8]
glMatrixLoadTranspose3x3fNV
SkScalar [6] [0,2,4]
[1,3,5]
glMatrixLoad3x2fNV
Cairo cairo_matrix_t [0,2,4]
[1,3,5]
glMatrixLoad3x2fNV
Qt QMatrix [0,2,4]
[1,3,5]
glMatrixLoad3x2fNV
OpenVG VGfloat [9] [0,3,6]
[1,4,7]
[2,5,8]
glMatrixLoad3x3fNV
Direct2D D2D_MATRIX_3X2_F [0,2,4]
[1,3,5]
glMatrixLoad3x2fNV
12. Rational Quadratic Path
Commands
• Inspired by Skia support
– Rational quadratics allow circular, elliptical arcs, and hyperbola
• Also known as conic curves
• Instead of just parabolas
• Easy to support, just 2 new paths commands
– GL_CONIC_CURVE_TO_NV (0x1A)
• 5 coordinates
– [ x, y, w, x, y ]
– First (x,y,w) is extrapolating control point
– Second (x,y) is interpolating end point
– GL_RELATIVE_CONIC_CURVE_TO_NV (0x1B)
• 5 coordinates
– [ dx, dy, w, dx, dy ]
13. GL_CONIC_CURVE_TO_NV
Details
• Normal GL_QUADRATIC_CURVE_TO_NV
– Takes four scalar components
• (P1x,P1y,P2x,P2y)
– With end-point of the last path command, these
provide three control points:
• (P0x,P0y), (P1x,P1y), (P2x,P2y)
• Rational quadratic version supports quadratics
– Call this command GL_CONIC_CURVE_TO_NV
• Google wants this, and for good reason
– Takes five scalar components
• (P1x,P1y,P1w,P2x,P2y)
– Make 3 homogeneous control points
• (P0x,P0y,1), (P1x,P1y,P1w), (P2x,P2y,1)
14. Partial Circular and Elliptical Arcs
• Rational quadratic Bezier curves can be
drawn if we support perspective rendering
of quadratic Bezier segments
neat!
should extend
to ellipses
15. Conics Details
• If the interpolating control points (P0 & P2) have unit W
values
– Meaning if P0w and P2w are both 1.0
• Then P1w controls the type of conic generated
– P1w = 1 generates a parabolic segments
• Basically a normal integral (non-rational) quadratic Bezier segments
– P1w > 1 generates a hyperbolic segment
• A portion of a hyperbola
– P1w < 1 generates a partial elliptical or circular arc
• To maintain the convex hull property, we need to avoid
negative values for P1w
– So use the absolute value of the coordinate for P1w
17. Rounded Rectangles
• Very common primitive on web pages
– Standardized by “
CSS Backgrounds and Borders Module Level 3” specification
– Google cites rounded rectangles as the only “non-trivial” paths in
most web pages
• Already have GL_RECT_NV path command
– PDF standardizes this path command
• Rationale for first-class support
– Common in web content
– Faster to bake
– Faster to render
– Easy parameterization, more compact to specify
• Represents sequence of 4 lines and 4 arcs
19. Rounded Rectangle
Circular Corners
• Rounded rect = 8 segment spline
– Four linear segments for edges
– Four 90 degree arcs at rounded corners
(x,y)
height
corner radius corner radius
corner radius
corner radius
width
radius can
be per-rectangle
or per-corner
20. Rounded Rectangle
Elliptical Corners
• Rounded rect = 8 segment spline
– Four linear segments for edges
– Four 90 degree arcs at rounded corners
(x,y)
height
width
y radius
x & y elliptical
radii can
be per-rectangle
or per-corner
x radius
y radius
x radius
x radius
x radius
y radius y radius
22. Glyph Index Font Support
Motivation
• Problem
– Existing NV_path_rendering allows glyphs to be created from a font
based on Unicode character point
– Very handy/useful for “toy” or “simple” text layout
• Advantage of Unicode approach: multiple font faces can “overlap” to
provide fallback to some supported glyph
– BUT quite insufficient for sophisticated text layout
• Browsers definitiely need sophisticated text layout
• Solution
– Add glyphs created based on font glyph index
– Facilities sophisticated text layout
• Awareness: Application request a specific font face and have
avaialble the font’s metrics and shading rules
– Note: NV_path_rendering does NOT provide this information
– Apps are expected to get it from the font directly
• Natural to use FreeType 2 + Harfbuzz for this
23. Glyph Index-based Path
Specification API
• Two commands
– GLenum glPathGlyphIndexArrayNV(
GLuint firstPathName,
GLenum fontTarget,
const void *fontName,
GLbitfield fontStyle,
GLuint firstGlyphIndex,
GLsizei numGlyphs,
GLuint pathParameterTemplate,
GLfloat emScale);
• Mimic glPathGlyphRangeNV but indexing of the font face is glyph indices rather than
Unicode character points
– GLenum glPathMemoryGlyphIndexArrayNV(
GLuint firstPathName,
GLenum fontTarget,
GLsizeiptr fontSize,
const void *fontData,
GLsizei faceIndex,
GLuint firstGlyphIndex,
GLsizei numGlyphs,
GLuint pathParameterTemplate,
GLfloat emScale);
• Like glPathGlyphIndexArrayNV but allows for in-memory font file for font face
24. Glyph Index-based Path
Specification Discussion
• App or library decides how glyph indices are arranged in
path object name space
– Example: Glyph indices can be arranged to match Skia’s
fallback font ordering of glyph indices
• Assumes app has a-priori knowledge of the number of
glyphs in the font face
• glPathMemoryGlyphIndexArrayNV: in-memory font
data needed is copied
– At least the font data needed to maintain the glyph outlines
– Not referenced
– Works like FreeType’s FT_New_Memory_Face
• Expectation is app will use FT_New_Memory_Face for it’s a-prior
knowledge of glyph count, metrics, etc.
25. Extra Glyph Index Range with
Allocation Command
• Generates range of glyphs for a particular font
– Good if you don’t know how many glyph indices there
might be in a font
• (But you probably know that if you are shaping your own text)
– GLenum glPathGlyphIndexRangeNV (
GLenum fontTarget,
const GLvoid *fontName,
GLbitfield fontStyle,
GLuint pathParameterTemplate,
GLfloat emScale,
GLuint baseAndCount[2]);
first path object ID &
count returned here
• Like calling glGenPathsNV for the font’s glyph index
count, and then populating the range with
glPathGlyphIndexArrayNV
29. OpenGL ES 2/3 Support
• NV_path_rendering
– Assumes modelview/projection matrix
– Assumes fragment shader only operates during “cover” step
– Relies on generating varying fragment values on linear function
of object-space path coordinates
• Similar to fixed-function glTexGen’s operation
• Problem: Required vertex shader in ES
– ES2 eliminates fixed function
– ES2 requires vertex & fragment shaders to be paired
• No fragment shaders alone
• No separate shader objects (is an EXT extension though)
• ES2 & ES3 eliminates API machinery
NV_path_rendering relies on for path transformation and
shading
30. OpenGL ES 2/3 Support Goals
• Invent as little new API as possible
– Leverage existing extensions
• EXT_separate_shader_objects
• EXT_direct_state_access
• ARB_program_interface_query
– Reuse token values and match prototypes for matrix commands
• Same NVpr code for ES, Core Profile, and Compatibility
Profile
• Rationale
– Developers don’t like “same, only different” APIs
– Testing effort easier
– Re-use is less controversial than invention
31. Proposed NVpr for ES Solution
• Add back into ES 2.0 and 3.x
– Transformation state
• Modelview and projection transforms
– Rely on selector-free matrix routines from
EXT_direct_state_access for this
– Clip planes operating in eye-space
• Leverage (assume/require!) separate shader
objects (SSO) functionality
– Currently ES 2.0/3.0 extension
• EXT_separate_shader_objects
– Slated for inclusion in ES 3.1 standard
32. Varying Fragment Input Generation
for “Cover” Step
• ES lacks fixed-function fragment inputs
– So NVpr’s glPathTexGen*NV, etc. APIs cannot drive
inputs
• So add generation command for GLSL fragment
inputs
– void glProgramPathFragmentInputGenNV(
GLuint program,
GLint location,
GLenum genMode,
GLint components,
const GLfloat *coeffs);
33. ES “Cover” Fragment Shader
Usage Notes
• Use “layout” qualifiers to assign locations to fragment
inputs
– Example: layout(location=0) int vec2 st;
– SSO introduces layout qualifiers for every shader domain
• Prior to SSO, just layout locations just allowed for the vertex shader
• ARB_program_interface_query is useful related
extension
– Allows programmatic querying of locations for fragment program
inputs
• When fragment shader is “first” domain in the SSO pipeline program
– Provides introspection when explicit layout locations not used in
the shader or shader is from an “outside” source
34. ES “Cover” Fragment Shader
Example
• Complete example for radial gradient:
– #version 300 es
layout(location=0) in vec2 st;
uniform sampler1D ramp;
uniform vec4 color;
void main() {
gl_FragColor = color*texture(ramp, length(st));
}
• Driving the “st” varying
– GLfloat params[3][3] = {
/* radial gradient linear coefficients */ };
glProgramPathFragmentInputGenNV(radGradProg,
/*location*/0, GL_OBJECT_LINEAR, 2,
¶ms[0][0]);
– Generation state is per-program
• (not per-GL context)
35. ES Matrix Additions
• Require EXT_direct_state_access (DSA) matrix functions be available
– When NV_path_rendering exposed on ES
– (Doesn’t require DSA itself)
• Matrix commands:
– glMatrixLoadfEXT, glMatrixLoaddEXT, glMatrixMultfEXT, glMatrixMultdEXT,
glMatrixLoadIdentityEXT, glMatrixRotatefEXT, glMatrixRotatedEXT, glMatrixScalefEXT,
glMatrixScaledEXT, glMatrixTranslatefEXT, glTranslateMatrixdEXT, glMatrixOrthoEXT,
glMatrixFrustumEXT, glMatrixPushEXT, glPopMatrixEXT
• Matrix values should be GL_PATH_PROJECTION_NV or
GL_PATH_MODELVIEW_NV
– Aliases (same token values) for GL_MODELVIEW and GL_PROJECTION
– No other matrices included (texture matrix, color matrix)
• Includes matrix stack for both these matices
– Important to commands can be rendered with respect to other views
• Unresolved
– Reintroduce built-in variables for these so non-NVpr rendering can reference the same
matrices?
• Likely YES, otherwise hard for non-NVpr rendering to be consistent
• gl_PathModelviewMatrixNV, gl_PathProjectionMatrixNV
– Reintroduce a glPathClipPlane (and glPathClipRect) for clip plane usage?
• Likely YES
36. Approach to Additions
• Simply extend exist NV_path_rendering with new
functions and tokens
– No new extension; documented as minor revisions in
specification
– Detect minor update by querying if new command functions exist
– Or detecting errors from new tokens
• Rationales
– Just adding functionality; fully backward compatible
– Few actual users of NV_path_rendering today
– None of these additions tied to actual hardware features
– Stuff NV_path_rendering really “should have always had”
– Relative to emulate the lack of these features
37. Availability
• In latest drivers (now public)
– Single command “StencilThenCover”
– 2D matrix commands
• Glyph index support
– Implemented
• Conic curves & round rectangles
– Implemented
• OpenGL ES support
– Implemented
• In 337.88 public drivers circa June 2014