2D GPU renderer for dynamic UIs

Overview

vger

build status Swift Package Manager (SPM) compatible

vger is a vector graphics renderer which renders a limited set of primitives, but does so almost entirely on the GPU. Works on iOS and macOS. API is plain C.

demo

Each primitive can be filled with a solid color, gradient, or texture. vger renders primitives as instanced quads, with most of the calculations done in the fragment shader.

Here's an early screenshot from vger in use for Audulus:

Here's it rendering that svg tiger (the cubic curves are converted to quadratic by a lousy method, and I've omitted the strokes):

Why?

I was previously using nanovg for Audulus, which was consuming too much CPU for the immediate-mode UI. nanovg is certainly more full featured, but for Audulus, vger maintains 120fps while nanovg falls to 30fps on my 120Hz iPad because of CPU-side path tessellation, and other overhead. vger renders analytically without tessellation, leaning heavily on the fragment shader.

vger isn't cross-platform (just iOS and macOS), but the API is simple enough that it could be ported fairly easily. If Audulus goes cross-platform again, I will port vger to vulkan or wgpu.

How it works

vger draws a quad for each primitive and computes the actual primitive shape in the fragment function. For path fills, vger splits paths into horizontal slabs (see vgerPathScanner) to reduce the number of tests in the fragment function.

The bezier path fill case is somewhat original. To avoid having to solve quadratic equations (which has numerical issues), the fragment function uses a sort-of reverse Loop-Blinn. To determine if a point is inside or outside, vger tests against the lines formed between the endpoints of each bezier curve, flipping inside/outside for each intersection with a +x ray from the point. Then vger tests the point against the area between the bezier segment and the line, flipping inside/outside again if inside. This avoids the pre-computation of Loop-Blinn, and the AA issues of Kokojima.

Status

  • Quadratic bezier strokes
  • Round Rectangles
  • Circles
  • Line segments (need square ends for Audulus)
  • Arcs
  • Text (Audulus only uses one font, but could add support for more if anyone is interested)
  • Multi-line text
  • Path Fills.

Installation

To add vger to your Xcode project, select File -> Swift Packages -> Add Package Depedancy. Enter https://github.com/audulus/vger for the URL. Check the use branch option and enter main.

Usage

See vger.h for the complete API. You can get a good sense of the usage by looking at these tests.

Vger has a C interface and can be used from C, C++, ObjC, or Swift. vgerEncode must be called from either ObjC or Swift since it takes a MTLCommandBuffer.

See the demo app for an example of using vger in a iOS/macOS SwiftUI app. vger includes VgerView to make it really easy to use Vger within SwiftUI:

import SwiftUI
import vger      // C/C++/ObjC interface.
import vgerSwift // Swift nicities.

struct HelloView: View {

    let cyan = SIMD4<Float>(0,1,1,1)

    var body: some View {
        VgerView(renderCallback: { vger in
            vgerText(vger, "Hello world. This is V'Ger.", cyan, 0)
        })
    }
}
Issues
  • Missing antialiasing on some edges in VgerDemo...

    Missing antialiasing on some edges in VgerDemo...

    I noticed it in VgerDemo on iPad Pro 11 from 2018, and ipadOS 14.8 This also happens on very simple svg, like this: <path d='M10,10v50h50z' fill='#22ff22'/>

    IMG_344AD2AF55DD-1

    opened by luckyclan 20
  • GPU path

    GPU path "scanning"

    Currently to render path fills efficiently, vger "scans" the path (see vgerPathScanner) and divides it into horizontal slabs on the CPU. This is the most significant CPU expense for rendering SVGs.

    Another option would be to generate this acceleration information on the GPU. A thread group would process a single path and compute a grid, where each square (or tile) contains a list of the relevant segment indices.

    In the current CPU implementation, a detailed path can have many slabs:

    image

    This is challenging for the GPU since each path would need handling at a different resolution.

    opened by wtholliday 2
  • tile-based rendering

    tile-based rendering

    I've implemented an experimental tile-based pipeline.

    How it works

    Instead of rendering primitives, the fragment function (vger_tile_fragment) adds commands to Tiles. I use raster_order_group to ensure the commands are entered in draw order (no need to deal with atomic operations or sorting :). Each tile is 16x16 pixels and is computed using a kernel (vger_tile_render).

    Issues

    • Tile overflow. Tiles are fixed size. What happens when too many commands are added to a tile? Could use a linked list for tiles instead of fixed buffers. For now I've put off this problem by not storing path cvs in the tile buffer.
    • Transformations. Bezier paths can be transformed by transforming their control points, but what about other prims? Would the prim command for round-rect need an inverse transform to get back to local space to compute the df? And then what about AA, since df's aren't preserved by affine transformations? Or should vger convert the other prims to paths? Where should that conversion happen?
    • Small complex paths: a single glyph might fit into a 16x16 tile, which would mean each tile pixel would be tested against all segments of the glyph. The slab-based renderer wouldn't suffer from this issue, as the glyph would still be divided into slabs to minimize tests.

    An alternative?

    The tile rendering is just to speed up paths without using any CPU. Primitives such as rounded rectangles are so cheap they can be rendered well using the standard GPU pipeline. Could some GPU computation be done for paths to speed up their rendering while still using the normal pipeline? This would probably involve computing slabs for each path on the GPU.

    opened by wtholliday 1
  • vertical centering of text isn't correct

    vertical centering of text isn't correct

    Running testTextAlign yields:

    image

    The text is lower than it should be relative to the magenta dot which is the origin. Seems that alignOffset is returning the wrong offset along the y-axis.

    My understanding of the typographic bounds is based on this:

    from here

    Vertical center should be at (ascent - descent)/2. Thus offset to move it down to the x-axis would be (descent - ascent) / 2.

    opened by wtholliday 1
