Skip to content
ozguronsoyPublic

About

An experimental cross-platform graphics library.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

206 Commits

Folders and files

Repository files navigation

HephGL

Examples Tests Coverage

Introduction

HephGL is an experimental cross-platform graphics library created for the sole purpose of me learning Rust and graphics programming.

Goals:

  • Multiple graphics backends (e.g., Vulkan, DirectX) with runtime backend switching.
  • Clean, simple, low boilerplate, and easy to use API that is agnostic to the used backend.
  • Thread-safe design.
  • High performance and low memory consumption.
  • Seamless integration with any windowing library.

Setup

Install

If you want to use HephGL in your project, run the following command

cargo add heph-gl

or add heph-gl = <version> to your Cargo.toml.

If you want to work on HephGL, simply clone this repository.

Dependencies

clippy

rustup component add clippy

nightly is used for formatting

rustup toolchain install nightly --component rustfmt

nextest is used for integration tests since running them with standard cargo test results in failure due to window creation in worker threads.

cargo install cargo-nextest --locked

llvm-cov is used for generating code coverage reports

cargo install cargo-llvm-cov --locked

All other dependencies are stated in the Cargo.toml file, and will be fetched automatically during build.

Usage

Environment Variables

HephGL supports compile-time configuration through optional environment variables:

  • HEPHGL_RENDERER_MAX_CONCURRENT_THREADS=<usize>: The maximum number of threads a renderer can concurrently run.

Renderer

The Renderer trait provides a clean and simple API that is agnostic to the backend it uses. This enables us to switch between graphics APIs without changing the code. Renderers must be initialized before we can start utilizing them.

After initialization and device selection, rendering and compute work follow the same basic lifecycle: load shaders, create a pipeline, and record commands between begin_frame and end_frame. Ending the frame submits the recorded work. Reuse the pipeline across frames, then wait for the GPU before releasing its resources.

flowchart TD
    A[Create and initialize renderer] --> B[Select graphics device]
    B --> C[Load shaders and create pipeline]
    C --> D[Begin frame]
    D --> E[Prepare resources and record commands]
    E --> F[End frame]
    F --> G{More frames?}
    G -- Yes --> D
    G -- No --> H[Wait for GPU completion and release resources]
Loading

The following example renders a basic triangle using the Vulkan backend. Replace the placeholders with the corresponding raw handles from your chosen windowing library. Shader paths are relative to the repository root, these shaders generate the triangle's vertices without vertex buffers.

use heph_gl::{
    renderers::{
        Renderer,
        settings::{GraphicsPipelineOptions, InitializeOptions},
        vulkan::VulkanRenderer,
    },
    shader::Shader,
};
use renkrs::RGB;

let mut renderer = VulkanRenderer::new();
renderer.initialize(&InitializeOptions {
        app_name: "Basic Triangle",
        window_handle: <raw_window_handle>,
        display_handle: <raw_display_handle>,
        api_version: VulkanRenderer::LATEST_API_VERSION,
    }).unwrap();
renderer.set_device(VulkanRenderer::DEFAULT_DEVICE, &[]).unwrap();

let vert_shader = Shader::from_file("shaders/shapes/basic_triangle_vert.spv").unwrap();
let frag_shader = Shader::from_file("shaders/shapes/basic_triangle_frag.spv").unwrap();
let pipeline = renderer.create_graphics_pipeline(
        &[&vert_shader, &frag_shader],
        &GraphicsPipelineOptions::default(),
    ).unwrap();
drop(vert_shader);
drop(frag_shader);

renderer.begin_frame().unwrap();
renderer.clear(RGB::default()).unwrap();
// Three vertices, one instance.
renderer.record_graphics_command(&pipeline, &[], 3, 1).unwrap();
renderer.end_frame().unwrap();

renderer.wait_idle().unwrap();
renderer.destroy_graphics_pipeline(&pipeline).unwrap();

Check out the examples directory for more examples and flowcharts.

Graphics

While the Renderer trait successfully abstracts the underlying backend, using it directly still requires a fair amount of boilerplate for pipeline creation, resource management, command recording, and multithreaded synchronization. The Graphics struct aims to provide a higher-level, simplified API that allows you to easily render sprites or execute computations without writing all of this boilerplate code.

You might wonder why the Renderer is still exposed directly if the Graphics struct is easier to use. The Graphics struct is ideal for rapid development and applications that are not strictly performance-critical. However, by retaining direct access to the Renderer, HephGL ensures that developers can bypass the higher-level abstractions to fine-tune and optimize the rendering pipeline specifically for their use cases.

Note

The Graphics struct is not implemented yet.

Contributing

All types of contributions are welcome. Feel free to open a PR, issue, or discussion.

HephGL uses prek for code formatting and linting. Follow the steps below to setup prek.

First install prek

cargo install prek --locked

To automatically run the required checks before every commit, install the pre-commit hook. Run this command at the root of the repository

prek install

You can also run prek manually if you don't want to install the hook

prek

License

Licensed under the BSD-3-Clause License.

About

An experimental cross-platform graphics library.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages