Skip to content

propellerfactory/headless-gl

Β 
Β 

Repository files navigation

gl

Travis CI Appveyor js-standard-style

gl lets you create a WebGL context in Node.js without making a window or loading a full browser environment.

It aspires to fully conform to the WebGL 1.0.3 specification.

Example

// Create context
var width   = 64
var height  = 64
var gl = require('gl')(width, height, { preserveDrawingBuffer: true })

//Clear screen to red
gl.clearColor(1, 0, 0, 1)
gl.clear(gl.COLOR_BUFFER_BIT)

//Write output as a PPM formatted image
var pixels = new Uint8Array(width * height * 4)
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
process.stdout.write(['P3\n# gl.ppm\n', width, " ", height, '\n255\n'].join(''))

for(var i = 0; i < pixels.length; i += 4) {
  for(var j = 0; j < 3; ++j) {
    process.stdout.write(pixels[i + j] + ' ')
  }
}

Install

Installing headless-gl on a supported platform is a snap using one of the prebuilt binaries. Using npm run the command,

npm install gl

And you are good to go! If your system is not supported, then please see the development section on how to configure your build environment. Patches to improve support are always welcome!

Supported platforms and Node.js versions

gl runs on Linux, macOS, and Windows.

Node.js versions 8 and up are supported.

Note [macOS only]: due to an inadvertant low-level breaking change in libuv's process handling code, this package doesn't return a gl context when running nodejs version 12.13.1 through to 12.16.1, and 13.0.0 through to 13.6.0 on macOS. A fix has been released in Node.js versions 12.16.2 and 13.7.0. Other platforms are unaffected.

To support Node.js versions less than 8, use version 4.2.2 of this package.

API

headless-gl exports exactly one function which you can use to create a WebGL context,

var gl = require('gl')(width, height[, contextAttributes])

Creates a new WebGLRenderingContext with the given context attributes.

Returns A new WebGLRenderingContext object

Extensions

In addition to all the usual WebGL methods, headless-gl exposes some custom extensions to make it easier to manage WebGL context resources in a server side environment:

STACKGL_resize_drawingbuffer

This extension provides a mechanism to resize the drawing buffer of a WebGL context once it is created.

In a pure DOM implementation, this method would implemented by resizing the WebGLContext's canvas element by modifying its width/height properties. This canvas manipulation is not possible in headless-gl, since a headless context doesn't have a DOM or a canvas element associated to it.

Example

var assert = require('assert')
var gl = require('gl')(10, 10)
assert(gl.drawingBufferHeight === 10 && gl.drawingBufferWidth === 10)

var ext = gl.getExtension('STACKGL_resize_drawingbuffer')
ext.resize(20, 5)
assert(gl.drawingBufferHeight === 20 && gl.drawingBufferWidth === 5)

IDL

[NoInterfaceObject]
interface STACKGL_resize_drawingbuffer {
    void resize(GLint width, GLint height);
};

ext.resize(width, height)

Resizes the drawing buffer of a WebGL rendering context

  • width is the new width of the drawing buffer for the context
  • height is the new height of the drawing buffer for the context

STACKGL_destroy_context

Destroys the WebGL context immediately, reclaiming all resources associated with it.

For long running jobs, garbage collection of contexts is often not fast enough. To prevent the system from becoming overloaded with unused contexts, you can force the system to reclaim a WebGL context immediately by calling .destroy().

Example

var gl = require('gl')(10, 10)

var ext = gl.getExtension('STACKGL_destroy_context')
ext.destroy()

IDL

[NoInterfaceObject]
interface STACKGL_destroy_context {
    void destroy();
};

gl.getExtension('STACKGL_destroy_context').destroy()

Immediately destroys the context and all associated resources.

System dependencies

In most cases installing headless-gl from npm should just work. However, if you run into problems you might need to adjust your system configuration and make sure all your dependencies are up to date. For general information on building native modules, see the node-gyp documentation.

headless-gl includes ANGLE as an OpenGL ES 2 implementation with EGL interface. You may choose another library in your system.

Mac OS X

Ubuntu/Debian

$ sudo apt-get install -y build-essential libxi-dev libglu1-mesa-dev libglew-dev pkg-config

Windows

Using a library other than ANGLE

In some cases, ANGLE is not available while other libraries are. For example, Unix-like operating systems except GNU/Linux and Android does have the Mesa 3D Graphics Library even though they are not supported by ANGLE.

The Mesa 3D Graphics Library also supports Wayland or surfaceless platforms.

headless-gl lets you choose another library with pkg-config. Prepare egl and glesv2 package for pkg-config, and set the execution command of pkg-config to npm_config_headless_gl_pkg_config. Typically you can install headless-gl with libraries in your system by typing the following command:

apt install python3-pip pip3 install meson pip3 install https://mesa.freedesktop.org/archive/mesa-20.0.5.tar.xz https://github.com/ninja-build/ninja/releases/download/v1.10.0/ninja-linux.zip https://dri.freedesktop.org/libdrm/libdrm-2.4.100.tar.gz apt install libpciaccess-dev

npm_config_headless_gl_pkg_config=pkg-config npm install headless-gl

FAQ

How can I use headless-gl with a continuous integration service?