Owner
Audulus LLC
Audulus LLC
A toy renderer written in C using Vulkan to perform real-time ray tracing research.

This is a toy renderer written in C using Vulkan. It is intentionally minimalist. It has been developed and used for the papers "BRDF Importance Sampl

Christoph Peters 250 Jun 27, 2022
physically based renderer written in DX12 with image-based lighting, classic deffered and tiled lighting approaches

Features Classical Deferred Renderer Physically Based shading Image Based Lighting BRDF Disney model (Burley + GGX) Tangent space normal mapping Reinh

Alena 35 Jun 2, 2022
PainterEngine is a application/game engine with software renderer,PainterEngine can be transplanted to any platform that supports C

PainterEngine is a application/game engine with software renderer,PainterEngine can be transplanted to any platform that supports C

DBinary 1.4k Jun 28, 2022
work in progress 3d renderer based on sdl2

work in progress 3d software renderer based on SDL. (Only supports wireframe view for now) Building On Linux, install libsdl2 and then run the folowin

null 4 Sep 12, 2021
work in progress 3d renderer based on sdl2

work in progress 3d software renderer based on SDL. (Only supports wireframe view for now) Building On Linux, install libsdl2 and then run the folowin

Jayachandra Kasarla 4 Sep 12, 2021
Ipsys Particle System Yey letS go, very cool particle system generator and fast renderer

ipsys - Ipsys Particle System Yey letS go About Ipsys is a piece of software that focuces on running and displaying cool randomly generated particule

Anima Libera 5 May 26, 2022
A modern C++ physically based renderer

The Dakku Renderer Warning: This project is currently under developing and does not guarantee any consistency. About Dakku is a physically based rende

xehoth 6 Apr 15, 2022
A Simple Spectral Renderer

Simple Spectral This is a simple multithreaded spectral pathtracer implementing the algorithm (linear combination of bases) described in our EGSR 2019

Ian Mallett 156 May 13, 2022
Source code for pbrt, the renderer described in the third edition of "Physically Based Rendering: From Theory To Implementation", by Matt Pharr, Wenzel Jakob, and Greg Humphreys.

pbrt, Version 3 This repository holds the source code to the version of pbrt that is described in the third edition of Physically Based Rendering: Fro

Matt Pharr 4.2k Jul 2, 2022
An immediate-mode, renderer agnostic, lightweight debug drawing API for C++

Debug Draw An immediate-mode, renderer agnostic, lightweight debug drawing API for C++. License This software is in the public domain. Where that dedi

Guilherme Lampert 433 Jun 25, 2022
A dx12 river renderer using wave particles with interactive vortices.

Wave Particles with Interactive Vortices Final Result Overview In game industry water can be divided into two domains, ocean and river. This project f

ACskyline 201 Jun 27, 2022
Minimal A* implementation in C. No dynamic memory allocation.

Micro A Star Path Finder This is a minimal A* path finder implementation in C, without any dynamic memory allocation. Usage The maximum size of the ma

Felipe da Silva 76 Jun 11, 2022
Sketch-Based Streaming Anomaly Detection in Dynamic Graphs

AnoGraph Implementation of Sketch-Based Streaming Anomaly Detection in Dynamic Graphs. Siddharth Bhatia, Mohit Wadhwa, Philip S. Yu, Bryan Hooi Existi

Stream-AD 51 May 10, 2022
Plot dynamic 3d functions z = f(x, y, t)

A tool for plotting 3D functions Controls Button Description Arrows Rotate view F Enable/Disable filling surface faces G Enable/Disable showing coordi

Boris Starkov 2 Oct 15, 2021
Dissecting the M1's GPU for 3D acceleration

Asahi GPU Research for an open source graphics stack for Apple M1. wrap Build with the included makefile make wrap.dylib, and insert in any Metal appl

Asahi Linux 927 Jun 22, 2022
nsfminer is an Ethash GPU mining application: with nsfminer you can mine every coin which relies on an Ethash Proof of Work.

nsfminer (no stinkin' fees) Ethereum (ethash) miner with OpenCL, CUDA and stratum support nsfminer is an Ethash GPU mining application: with nsfminer

Jean M. Cyr 510 Jun 21, 2022
Software ray tracer written from scratch in C that can run on CPU or GPU with emphasis on ease of use and trivial setup

A minimalist and platform-agnostic interactive/real-time raytracer. Strong emphasis on simplicity, ease of use and almost no setup to get started with

Arnon Marcus 44 May 18, 2022
This is a openGL cube demo program. It was made as a tech demo using PVR_PSP2 Driver layer GPU libraries.

OpenGL Cube Demo using PVR_PSP2 Driver layer GPU libraries This is a openGL cube demo program. It was made as a tech demo using PVR_PSP2 Driver layer

David Cantu 5 Oct 31, 2021
What I'm doing here is insane GPU driver prototype for @GreenteaOS

NjRAA Work-in-progress Driver Foundation [nee-jee-ray] What I'm doing here is a GPU driver for Linux as a prototype for future graphics stack of the @

Miraculous Ladybugreport 4 Jan 22, 2022