Skip to content

Commit

Permalink
Port the high-level Blade engine from RayCraft
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Dec 4, 2023
1 parent 4204552 commit 2c4acb1
Show file tree
Hide file tree
Showing 15 changed files with 990 additions and 223 deletions.
38 changes: 24 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,44 @@ readme = "docs/README.md"
[features]

[dependencies]
blade-asset = { version = "0.2.0", path = "blade-asset" }
blade-egui = { version = "0.2.0", path = "blade-egui" }
blade-macros = { version = "0.2.1", path = "blade-macros" }
blade-graphics = { version = "0.3.0", path = "blade-graphics" }
blade-render = { version = "0.2.0", path = "blade-render" }
blade-asset = { version = "0.2", path = "blade-asset" }
blade-egui = { version = "0.2", path = "blade-egui" }
blade-graphics = { version = "0.3", path = "blade-graphics" }
blade-render = { version = "0.2", path = "blade-render" }
choir = { workspace = true }
colorsys = "0.6"
egui = { workspace = true }
nalgebra = { version = "0.32", features = ["mint"] }
log = { workspace = true }
mint = { workspace = true, features = ["serde"] }
num_cpus = "1"
profiling = { workspace = true }
rapier3d = { version = "0.17", features = ["debug-render"] }
serde = { version = "1", features = ["serde_derive"] }
slab = "0.4"
strum = { workspace = true }
winit = "0.28"

[dev-dependencies]
blade-macros = { version = "0.2", path = "blade-macros" }
bytemuck = { workspace = true }
choir = { workspace = true }
egui = { workspace = true }
del-msh = "0.1"
egui-gizmo = "0.12"
egui_plot = "0.23"
egui-winit = "0.23"
env_logger = "0.10"
# https://github.com/nobuyuki83/del-msh/issues/1
del-msh = "=0.1.17"
glam = { workspace = true }
log = { workspace = true }
mint = { workspace = true, features = ["serde"] }
naga = { workspace = true }
nanorand = { version = "0.7", default-features = false, features = ["wyrand"] }
num_cpus = "1"
profiling = { workspace = true }
ron = "0.8"
serde = { version = "1", features = ["serde_derive"] }
strum = { workspace = true }
winit = "0.28"

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
egui-winit = "0.23"
egui_plot = "0.23"
egui-gizmo = "0.12"
env_logger = "0.10"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
console_error_panic_hook = "0.1.7"
Expand Down
20 changes: 20 additions & 0 deletions blade-egui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Blade EGUI