headless-gl should work out of the box on most CI systems. Some notes on specific CI systems:

  • CircleCI: headless-gl should just work in the default node environment.
  • AppVeyor: Again it should just work
  • TravisCI: Works out of the box on the OS X image. For Linux VMs, you need to install mesa and xvfb. To do this, create a file in the root of your repo called .travis.yml and paste the following into it:
language: node_js
os: linux
sudo: required
dist: trusty
addons:
  apt:
    packages:
    - mesa-utils
    - xvfb
    - libgl1-mesa-dri
    - libglapi-mesa
    - libosmesa6
node_js:
  - '8'
before_script:
  - export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start

If you know of a service not listed here, open an issue I'll add it to the list.

How can headless-gl be used on a headless Linux machine?

If you are running your own minimal Linux server, such as the one one would want to use on Amazon AWS or equivalent, it will likely not provide an X11 nor an OpenGL environment. To setup such an environment you can choose one of the following configurations:

  1. Use Mesa with surfaceless context
  2. Use ANGLE included in headless-gl, Mesa and Xvfb

Use Mesa with its surfaceless context

Mesa provides what you need to setup headless OpenGL environment, and does not require additional dependencies with notable exceptions of drivers, if your server has GPUs and you are going to utilize them.

It does not support ANGLE_instanced_arrays extension. Check whether your application uses the extension before setup.

Unfortunately, its EGL frontend does not support swrast (its software renderer), but there is an attempt to get it work. See 101397 – [EGL] Surfaceless lacks swrast support.

To use it without X11 server or Wayland, you need surfaceless platform support of its EGL interface. It may not be available in your distribution because it is relatively new (merged in 2015). It could even have been disabled in your distribution because it is not necessary for desktops and. In those cases, build it by yourself by following the official instruction. Do not forget to enable OpenGL ES 2, EGL and surfaceless platform.

To use the installed Mesa for this purpose, follow the instruction of Using a library other than ANGLE section.

Use ANGLE included in headless-gl, Mesa and Xvfb

ANGLE can use Mesa as its backend with GLX. GLX requires X11 server, and Xvfb is a X11 server suitable for headless servers.

While ANGLE_instanced_arrays extension is not supported by the OpenGL implementation of Mesa, ANGLE supports it even if the backend is Mesa.

Interacting with Xvfb requires you to start it on the background and to execute your node program with the DISPLAY environment variable set to whatever was configured when running Xvfb (the default being :99). If you want to do that reliably you'll have to start Xvfb from an init.d script at boot time, which is extra configuration burden. Fortunately there is a wrapper script shipped with Xvfb known as xvfb-run which can start Xvfb on the fly, execute your Node.js program and finally shut Xvfb down. Here's how to run it:

xvfb-run -s "-ac -screen 0 1280x1024x24" <node program>

Does headless-gl work in a browser?

Yes, with browserify. The STACKGL_destroy_context and STACKGL_resize_drawingbuffer extensions are emulated as well.

How are <image> and <video> elements implemented?

They aren't for now. If you want to upload data to a texture, you will need to unpack the pixels into a Uint8Array and feed it into texImage2D. To help reading and saving images, you should check out the following modules:

What extensions are supported?

Only the following for now:

How can I keep up to date with what has changed in headless-gl?

There is a change log.

Why use this thing instead of node-webgl?

Despite the name node-webgl doesn't actually implement WebGL - rather it gives you "WebGL"-flavored bindings to whatever OpenGL driver is configured on your system. If you are starting from an existing WebGL application or library, this means you'll have to do a bunch of work rewriting your WebGL code and shaders to deal with all the idiosyncrasies and bugs present on whatever platforms you try to run on. The upside though is that node-webgl exposes a lot of non-WebGL stuff that might be useful for games like window creation, mouse and keyboard input, requestAnimationFrame emulation, and some native OpenGL features.

headless-gl on the other hand just implements WebGL. It is built on top of ANGLE and passes the full Khronos ARB conformance suite, which means it works exactly the same on all supported systems. This makes it a great choice for running on a server or in a command line tool. You can use it to run tests, generate images or perform GPGPU computations using shaders.

Why use this thing instead of electron?

Electron is fantastic if you are writing a desktop application or if you need a full DOM implementation. On the other hand, because it is a larger dependency electron is more difficult to set up and configure in a server-side/CI environment. headless-gl is more modular in the sense that it just implements WebGL and nothing else. As a result creating a headless-gl context takes just a few milliseconds on most systems, while spawning a full electron instance can take upwards of 15-30 seconds. If you are using WebGL in a command line interface or need to execute WebGL in a service, headless-gl might be a more efficient and simpler choice.

How should I set up a development environment for headless-gl?

After you have your system dependencies installed, do the following:

  1. Clone this repo: git clone git@github.com:stackgl/headless-gl.git
  2. Switch to the headless gl directory: cd headless-gl
  3. Initialize the angle submodule: git submodule init
  4. Update the angle submodule: git submodule update
  5. Install npm dependencies: npm install
  6. Run node-gyp to generate build scripts: npm run rebuild

Once this is done, you should be good to go! A few more things

  • To run the test cases, use the command npm test, or execute specific tests by just running them using node.
  • On a Unix-like platform, you can do incremental rebuilds by going into the build/ directory and running make. This is way faster running npm build each time you make a change.

License

See LICENSES

About

πŸŽƒ Windowless WebGL for node.js

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 65.0%
  • C++ 33.0%
  • Python 1.5%
  • Shell 0.5%