https://github.com/Dolkar/Tephra
A modern, high-performance C++17 graphics and compute library based on Vulkan
https://github.com/Dolkar/Tephra
gpgpu gpu graphics graphics-library high-performance low-level performance rendering vulkan
Last synced: about 2 months ago
JSON representation
A modern, high-performance C++17 graphics and compute library based on Vulkan
- Host: GitHub
- URL: https://github.com/Dolkar/Tephra
- Owner: Dolkar
- License: mit
- Created: 2023-04-11T10:21:57.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-10-16T15:19:14.000Z (3 months ago)
- Last Synced: 2025-10-17T18:02:04.692Z (3 months ago)
- Topics: gpgpu, gpu, graphics, graphics-library, high-performance, low-level, performance, rendering, vulkan
- Language: C++
- Homepage: https://dolkar.github.io/Tephra/
- Size: 4.86 MB
- Stars: 42
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-vulkan - Tephra - A modern C++17 graphics and compute library filling the gap between Vulkan and high-level APIs like OpenGL. [MIT] (Libraries)
README
# Tephra
**_A modern C++17 graphics and compute library filling the gap between [Vulkan](https://www.vulkan.org/) and high-level APIs such as OpenGL._**
**License**: [MIT](https://github.com/Dolkar/Tephra/blob/main/LICENSE)
**Current version**: [v0.8.0](https://dolkar.github.io/Tephra/changelog.html)
**Links**: [User guide](https://dolkar.github.io/Tephra/user-guide.html) | [API Documentation](https://dolkar.github.io/Tephra/annotated.html) |
[Discussions](https://github.com/Dolkar/Tephra/discussions)
**Build status**: 
## About
Tephra aspires to provide a modern alternative to high-level graphics APIs like OpenGL and DirectX 11, while leveraging
the benefits of the underlying Vulkan ecosystem. Its goal is to strike a good balance between ease-of-use, performance
and relevance. To that end, Tephra provides:
- A high-level job system for submitting batches of work to the GPU (or to other accelerators that expose the Vulkan
API)
- Low-level command lists that can be recorded in parallel and with minimal overhead
- An easy and efficient way to create temporary images, staging buffers and scratch memory
- A simple, general-purpose interface that tries not to force architectural decisions upon the user (such as the concept
of frames, requiring recording callbacks or a bindless resource model)
- The ability to use bleeding-edge features of graphics hardware through direct interoperability with the Vulkan API
- An introductory [user guide](https://dolkar.github.io/Tephra/user-guide.html), extensive
[documentation](https://dolkar.github.io/Tephra/annotated.html) and [examples](https://dolkar.github.io/Tephra/examples.html)
for getting started with using the library without prior knowledge of Vulkan
- Debugging features, usage validation and testing suite (WIP)
_Tephra is being used and partially developed by [Bohemia Interactive Simulations](https://bisimulations.com/)._
Tephra path tracing example
### Comparison to OpenGL / DirectX 11
One of the main differences when moving over from these older graphics APIs is the execution model. Much like in Vulkan,
your draw calls don't take effect immediately in Tephra, but are instead recorded into either jobs or command lists that
then get executed at a later time. There is no "immediate context". This allows for easy parallel recording and
full control over the execution of workloads. Recording commands is usually done in two passes. A "job" first defines
high-level commands such as:
- Allocation of temporary job-local resources
- Clears, copies, blits and resolves
- Render and compute passes specifying target resources and forming a set of command lists to execute
- Resource export commands and Vulkan interop commands
The actual draw and dispatch commands then get recorded into the command lists of each pass after the job itself has
been finalized. For convenience, a callback function can be optionally used to record a small command list in-place to
help with code organization.
While Tephra handles most of the Vulkan-mandated synchronization automatically from the list of job commands,
analyzing commands recorded into command lists would have unacceptable performance overhead. This could ordinarily be
circumvented by manually specifying all the resource accesses of each render / compute pass, but for the majority of
read-only accesses, the library offers the much more convenient "export" mechanism. Once an image or buffer is written
to by a prior command or pass, it can be exported for all future accesses of a certain type, for example as a sampled
texture. In effect, for a resource used inside shaders, this means that you generally only need to specify how it is
going to be read in the future after each time you write into it. In most cases that only needs to be done once.
Another system inherited from Vulkan is its binding model. By default, resources get bound as descriptors in sets,
rather than individually. You can think of a material's textures - the albedo map, normal map, roughness map, etc -
as one descriptor set, through which all of its textures get bound to a compatible shader pipeline at the same time.
Alternatively, you can use the "bindless" style of managing a global array of all of your textures inside a single giant
descriptor set that you then index into inside your shaders. Tephra streamlines working with either method.
### Comparison to Vulkan and other Vulkan abstractions
Starting from the initialization stage, Tephra already provides amenities for interacting with the varied world of
Vulkan devices. Arbitrary number of queues can be used from each supported queue family, irrespective of the actual
number exposed by Vulkan. Feature maps and format utilities further help handle hardware differences. Vulkan profile
support is planned, making the process of choosing and relying upon a specific set of hardware features even easier.
Overall, the initialization process is greatly simplified compared to raw Vulkan, akin to using the
[vk-bootstrap](https://github.com/charles-lunarg/vk-bootstrap) library.
Tephra leverages [VMA](https://gpuopen.com/vulkan-memory-allocator/) for all of its resource allocations. On top of that,
it allows efficient use of temporary resources within each job. Requested job-local resources can be aliased to the same
memory location to reduce memory usage if their usage does not overlap. Growable ring buffers provide temporary staging
buffers for easy uploading of data. The pools that all these reusable resources are allocated from are controllable and
configurable. In general, the library tries to avoid allocations whenever possible, opting instead for pooling and reuse.
RAII is used to manage the lifetime of resources and other objects. Their destruction is delayed until the device is done
using the objects, so they can be safely dropped even right after enqueuing a job. The idea of buffer and image views
has been expanded upon and nearly all interactions with resources are done through these non-owning views. They can
reference the entire resource, or just its part, and are relatively cheap to create on the fly.
Automatic synchronization is implemented between all job commands submitted to the same queue. The implementation tries
to minimize the number of barriers without reordering the commands - the control of that is left in the hands of
the user. All dependencies are resolved on a subresource level, including byte ranges for buffers and array layers / mip
levels for images. Synchronization across different queues is handled with timeline semaphores and resource exports in
a thread safe manner.
Many other Vulkan abstractions opt for
[render graphs](https://themaister.net/blog/2017/08/15/render-graphs-and-vulkan-a-deep-dive/) to manage synchronization
and resource aliasing. Tephra's approach works the same as a render graph that does not reorder passes, but has a smaller
API footprint, does not force resource virtualization and is already familiar to users of last-gen graphics APIs. A
render graph solution can be easily implemented on top of Tephra, if desired.
Descriptor sets differ from Vulkan's by being immutable. Changing them requires waiting until the device is done with
any workload that uses it, which is infeasible in practice. Instead, Tephra recycles and reuses old descriptor sets
to create new ones in the background. Besides these ordinary descriptor sets, a mutable descriptor set implementation is
also provided. It can be useful for emulating the binding of individual resources, or to assist with a bindless resource
model.
Tephra provides many other abstractions around Vulkan, such as pools, pipelines, swapchain and others to form an
all-encompassing, high-level-ish graphics library. You generally do not need to use the Vulkan API directly, except when
working with extensions that Tephra does not natively support, or when interacting with various device properties and
features.
## Feature list
The following features are already present:
- All of the compute and graphics commands supported by core Vulkan
- Automatic synchronization and resource state tracking inside and across queues
- Temporary resource allocator that leverages aliasing to reduce memory usage
- Support for multi-threaded recording and device-level thread safety
- Improved image and buffer views
- Safe delayed destruction of Vulkan handles
- Timestamp, occlusion and pipeline queries
- Ray tracing using the ray query API
- Interoperability with plain Vulkan (WIP)
- Native support of commonly used Vulkan extensions (WIP)
- Debug logging, statistics, tests and partial usage validation (WIP)
The following features are planned and will likely be available in the future:
- Ray tracing pipeline support (ray tracing with ray queries is already present)
- Better handling of dynamic pipeline state
- Improved pipeline building and management
- Vulkan profiles
The following features are out of scope for the library and won't be included:
- Platform-dependent window management - use GLFW or a similar library instead
- Shader compilation and reflection - use the existing Vulkan ecosystem
- CPU-side acceleration structure building and serialization
- Rendering algorithms - this is not a renderer or a game engine
See the [user guide](https://dolkar.github.io/Tephra/user-guide.html) for more detailed explanations and inline code
examples of Tephra's features, or the [examples](https://github.com/Dolkar/Tephra/tree/main/examples) folder for a
runnable showcase.
## Prerequisities
- Tephra is a C++ library. It makes use of C++17 features, the standard library and C++ exceptions
- Visual Studio 2022 (see build/Tephra.sln) or CMake 3.15 (limited support of tests and examples)
- Vulkan headers version 1.4.304 or newer, provided with the SDK [here](https://www.lunarg.com/vulkan-sdk/)
- Compatible devices must support Vulkan 1.3 or newer
- While any x64 platform is supported, Tephra is being used and tested mainly on Windows
Building the documentation:
- Python 3.6 or newer
- Doxygen 1.8.15 or newer
- The [Jinja2](https://palletsprojects.com/p/jinja/) and [Pygments](https://pygments.org/) Python packages
## Contributing
Feel free to create issues, submit pull requests for non-trivial changes and participate in
[Discussions](https://github.com/Dolkar/Tephra/discussions). Submitting examples, validation and tests is also very
appreciated.