[![Docs](https://docs.rs/blade/badge-egui.svg)](https://docs.rs/blade-egui)
[![Crates.io](https://img.shields.io/crates/v/blade-egui.svg?maxAge=2592000)](https://crates.io/crates/blade-egui)

[EGUI](https://www.egui.rs/) support for [Blade-graphics](https://crates.io/crates/blade-graphics).

![scene editor](etc/scene-editor.jpg)

## Instructions

Just the usual :crab: workflow. E.g. to run the bunny-mark benchmark run:
```bash
cargo run --release --example bunnymark
```

## Platforms

The full-stack Blade Engine can only run on Vulkan with hardware Ray Tracing support.
However, on secondary platforms, such as Metal and GLES/WebGL2, one can still use Blde-Graphics and Blade-Egui.
File renamed without changes
52 changes: 52 additions & 0 deletions blade-graphics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Blade-Graphics

[![Docs](https://docs.rs/blade-graphics/badge-graphics.svg)](https://docs.rs/blade-graphics)
[![Crates.io](https://img.shields.io/crates/v/blade-graphics.svg?maxAge=2592000)](https://crates.io/crates/blade-graphics)

Blade-graphics is a lean and mean [GPU abstraction](https://youtu.be/63dnzjw4azI?t=623) aimed at ergonomics and fun. See [motivation](etc/motivation.md), [FAQ](etc/FAQ.md), and [performance](etc/performance.md) for details.

## Examples

![ray-query example](etc/ray-query.gif)
![particles example](etc/particles.png)

## Platforms

The backend is selected automatically based on the host platform:
- *Vulkan* on desktop Linux, Windows, and Android
- *Metal* on desktop macOS, and iOS
- *OpenGL ES3* on the Web

| Feature | Vulkan | Metal | GLES |
| ------- | ------ | ----- | ---- |
| compute | :white_check_mark: | :white_check_mark: | |
| ray tracing | :white_check_mark: | | |

### OpenGL ES

GLES is also supported at a basic level. It's enabled for `wasm32-unknown-unknown` target, and can also be force-enabled on native:
```bash
RUSTFLAGS="--cfg gles" CARGO_TARGET_DIR=./target-gl cargo test
```

This path can be activated on all platforms via Angle library.
For example, on macOS it's sufficient to place `libEGL.dylib` and `libGLESv2.dylib` in the working directory.

### WebGL2

Following command will start a web server offering the `bunnymark` example:
```bash
cargo run-wasm --example bunnymark
```

### Vulkan Portability

First, ensure to load the environment from the Vulkan SDK:
```bash
cd /opt/VulkanSDK && source setup-env.sh
```

Vulkan backend can be forced on using "vulkan" config flag. Example invocation that produces a vulkan (portability) build into another target folder:
```bash
RUSTFLAGS="--cfg vulkan" CARGO_TARGET_DIR=./target-vk cargo test
```
44 changes: 22 additions & 22 deletions docs/FAQ.md → blade-graphics/etc/FAQ.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# Frequency Asked Questions

## When should I *not* use Blade?

- When you *target the Web*. Blade currently has no Web backends supported. Targeting WebGPU is desired, but will not be as performant as native.
- Similarly, when you target the *low-end GPUs* or old drivers. Blade has no OpenGL/D3D11 support, and it requires fresh drivers on Vulkan.
- When you render with 10K or *more draw calls*. State switching has overhead with Blade, and it is lower in GPU abstractions/libraries that have barriers and explicit bind groups.
- When you need something *off the shelf*. Blade is experimental and young, it assumes you'll be customizing it.

## Why investing into this when there is `wgpu`?

`wgpu` is becoming a standard solution for GPU access in Rust and beyond. It's wonderful, and by any means just use it if you have any doubts. It's a strong local maxima in a chosen space of low-level portability. It may very well be the global maxima as well, but we don't know this until we explore the *other* local maximas. Blade is an attempt to strike where `wgpu` can't reach, it makes a lot of the opposite design solutions. Try it and see.

## Isn't this going to be slow?

Blade creating a descriptor set (in Vulkan) for each draw call. It doesn't care about pipeline compatibility to preserve the bindings. How is this fast?

Short answer is - yes, it's unlikely going to be faster than wgpu-hal. Long answer is - slow doesn't matter here.

Take a look at Vulkan [performance](performance.md) numbers. wgpu-hal can get 60K bunnies on a slow machine, which is pretty much the maximum. Both wgpu and blade can reach about 20K. Honestly, if you are relying on 20K unique draw calls being fast, you are in a strange place. Generally, developers should switch to instancing or other batching methods whenever the object count grows above 100, not to mention a 1000.

Similar reasoning goes to pipeline switches. If you are relying on many pipeline switches done efficiently, then it's good to reconsider your shaders, perhaps turning into the megashader alley a bit. In D3D12, a pipeline change requires all resources to be rebound anyway (and this is what wgpu-hal/dx12 does regardless of the pipeline compatibility), so this is fine in Blade.
# Frequency Asked Questions

## When should I *not* use Blade?

- When you *target the Web*. Blade currently has no Web backends supported. Targeting WebGPU is desired, but will not be as performant as native.
- Similarly, when you target the *low-end GPUs* or old drivers. Blade has no OpenGL/D3D11 support, and it requires fresh drivers on Vulkan.
- When you render with 10K or *more draw calls*. State switching has overhead with Blade, and it is lower in GPU abstractions/libraries that have barriers and explicit bind groups.
- When you need something *off the shelf*. Blade is experimental and young, it assumes you'll be customizing it.

## Why investing into this when there is `wgpu`?

`wgpu` is becoming a standard solution for GPU access in Rust and beyond. It's wonderful, and by any means just use it if you have any doubts. It's a strong local maxima in a chosen space of low-level portability. It may very well be the global maxima as well, but we don't know this until we explore the *other* local maximas. Blade is an attempt to strike where `wgpu` can't reach, it makes a lot of the opposite design solutions. Try it and see.

## Isn't this going to be slow?

Blade creating a descriptor set (in Vulkan) for each draw call. It doesn't care about pipeline compatibility to preserve the bindings. How is this fast?

Short answer is - yes, it's unlikely going to be faster than wgpu-hal. Long answer is - slow doesn't matter here.

Take a look at Vulkan [performance](performance.md) numbers. wgpu-hal can get 60K bunnies on a slow machine, which is pretty much the maximum. Both wgpu and blade can reach about 20K. Honestly, if you are relying on 20K unique draw calls being fast, you are in a strange place. Generally, developers should switch to instancing or other batching methods whenever the object count grows above 100, not to mention a 1000.

Similar reasoning goes to pipeline switches. If you are relying on many pipeline switches done efficiently, then it's good to reconsider your shaders, perhaps turning into the megashader alley a bit. In D3D12, a pipeline change requires all resources to be rebound anyway (and this is what wgpu-hal/dx12 does regardless of the pipeline compatibility), so this is fine in Blade.
Loading

0 comments on commit 2c4acb1

Please sign in to comment.