Skip to content

Unified renderer implementation ("Un r imp")

License

Notifications You must be signed in to change notification settings

cofenberg/unrimp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub license

x64 Windows pre-build binary Google Drive link: unrimp_windows_20042024.zip

Foreword

This is a spare time project. There's no support. API changes are done in an time efficient way, meaning without thinking about backward compatibility.

Unrimp Description

Unified renderer implementation ("Un r imp") with separation into rendering hardware interface (RHI), renderer and toolkit for asset cooking

  • RHI abstracts way the underlying API like Vulkan/OpenGL/Direct3D
  • Renderer designed with end-user and middleware-user in mind
    • Efficiency and responsiveness over flexibility (were it isn't useful in practice)
    • Intended to be controlled by a high-level entity-component system, no unused implementation feature overkill in the basic renderer
  • Toolkit designed with developer fast iterations in mind: Asset source flexibility, asset background compilation, hot-reloading

Examples from basic to advanced are provided.

Originally started as modern renderer replacement for the PixelLight engine which was in active development between 2002-2012. The first public Unrimp source code release after starting the project on Friday, 1 June 2012 was on January 03, 2013.

Screenshots

General

  • C++20 and above, no legacy compiler support
  • Compact user-header for the RHI
    • A single all in one header for ease-of-use and optimized compile times
    • No need to links against the RHI library itself, load RHI implementations dynamically during runtime
  • Usage of amalgamated/unity builds for optimized compile times
  • Using CMake for the build process
  • Using Doxygen for code documentation
  • Lightweight RHI implementations
    • Designed with AZDO ("Almost Zero Driver Overhead") in mind
    • Implementations try to stick as best as possible close-to-the-metal and as a result are just a few KiB instead of MiB in memory size
    • Implementations load the entry points of Vulkan, Direct3D, OpenGL and so on during runtime, meaning it's possible to react on system failures by e.g. dynamically switching to another RHI implementation
  • Support for static and shared build
  • RTTI and C++ exceptions are not used by RHI and renderer
  • Interfaces for log, assert, memory allocator, graphics debugger, profiler and file so the user has the control over those things
    • Standard implementations are provided
    • Standard memory allocator as well as mimalloc memory allocator implementation is provided
    • Standard graphics debugger implementation using RenderDoc is provided
    • Standard profiler implementation using Remotery is provided
    • Standard file implementation using UTF-8 STD file streams as well as PhysicsFS for shipping packed asset packages are provided
  • Cross-platform
    • Microsoft Windows x86 and x64
    • Currently unmaintained
      • Linux
      • Android
    • Mac is currently no target platform due no dropped OpenGL support and no official Vulkan support, implementing Metal is too much effort for a spare time pet project

Rendering hardware interface (RHI) and implementations

  • RHI implementations for
    • Vulkan (not feature complete, yet)
    • Direct3D 12 (not feature complete, yet)
    • Direct3D 11
    • OpenGL (by default a OpenGL 4.1 context is created, the best OpenGL version Mac OS X 10.11 supports, so lowest version we have to support)
    • OpenGL ES 3
    • Legacy = critical features like uniform buffer, texture buffer and/or compute shaders are missing which are required for modern efficient renderers which provide e.g. automatic instancing or clustered deferred rendering, still maintained for curiosity reasons
      • Direct3D 10
      • Direct3D 9
  • Render targets
    • Swap chains, render into one or multiple operation system windows
    • Framebuffer object (FBO) used for render to texture, support for multiple render targets (MRT), support for multisample (MSAA)
  • Shaders
    • Shader types
      • Vertex shader (VS)
      • Tessellation control shader (TCS, "hull shader" in Direct3D terminology)
      • Tessellation evaluation shader (TES, "domain shader" in Direct3D terminology)
      • Geometry shader (GS)
      • Fragment shader (FS, "pixel shader" in Direct3D terminology)
      • Task shader (TS, "amplification shader" in Direct3D terminology)
      • Mesh shader (MS)
      • Compute shader (CS)
    • Shader data sources
      • Shader bytecode (aka shader microcode, binary large object (BLOB))
        • Vulkan and OpenGL: SPIR-V support for cross-platform vendor and GPU driver independent shader bytecodes
          • Optional build in online GLSL to SPIR-V compilation using glslang, offline compilation before shipping a product is preferred of course but not mandatory
          • Using SMOL-V: like Vulkan/Khronos SPIR-V, but smaller
      • Shader source code
  • Buffers
    • Vertex array object (VAO, input-assembler (IA) stage) with support for multiple vertex streams
      • Vertex buffer object (VBO, input-assembler (IA) stage)
      • Index buffer object (IBO, input-assembler (IA) stage)
    • Texture buffer object (TBO)
    • Structured buffer object (SBO)
    • Indirect buffer object with optional internal emulation, draw methods always use an indirect buffer to have an unified draw call API
    • Uniform buffer object (UBO, "constant buffer" in Direct3D terminology)
    • Command buffer mandatory by design, not just build on top
  • Textures: 1D, 1D array, 2D, 2D array, 3D, cube, cube array
  • State objects with mapping to API specific settings during creation, not runtime
    • Graphics pipeline state object (PSO) which directly maps to Direct3D 12, other RHI implementations internally subdivide into
      • Rasterizer state object (rasterizer stage (RS))
      • Depth stencil state object (output-merger (OM) stage)
      • Blend state object (output-merger (OM) stage)
    • Sampler state object (SO)
  • Instancing support
    • Instanced arrays (shader model 3 feature, vertex array element advancing per-instance instead of per-vertex)
    • Draw instanced (shader model 4 feature, build in shader variable holding the current instance ID)
  • Debug methods and RHI debug resource names
    • When using Direct3D <11.1, those methods map to the Direct3D 9 PIX functions (D3DPERF_* functions, also works directly within VisualStudio 2019 out-of-the-box)
    • Used inside the RHI implementations for better RHI debugging
  • Supported asynchronous queries: Occlusion, pipeline statistics and timestamp
  • RHI implementation specific optimizations:
    • OpenGL: Usage of direct state access (DSA), if available

Renderer (e.g. "The Game")

  • During runtime, only platform optimized and compressed binary assets are used
    • No inefficient generic stuff, no e.g. endianness handling, primarily raw chunks which can be fed into memory and GPU as efficient as possible
    • Efficient CRN textures are used by default, DDS is supported as well
    • Using LZ4 compression
  • Asynchronous loading for all resources: To fight lags, micro stutter / judder, especially for virtual reality applications one needs a constant framerate
  • Material and shader blueprint system which was designed from ground up for pipeline state object (PSO) architecture
    • New material types can be added without a single line of C++ source code, meaning technical artists can create and fine-tune the shaders in realtime
    • Materials reference material blueprints and are just a list of key-value-pairs
    • Shader language specifics are abstracted away: Write shaders once, use them across multiple RHI implementations
    • Support for shader combinations (Uber-shaders)
    • Support for reusable shader pieces
    • Material inheritance for materials which should share common properties, but differ in other properties
    • Using MojoShader as shader preprocessor so the resulting shader source codes are compact and easy to debug
    • Asynchronous pipeline state compilation, including a fallback system to reduce visual artifacts in case of pipeline cache misses
  • Compositor: Setup your overall rendering flow without a single line of C++ source code
    • The compositor is using the material blueprint system, meaning compact C++ implementation while offering mighty possibilities
    • Using Reversed-Z for improved depth buffer precision to reduce z-fighting
    • Using camera relative rendering for rendering large scale scenes without jittering/wobbling
    • Using 64 bit world space position
    • Blurred stabilized cascaded (CSM) exponential variance (EVSM) shadow mapping basing on "A Sampling of Shadow Techniques" by Matt Pettineo
    • Resolution scale support
  • Scene as most top-level concept: Fancy-feature set kept simple because more complex applications / games usually add an entity-component-system
  • Sorted render queue fed with generic renderables to decouple concrete constructs like meshes, particles, terrain etc. from the generic rendering
  • Using mathematics library GLM
  • Using xsimd for SIMD intrinsics
  • Cache efficient SIMD multi-threaded frustum culling basing on "The Implementation of Frustum Culling in Stingray"
  • ImGui is used as debug GUI to be able to quickly add interactive GUI elements for debugging, prototyping or visualization
  • Virtual reality manager which is internally using OpenVR for head-mounted display support
    • Animated controller visualization supported
    • Single pass stereo rendering via instancing
    • Hidden area mesh supported
  • Texture top mipmap removal support while loading textures for efficient texture quality reduction
  • Light
  • Mesh
    • Level of detail (LOD) support
    • Optional position-only vertex array object (VAO) which can reduce the number of processed vertices up to half, can be used for position-only rendering (e.g. shadow map rendering) using the same vertex data that the original vertex array object (VAO) uses
  • Skeleton animation
    • ACL compressed skeleton animation clip
    • GPU dual quaternion skinning (DQS), linear blend skinning (LBS) using matrices path is available as well
  • Particles rendering
  • Terrain
  • Sky
    • Traditional environment cube map skybox
    • Procedural sky
      • Hosek-Wilkie sky which is also used to derive a sun color
      • Distance clouds
      • Sun
  • Volume rendering
  • Debug draw functionality

Renderer Toolkit (e.g. "The Editor")

  • Project compiler will transform source data into runtime data and while doing so tries to detect editing issues at tooltime as early as possible to reduce runtime harm and long debugging seasons
  • Asynchronous resource compilation and hot reloading for all resources if the toolkit is enabled (true for production, probably not true for shipped titles)
    • Shader-resource example: It's possible to develop shaders while the application is running and see changes instantly
  • Most source file formats are using JSON: RapidJSON is used for parsing
  • Performs optimizations and validations at tooltime instead of runtime. Examples:
    • Strips comments from shader source codes
    • Checks the material blueprint resources for valid uniform buffer packing rules
  • Mesh compiler
    • Using Assimp (Open Asset Import Library) for mesh import and post processing like joining identical vertices
    • Using MikkTSpace by Morten S. Mikkelsen for semi-standard mesh tangent space generation
    • Using meshoptimizer for mesh optimization and LOD generation
  • Texture compiler
    • Using enhanced Unity Crunch (better encoder performance and ETC2 support) version of Crunch for mipmap generation and compression
    • Support for normal map compression
    • Support for alpha mipmaps
    • Support for creating a cube-map out of six provided individual textures
    • Support for 2D-LUT to 3D-LUT conversion
    • Support for texture channel packing
    • Support for defining texture arrays
    • Toksvig specular anti-aliasing basing on "Specular Showdown in the Wild West" by Stephen Hill to reduce shimmering/sparkling via texture modifications during texture asset compilation
  • Sketchfab asset importer without the need to unzip the downloaded meshes first

Examples (just some high level keywords)

Terminology and Acronyms

  • General
    • Plain old data (POD)
  • Rendering hardware interface (RHI)
    • Compute shader (CS)
    • Fragment shader (FS), "pixel shader" in Direct3D terminology
    • Geometry shader (GS)
    • Index buffer object (IBO)
    • Mesh shader (MS)
    • Pipeline state object (PSO, there's a graphics PSO and a compute PSO)
    • Root signature (Direct3D terminology) = pipeline layout in Vulkan terminology
    • Sampler state object (SO)
    • Shader resource view (SRV)
    • Structured buffer object (SBO)
    • Task shader (TS, "amplification shader" in Direct3D terminology)
    • Texture buffer object (TBO)
    • Tessellation control shader (TCS), "hull shader" in Direct3D terminology
    • Tessellation evaluation shader (TES), "domain shader" in Direct3D terminology
    • Uniform buffer object (UBO), "constant buffer" in Direct3D terminology
    • Uniform buffer view (UBV)
    • Unordered access view (UAV)
    • Vertex array object (VAO)
    • Vertex buffer object (VBO)
    • Vertex shader (VS)
  • Renderer
    • Asset: Lightweight content metadata like ID, type and location (texture, mesh, shader etc. - on this abstraction level everything is an asset)
    • Gamma space = Perceptual color space = sRGB = Not linear
    • HMD: Head mounted display
    • LOD: Level of detail
    • Mesh: 3D-model consisting of a vertex- and index-buffer, geometry subdivided into sub-meshes
    • Material and shader blueprint: High-level rendering description
    • Material: Just a property-set used as shader input
    • Resource: A concrete asset type used during runtime in-memory (texture, mesh, shader etc.)

Microsoft Windows: First Example Kickoff

  • Open Visual Studio 2019 and select "File -> Open -> CMake..." -> "unrimp/CMakeLists.txt"
  • Build "Windows_x64_Shared" project settings
  • Compile the runtime assets by starting "unrimp/Binary/Windows_x64_Shared/ExampleProjectCompiler.exe"
  • Run "unrimp/Binary/Windows_x64_Shared/Examples.exe" (is using default command line arguments "unrimp/Binary/Windows_x64_Shared/Examples.exe ImGuiExampleSelector -r Direct3D11")
  • For debugging with Visual Studio 2019, use "Examples.exe (Install with Arguments)" or "ExampleProjectCompiler.exe (Install with Arguments)" as startup item
  • Modify "launch.vs.json" to change the Visual Studio application launch options, e.g. to start the "FirstScene"-example by default

Microsoft Windows: Using the Unrimp examples together with SDL2

  • Download e.g. "SDL2-devel-2.0.10-VC.zip" from https://www.libsdl.org/download-2.0.php and extract it into "unrimp/External/Example/SDL2" (directory contains "include" and "lib")
  • Click on Visual Studio 2019 -> Menu bar -> "Project" -> "Generate Cache for Unrimp", the minimal SDL2 standalone example "ExampleSDL2" is now also available (RHI only, no renderer nor renderer toolkit)
  • For debugging with Visual Studio 2019, use "ExampleSDL2.exe (Install with Arguments)" as startup item
  • Build and run the examples, when setting a break point inside Visual Studio 2019 at "ApplicationImplSdl2::onInitialization()" it should trigger now so you know it worked

Microsoft Windows: Targeting Android

Useful Microsoft Windows Developer Tools

Useful Online Asset Data Sources

Asset Prefixes

The asset prefixes are just used inside the Unrimp examples and are not fixed build in. Feel free to use other asset prefixes or no prefixes at all in your projects.

  • "CN" = "Compositor node"
  • "CW" = "Compositor workspace"
  • "M" = "Material"
  • "MB" = "Material blueprint"
  • "S" = "Scene"
  • "SA" = "Skeleton animation"
  • "SB" = "Shader blueprint"
  • "SM" = "Static or skinned mesh"
  • "SP" = "Shader piece"
  • "T" = "Texture"
  • "VA" = "Vertex attributes"

Assets

  • Each source asset which gets compiled into an runtime usable asset has a ".asset"-file which defines which asset compiler should be used as well as an optional asset compiler configuration. The rule is to not manipulate the source asset itself for asset compilation but to just decorate it with additional information. For ease of use there's support for automatically in-memory generated ".asset"-files which works for asset compilers which accept just a single unique filename extension.
  • Assets are referenced by using
    • Renderer toolkit source asset ID naming scheme "<name>.asset"
      • Absolute: "${PROJECT_NAME}" inserts the name of the project the currently processed asset is in, only valid at the beginning of source asset IDs
      • Relative: "./" uses the directory the currently processed asset is in, only valid at the beginning of source asset IDs
      • Relative: "../" switches into the parent directory the currently processed asset is in, only valid at the beginning of source asset IDs
    • Compiled or runtime generated asset ID naming scheme "<project name>/<asset directory>/<asset name>"
  • Examples for asset references inside source assets
    • Referencing a source asset inside the same project as the currently compiled source asset
      • "${PROJECT_NAME}/Blueprint/Sky/M_Sky.asset": Referencing a source asset which is inside the same project as the currently compiled source asset
      • "./MB_Debug.asset": Referencing a source asset which is inside the same directory as the currently compiled source asset
      • "./MyDirectory/MB_Debug.asset": Referencing a source asset which is inside a sub-directory named "MyDirectory" which is inside same directory as the currently compiled source asset
      • "../MB_Debug.asset": Referencing a source asset which is inside the parent directory of the directory the currently compiled source asset is in
      • "../../MB_Debug.asset": Referencing a source asset which is inside the parent directory of the parent directory of the directory the currently compiled source asset is in
      • "../../MyDirectory/MB_Debug.asset": Referencing a source asset which is inside a sub-directory named "MyDirectory" which is inside the parent directory of the parent directory of the directory the currently compiled source asset is in
    • "MyProject/Blueprint/Sky/M_Sky.asset": Referencing a source asset which is inside another project named "MyProject"
    • "Unrimp/Texture/DynamicByCode/BlackMap2D": Referencing an asset which is dynamically created during runtime without having a compiled source asset

Hints

  • Error strategy
    • Inside renderer toolkit: Exceptions in extreme, up to no error tolerance. If something smells odd, blame it to make it possible to detect problems as early as possible in the production pipeline.
    • Inside renderer: The show must go on. If the floor breaks, just keep smiling and continue dancing.
  • Windows using Visual Studio 2019 C++ Open Folder and CMake: IntelliSense keeps failing
  • How to test the 64 bit world space position support?
    • Inside "SceneResourceLoader.cpp" -> "nodeDeserialization()" after reading a node, add an 100.000.000 offset to the node transform position
  • A few words about Euler angles
    • We use the YXZ rotation order as default (glm::eulerAngleYXZ()/glm::extractEulerAngleYXZ())
      • "yaw" represents a rotation around the Y-axis (= up vector)
      • Then "pitch" is applied as a rotation around the local (i.e. already rotated) X-axis (= right vector)
      • Finally "roll" rotates around the local Z-axis (= front vector)
    • When dealing with Euler angles keep care of 'gimbal lock', at http://www.sjbaker.org/steve/omniv/eulers_are_evil.html you will find some good information about this topic.

The unified RHI can't unify some RHI implementation behaviour differences. Here's a list of hints you might want to know:

Copyright (c) 2012-2022 The Unrimp Team

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.