Overview
- Background
- hardware (GPUs)
- software (OpenGL)
- LambdaCube 3D
- motivations, usage, components, plans
- Demo
Hardware background
Trends driving GPU development
Main trend: Migrate computationally intensive work from CPU to GPU
- by adding special hardware elements
- by unifying GPU hardware elements to be more general purpose
Work migrated from CPU to GPU
- 80’s
- sprites
- line drawing
- filling
- blending (transparency)
- mid 90’s
- 96: texturing, clipping
- 99: 3D vertex transformations
- 00’s
- real time decompression / compression of data streams
- 2001: programmable shading
- shadow mapping
- bump mapping
- 2007: GPGPU
- computational finance
- biochemistry
- climate modelling, …
- 10’s
- tesselation
- global illumination
Other trends in GPU development
- memory closer to computation
- more hierarchical design (see figure)
- desktop and mobile GPUs are getting closer
- more tight CPU - GPU integration
- bigger displays (resolution, color depth, HZ, number of displays drivable from one card)
Software background
GPU API
- Main motivation
- have a common interface for lots of different GPUs
- How it works
- missing features on a specific GPU are emulated on CPU
OpenGL
Currently OpenGL is the only cross-language, multi-platform API for GPU graphics.
Scope:
- 2D and 3D vector graphics
- some general purpose GPU programming (compute shaders)
OpenGL (2)
- History
- Development started in 1991, by Silicon Graphics Inc.
- Currently is managed by the non-profit technology consortium Khronos Group.
- Languages
- Primarily for C language, but has many language bindings
- Platforms
- desktop: iOS, Linux, Windows, …
- OpenGL ES: for embedded systems (mobile devices)
- WebGL: JavaScript binding for browsers (Chrome, Firefox, Safari, Opera, IE, BlackBerry, Maemo, Tizen, …)
- Versions
1.0, 1.1, 1.2, 1.2.1, 1.3, 1.4, 1.5, 2.0, 2.1, 3.0, 3.1, 3.2, 3.3, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5
- Implementations (a.k.a. drivers)
- by graphics card manufacturers
- open source drivers
OpenGL architecture and usage
OpenGL is a state-machine whose state is called pipeline.
The pipeline is an abstract model of the configured GPU
(the data is loaded into the GPU memory but the computation did not begin)
Two different group of OpenGL operations:
- pipeline setup (operations which modify the pipeline)
- pipeline execution (draw call)
Typical sequence of operations of an application:
- initial pipeline setup
- pipeline execution
- put the result onto the screen (not part of OpenGL)
- wait for user input (not part of OpenGL)
- pipeline modification
- go back to 2.
OpenGL pipeline
- some parts of the pipeline are configurable
- some parts of the pipeline are programmable (configurable by a program; blue in figure)
The configuration programs are called shaders,
i.e. shaders are programs running on the GPU
Shaders
GLSL: the language specified for shaders in OpenGL
- a C like language
- the same language for all OpenGL language bindings
- no real procedure calls because there is no stack on GPU
- limited procedure calls are emulated by inlining / using registers;
limitation: call graph should be known statically
- branches (
if-then-else
) and loops (while
and for
) are possible
Steps for processing GLSL source code:
- the application provides GLSL code as a string (usually hand written)
- the driver compiles it to GPU machine code (usually at runtime)
- the code is uploaded to the GPU with specific OpenGL commands (at runtime)
LambdaCube 3D
Motivations
Main goal: cross-platform GPU graphics in a statically typed functional language
LambdaCube 3D layers
Layers and design decisions:
- OpenGL backend for various architectures
- Intermediate Representation (IR)
- data type for OpenGL command sequences
- interpreted with OpenGL command calls
- functional OpenGL API
- written in a Haskell-like language
- OpenGL constraints are expressed in the type system
- OpenGL state machine is replaced by ADT expressions
- shaders are expressions with function type (
input -> output
)
- compiled to IR
- high-level layer on top of the functional OpenGL API
- library in the same language as the functional OpenGL API
- intended for use by application developers
- developed by need
State machine vs. ADT expressions
A state machine is fed by a sequence of state modification operations
- each operation modifies one part of the state
- easy to express mutations of state
An ADT expression is built up by constructors
- ADT stands for Algebraic Data Type (a kind of composite type)
- each ADT constructor builds a substate from smaller substates
- easy to reuse substates
- immutability prevents unexpected mutations
- needs optimization to reach the same performance as with the state-machine approach
Use strong static typing
- Language construct used:
- ADTs: the type of argument substates are constrained
- GADTs: the type of the result substate can depend on the constructor and the type of arguments used
- type classes
- type families
- example
Result: all OpenGL specification constraints are expressed in the type system
i.e. if the type checking succeeds at compile time, we have a valid pipeline at runtime
Development history of LambdaCube 3D
2009 |
begin to work on an Ogre3D compatible engine in Haskell |
2011 |
public API of the engine as a Haskell EDSL |
2012 |
redesigned, more functional EDSL which was ispired by GPipe |
2013 |
LambdaCube Intermediate Representation (IR) was introduced for platform independence |
2015 March |
begin to work on a separate DSL with a compiler |
2015 May |
begin to work on a web-based editor |
2015 end of May |
begin LambdaCube 3D Europe Tour |
Integration into applications
LambdaCube 3D language
Scope:
- functional OpenGL API
- high-level library on top of the functional OpenGL API
Main abstractions used: GADTs, functions, type classes
Language specification
Haskell98 (with some diversions) + various extensions
Main diversion: different Prelude
more
LambdaCube 3D Prelude
- no
IO
monad
- builtins for the functional OpenGL API
- GADTs
- primitive operations used in shaders
- utility functions (
id
, foldl
, …)
data FrontFace
= CW
| CCW
data CullMode
= CullFront FrontFace
| CullBack FrontFace
| CullNone
data RasterContext (a :: PrimitiveType) where
TriangleCtx :: CullMode -> PolygonMode -> PolygonOffset -> ProvokingVertex -> RasterContext Triangle
PointCtx :: PointSize -> Float -> PointSpriteCoordOrigin -> RasterContext Point
LineCtx :: Float -> ProvokingVertex -> RasterContext Line
builtins
PrimAnd, PrimOr, PrimXor :: Bool -> Bool -> Bool
PrimAdd, PrimSub, PrimMul :: (t ~ MatVecElem a, Num t) => a -> a -> a
Compiler
- written in Haskell
- built from scratch
Plans
Plans for the second half of 2015
- port Quake example
- add tutorial & documentation
- organize a game jam
- develop a small, real game
- get feedback & plan next phase