Awesome
Pumex library
The purpose of the Pumex library is to create an efficient and universal rendering engine using Vulkan API that has following properties :
- enables multithreaded rendering on many windows ( or many screens ) at once, may use many graphics cards in a single application
- uses render graph allowing for complete customization of a renderer. Pumex is not tied up to any particular rendering method, like deferred rendering, direct plus rendering, etc. In fact the user is able to implement any of these methods himself fairly quickly.
- decouples rendering stage from update stage and enables update step with constant time rate independent from rendering time rate
- uses modern C++ ( C++11 to C++17 ) but not overuses its features if it's not necessary
- works on many platforms: currently Windows, Linux and Android operating systems are supported. Optionally you may also render to QT windows on Linux and Windows.
- implements efficient rendering algorithms ( like instanced rendering with vkCmdDrawIndexedIndirect() to draw many objects of different types with one draw call )
Quick preview on Youtube :
You can follow library development on Twitter .
Library architecture
This paragraph assumes that reader knows Vulkan specification.
Every Pumex application consists of three distinct layers of objects :
- first layer is responsible for creation and configuration of Vulkan instance, logical devices, surfaces and windows. Let's call it a device layer. Below you may see an example of such layer.
-
second layer is called a render graph ( also known in literature as frame graph ). Each Vulkan surface rendered by the application may use one or more render graphs. Render graphs may be shared between surfaces ( see: image above ).
Render graph defines render operations and inputs/outputs between them. During application run abstract render graph is compiled into a set of Vulkan objects required to render a scene: graphics passes and subpasses ( with its attachments and dependencies ), compute passes, images, buffers, attachments and pipeline barriers. These objects are then used to build a primary command buffers.
Each render graph may use one or more Vulkan queues for its execution.
An example of render graph for a simple deferred renderer with depth prepass is shown below.
- third layer is called a scene graph. Every render operation ( graphics subpass from image above ) has its own scene graph. All nodes in a scene graph derive from pumex::Node class and can be categorized as follows :
- pipelines defining render state such as used shaders, culling, blending, depth test state, etc ( pumex::GraphicsPipeline, pumex::ComputePipeline )
- nodes that store vertex and index data ( pumex::AssetBufferNode, pumex::AssetNode, pumex::DrawVerticesNode )
- nodes that perform vkCmdDraw calls ( pumex::AssetBufferDrawNode, pumex::AssetBufferDrawIndirectObject, pumex::AssetNode, pumex::DrawVerticesNode, pumex::Text ) - these nodes are leafs in a scene graph
- node that performs vkCmdDispatch in compute operations ( pumex::DispatchNode )
- helper nodes ( pumex::Group, pumex::AssetBufferFilterNode )
Each node may have descriptor sets connected to it. Descriptor sets consist of images and buffers along with their GPU representation ( whether they should be treated as uniform buffers, storage buffers, sampled images, samplers, etc.).
By default the scene graph is included into primary command buffer building, but subgraphs may be moved to secondary buffers ( as long as secondary buffers include graphics pipeline / compute pipeline - this is Vulkan requirement ). Secondary command buffers may be built/rebuilt in parallel to each other.
Scene graph shown below is connected to the "lighting" operation from image above. First graphics pipeline to the left defines shaders that use gbuffers as input attachments. As a result, pumex::AssetNode draws a fullscreen triangle that uses gbuffers to render lighting. Second and third graphics pipelines render statistics GUI: pumex::DrawVerticesNode draws rectangles representing CPU timing of different rendering stages. pumex::Text nodes render FPS counter and names of rendering stages.
Articles discussing various features of the library
Basic tutorial : rendering single 3D object
How does main render loop work
Multithreaded cooperation between render stage and update stage
Memory buffers and images in detail
Asset class and its components
Pumex examples
Pumex library comes with a set of examples implementing different aspects of it. Each of the examples accepts following options from command line :
-h, --help display this help menu
-d enable Vulkan debugging
-f create fullscreen window
-p [presentation_mode] presentation mode (immediate, mailbox, fifo, fifo_relaxed)
-u [update_frequency] number of update calls per second
Default value for presentation mode is mailbox ( = VK_PRESENT_MODE_MAILBOX_KHR ).
While each example is running , you are able to use following inputs :
-
W, S, A, D, Q, Z - move camera : forward, backward, left, right, up, down
-
Left Shift - move camera faster
-
LMB - rotate camera around origin point
-
RMB - change distance to origin point
-
F4 - change application statistics mode. Available modes are : "no statistics", "FPS counter", "CPU stats"
-
F5, F6 - change time scale in "CPU stats" mode
-
F7, F8 - show less / more frames in "CPU stats" mode
pumexcrowd
Application that renders a crowd of 500 animated people on one or more windows.
Application presents :
-
how to utilize compute operation in a render graph.
-
how to use output storage buffer from compute operation as input indirect buffer in a following render operation
-
how to use instanced rendering nodes like pumex::AssetBufferFilterNode and pumex::AssetBuffer
-
how to store textures in texture array and use texture array during instanced rendering
- There are 3 different models of human body, each one has 3 LODs ( levels of detail ) :
- LOD0 has 26756 triangles
- LOD1 has 3140 triangles
- LOD2 has 1460 triangles
- Skeleton of each model has 53 bones
- Each body has 3 texture variants
- Each model has 3 different sets of clothes ( also 3D models ). Each cloth has only 1 LOD.
- Each model randomly chooses one of four provided animations.
Apart from standard command line parameters pumexcrowd example uses also following ones :
-v create two halfscreen windows for VR
-t render in three windows
Below is additional image showing pumexcrowd example working in VR mode ( 2 windows - each one covers half of the screen, window decorations disabled ) :
pumexgpucull
Application that renders simple not textured static objects ( trees, buildings ) and dynamic objects ( cars, airplanes, blimps ) on one or more windows.
This application serves as performance test, because all main parameters may be modified ( LOD ranges, number of objects, triangle count on each mesh ). All meshes are generated procedurally. Each LOD for each mesh has different color, so you may see, when switches betwen LODs occur.
In OpeneSceneGraph library there is almost the same application called osggpucull, so you may compare performance of Vulkan API and OpenGL API.
Command line parameters enable us to use one of predefined window configurations and also we are able to modify all parameters that affect performance:
-v create two halfscreen windows for VR
-t render in three windows
--skip-static skip rendering of static objects
--skip-dynamic skip rendering of dynamic objects
--static-area-size=[static-area-size]
size of the area for static rendering
--dynamic-area-size=[dynamic-area-size]
size of the area for dynamic rendering
--lod-modifier=[lod-modifier] LOD range [%]
--density-modifier=[density-modifier]
instance density [%]
--triangle-modifier=[triangle-modifier]
instance triangle quantity [%]
--instances-per-cell=[instances-per-cell]
how many static instances per cell
pumexdeferred
Application that implements deferred rendering with multisampling in one window. The number of samples per pixel may be configured from command line ( see parameters below ). Available values of samples per pixel include : 1, 2, 4, 8.
By default application uses depth prepass rendering, but you are able to switch it off using command line parameters ( see below ).
Application presents how to use attachment produced by one render operation as input attachment in a following render operation.
Famous Sponza Palace model is used as a render scene.
Shaders used in that example realize physically based rendering inspired by learnopengl.com
Additional command line parameters :
-n skip depth prepass
-s[samples] samples per pixel (1,2,4,8). Default = 4
pumexmultiview
Application based on pumexdeferred example. It shows how to utilize VK_KHR_multiview extension to render two images at the same time ( without a need for a second render graph and scene graph traversal ) and how to apply barrel distortion.
Shaders used in that example realize physically based rendering inspired by learnopengl.com
pumexibl
Application presenting image based lighting with models able to render using physically based rendering methods ( example model seen on a screenshot below was acquired from glTF Sample Models repository managed by Khronos ).
From technical standpoint - this example shows how to render to many cubemap layers and to texture mipmaps using render graph. Also shows how to generate texture mipmaps using transfer operations ( vkCmdBlitImage is called under the hood to generate missing mipmaps ).
Additional command line parameters :
-i [texture_name] provide equirectangular texture that will be
transformed into cubemaps required to implement
IBL.
model 3D model filename
animation 3D animation filename
pumexviewer
Minimal pumex application that renders single non-textured 3D model provided by the user in command line along with its bounding box. You may render any model as long as Assimp library is able to load it and sum of model's vertex and index size is less than 64 MB.
At the moment the pumexviewer example is only example working on Android.
Application presents simplest possible render graph with only one render operation.
Additional command line parameters :
model 3D model filename
animation 3D animation filename
Examples of use ( command line ) :
Show animated model of a man ( running animation ) :
pumexviewer people/wmale1_lod0.dae people/wmale1_run.dae
Show Sponza palace model :
pumexviewer sponza/sponza.dae
pumexviewerqt
If Pumex was built withQT support enabled ( CMake flag PUMEX_BUILD_QT set to ON - see: Building and installation section ), then there is additional example showing how to create a window using QT library and how to cooperate with it. pumexviewerqt example performs rendering the same way as pumexviewer example.
Difference is that models and animations are not loaded from command line, but when user presses appropriate buttons to do so ( code presents how to use QFileDialog to load a 3D model and send data to pumex application using QT signals ). Additionally user may change model color ( code shows how to use QColorDialog ).
pumexvoxelizer
Application that performs realtime voxelization of a 3D model provided by the user in command line. After producing 3D texture raymarching algorithm is used to render it on screen.
Application presents
- how to use output image from one render operation as input image in a following render operation
- how to perform conservative rendering to 3D texture without conservative rendering extension present
Additional command line parameters :
model 3D model filename
animation 3D animation filename
Examples of use ( command line ) :
Voxelize and render animated model of a man ( running animation ) :
pumexvoxelizer people/wmale1_lod0.dae people/wmale1_run.dae
Voxelize and render Sponza palace model :
pumexvoxelizer sponza/sponza.dae
Windows installer
If you want to see examples in action - there's a Windows installer on Github releases page.
Besides installer you also need Vulkan SDK to be able to run examples.
Installer contains libraries, example applications, header files, data files and compiled shaders, but does not contain source code. In other words - installer has everything you need to run examples and use library as a dependency.
Installer puts all these elements in C:\Program Files\Pumex directory by default ( you may choose different target directory during installation process ).
Installer does not have QT support at the moment.
Building and installation on Windows
Elements that are required to build and install Pumex on Windows :
- Vulkan SDK
- CMake version at least 3.11.0 ( because new FetchContent module is used to download external sources during CMake configuration).
- git
- Microsoft Visual Studio 2015 ( 64 bit ) or Microsoft Visual Studio 2017 ( 64 bit ). clang toolchain was not tested on Windows, but it's highly possible that it also works.
- QT5 GUI library - optional dependency - if you are planning to build Pumex with support for rendering inside QT windows. Important notice: newest versions of QT library ( QT 5.12 ) have Vulkan support disabled by default, so you need to recompile QT from sources with Vulkan SDK present in your system. Have fun.
Steps required to build and install library :
-
download Pumex Library from here
-
create solution files for MS Visual Studio using CMake
- to build Pumex with support for QT5 library - you need to set the flag PUMEX_BUILD_QT manually in CMake GUI. This flag is switched off by default. Also remember, that you have to recompile QT5 library yourself, because Vulkan support is switched off in QT by default.
-
build Release version for 64 bit. All external dependencies will be downloaded during first build. Now you are able to run examples from within Visual Studio
-
(optional step) install library and applications by building INSTALL project ( you need to run Visual Studio in administrator mode to be able to perform this step ). WARNING: due to recent CMake modifications installation is not possible at the moment.
-
if example programs have problem with opening shader files, or 3D models - set the PUMEX_DATA_DIR environment variable so that it points to a directory with data files, for example :
set PUMEX_DATA_DIR=C:\Dev\pumex\data
Building and installation on Linux
Elements that are required to build and install Pumex on Linux :
- Vulkan SDK
- CMake version at least 3.11.0 ( because new FetchContent module is used to download external sources during CMake configuration).
- git
- gcc compiler. clang toolchain was not tested on Linux, but it's highly possible that it also works.
- following libraries
- Assimp
- Intel Threading Building Blocks
- Freetype2
- libjpeg
- libpng
- zlib
- QT5 GUI library - optionally - if you are planning to build Pumex with support for rendering inside QT windows. Important notice: newest versions of QT library ( QT 5.12 ) have Vulkan support disabled by default, so you need to recompile QT from sources with Vulkan SDK present in your system. Have fun.
You can install above mentioned libraries using this command ( excluding QT ) :
sudo apt-get install libassimp-dev libtbb-dev libfreetype6-dev libjpeg-dev libpng-dev
Other libraries will be downloaded during first build ( glm, gli and args )
Steps required to build and install library :
-
download Pumex Library from here
-
create solution files for gcc using CMake, choose "Release" configuration type for maximum performance.
- to build Pumex with support for QT5 library - you need to set the flag PUMEX_BUILD_QT manually in CMake GUI. This flag is switched off by default. Also remember, that you have to compile and install QT5 library yourself, because Vulkan support is switched off in QT by default.
-
perform make -j4
-
( optional step ) perform sudo make install if necessary. WARNING: due to recent CMake modifications installation is not possible at the moment.
Pumex library instals itself in /usr/local/* directories. On some Linux distributions ( Ubuntu for example ) /usr/local/lib directory is not added to LD_LIBRARY_PATH environment variable. In that case you will see a following error while trying to run one of the example programs :
pumexviewer: error while loading shared libraries: libpumex.so.1: cannot open shared object file: No such file or directory
In that case you need to add /usr/local/lib directory to LD_LIBRARY_PATH to remove this error :
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
-
if example programs have problem with opening shader files, or 3D models - set the PUMEX_DATA_DIR environment variable so that it points to a directory with data files, for example :
export PUMEX_DATA_DIR=${HOME}/Dev/pumex/data
Building and installation on Android
Elements that are required to build Pumex on Windows and install it on Android device ( building on Linux has not been tested, but it should look the same )
- Vulkan SDK
- Android Studio with Android SDK and Android NDK installed - you may install both from within Android Studio ( MainMenu -> Tools -> SDK Manager ). You may also optionally install LLDB debugger if required.
- CMake version at least 3.11.0 ( because new FetchContent module is used to download external dependencies during CMake configuration).
- git
Steps required to build and deploy pumexviewer example ( as it is only example working on Android at the moment ) :
-
Import project into Android Studio from pumex/android directory.
-
find local.properties file in pumex/android directory. This file is created by import and is not stored in git, because it contains local settings ). Newest CMake version bundled with Android Studio is 3.10 so it's below minimal Pumex requirements. As a result you have to add path to newer CMake to local.properties file ( CMake 3.11 at least. Newest version is 3.13). For example :
cmake.dir=C\:\\Program Files\\CMake
-
Build project by pressing Build -> Make Project. First project compilation may take some time, because external dependencies are downloaded, patched and built.
-
Deploy to your device using Run -> Run 'pumexviewer'
-
Write github issue describing what went wrong. There's no chance it worked on a first try. Murphy's laws are strong on Android.
You are also able to build project without Android Studio ( standalone build - using gradlew script ). But you still should have proper Android SDK, Android NDK and CMake installed.
Dependencies
Pumex renderer is dependent on a following set of libraries :
- Assimp - library that enables Pumex to read different 3D file formats into pumex::Asset object.
- Intel Threading Building Blocks - adds modern multithreading infrastructure ( tbb::parallel_for(), tbb::flow::graph )
- Freetype2 - for rendering freetype fonts to a texture
- GLM - provides math classes and functions that are similar to their GLSL counterparts ( matrices, vectors, etc. )
- GLI - provides classes and functions to load, write and manipulate textures ( may load DDS, KTX and KMG texture files )
- libjpeg - provides possibility to load JPEG textures
- libpng and zlib - provides possibility to load PNG textures
- args - small header-only library for command line parsing.
- QT5 GUI library - well known GUI library for C++. This is optional dependence if you want to render inside QT windows.
On Windows and Android all mandatory dependencies are downloaded and built on first Pumex library build. On Linux - some of the libraries may be installed using your local package manager ( see section about installation on Linux ). On both systems optional QT library must be downloaded manually and built with Vulkan support enabled.
Future plans
- iOS port through MoltenVK
- implement async compute that may be run during update phase
- scene graphs should only render what is visible ( that's why pumexgpucull example is slower than osggpucull example now ). Should it be mandatory or optional ?
- asynchronous loading of models and textures
- new examples presenting things like :
- different types of shadows
- order independent transparency ( compute shaders using render pass attachments as input storage images )
- physics engine integration
- async compute
- terrain rendering
- optimization of existing examples
- pumexcrowd may be faster because of animations calculated on CPU before each render frame
- pumexgpucull requires visibility testing on CPU scene graph
- pumexdeferred should render lighting using different shapes instead of fullscreen triangle
- extensive library testing
Remark : Pumex is a "work in progress" which means that some elements of Vulkan API are not implemented yet and some may not work properly on every combination of hardware / operating system ( especially on Android ). Pumex API is subject to change.