Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples crate #124

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"tracy-client-sys",
"tracy-client",
"tracing-tracy",
"examples",
]
resolver = "2"

Expand Down
20 changes: 20 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "tracy-client-examples"
publish = false
version = "0.17.4" # AUTO-BUMP
authors = ["Nathan Adams <dinnerbone@dinnerbone.com>"]
license.workspace = true
edition.workspace = true
rust-version.workspace = true
readme = "README.mkd"
repository.workspace = true
homepage.workspace = true
description = """
Examples for using `tracy-client` in a wgpu application
"""

[dependencies]
tracy-client = { path = "../tracy-client" }
wgpu = "23.0.1"
futures = "0.3.31"
rand = "0.8.4"
9 changes: 9 additions & 0 deletions examples/README.mkd
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Examples for Tracy integration

These examples exist to demonstrate how to integrate the rust-Tracy API within an application.
They do not serve as examples of a real world application, but rather how an application would use a given API.

To use them, run `cargo run -p tracy-client-examples -- example_name` from within the repository root.
If you don't provide an `example_name`, it will list the available examples.

Be sure to have Tracy running and awaiting a connection, before running any example!
51 changes: 51 additions & 0 deletions examples/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
mod secondary_frames;
mod threads;
mod wgpu_frame_images;
mod zones;

struct ExampleDesc {
name: &'static str,
description: &'static str,
function: fn(),
}

const EXAMPLES: &[ExampleDesc] = &[
ExampleDesc {
name: "wgpu_frame_images",
description: "Demonstrates capturing frame images with wgpu",
function: wgpu_frame_images::main,
},
ExampleDesc {
name: "secondary_frames",
description: "Demonstrates secondary frames, both continuous and discontinuous",
function: secondary_frames::main,
},
ExampleDesc {
name: "zones",
description: "Demonstrates the use of zones to measure work",
function: zones::main,
},
ExampleDesc {
name: "threads",
description: "Demonstrates the use of zones across threads",
function: threads::main,
},
];

fn main() {
let example_name = std::env::args().nth(1);
if let Some(example) = EXAMPLES
.iter()
.find(|e| Some(e.name) == example_name.as_deref())
{
(example.function)();
} else {
if let Some(name) = example_name {
eprintln!("Example {name} not found!");
}
println!("Available examples:");
for example in EXAMPLES {
println!("{}: {}", example.name, example.description);
}
}
}
38 changes: 38 additions & 0 deletions examples/src/secondary_frames/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use rand::rngs::ThreadRng;
use rand::Rng;
use std::thread::sleep;
use std::time::Duration;
use tracy_client::{non_continuous_frame, secondary_frame_mark};

pub fn main() {
tracy_client::Client::start();
let mut rng = rand::thread_rng();

for _ in 0..100 {
simulate_physics(&mut rng);
if rng.gen_bool(0.75) {
simulate_rendering(&mut rng);
}

// This marks the boundary between two continuous frames
secondary_frame_mark!("Update Loop");
}
}

fn simulate_physics(rng: &mut ThreadRng) {
// This is a discontinuous frame; it has a defined start and stop
// In this case, the start is now - and the end is when _frame is dropped
let _frame = non_continuous_frame!("Physics");

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(10..20)));
}

fn simulate_rendering(rng: &mut ThreadRng) {
// This is a discontinuous frame; it has a defined start and stop
// In this case, the start is now - and the end is when _frame is dropped
let _frame = non_continuous_frame!("Rendering");

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(10..30)));
}
92 changes: 92 additions & 0 deletions examples/src/threads/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use rand::rngs::ThreadRng;
use rand::{thread_rng, Rng, RngCore};
use std::thread::{sleep, spawn};
use std::time::Duration;
use tracy_client::{set_thread_name, span, Client};

pub fn main() {
Client::start();

let mut handles = Vec::new();
handles.push(Box::new(spawn(|| {
// We can mark this thread with a custom name
set_thread_name!("Physics");
let mut rng = thread_rng();
for _ in 0..50 {
simulate_physics(&mut rng);
// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(5..20)));
}
})));
handles.push(Box::new(spawn(|| {
// We can mark this thread with a custom name
set_thread_name!("Rendering");
let mut rng = thread_rng();
for _ in 0..50 {
simulate_rendering(&mut rng);
}
// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(5..20)));
})));

for handle in handles {
handle.join().unwrap();
}
}

fn simulate_physics(rng: &mut ThreadRng) {
// This zone starts immediately, and ends when zone is dropped
let zone = span!("Physics");
// Zones can have custom colours!
zone.emit_color(0xFF0000);

for name in ["Cow", "Pig", "Player", "Robot"] {
// Let's imagine these names are dynamic
// To mark zones for them, we need to use a different method which temporarily allocates a zone location
let zone = Client::running().unwrap().span_alloc(
Some(name),
"perform_physics",
"physics.rs",
123,
0,
);

zone.emit_value(rng.next_u64()); // entity ID? Who knows!

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(5..20)));

if rng.gen_bool(0.15) {
let zone = span!("Collision");
// Zones can have arbitrary text!
zone.emit_text("Collided against a wall");

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(5..20)));
}
}

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(1..20)));
}

fn simulate_rendering(rng: &mut ThreadRng) {
// This zone starts immediately, and ends when zone is dropped
let zone = span!("Rendering");
// Zones can have custom colours!
zone.emit_color(0x00FF00);

for _ in 0..rng.gen_range(1..10) {
if rng.gen_bool(0.50) {
let zone = span!("Mesh");
zone.emit_color(rng.gen_range(0x000000..0xFFFFFF));
// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(1..15)));
} else {
// Sometimes let's not mark it, just to show that zones don't have to next to eachother

// simulate doing some work
sleep(Duration::from_millis(rng.gen_range(1..15)));
}
}
}
30 changes: 30 additions & 0 deletions examples/src/wgpu_frame_images/blit.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@group(0) @binding(0) var frame_sampler: sampler;
@group(0) @binding(1) var frame_texture: texture_2d<f32>;

struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) tex_coord: vec2<f32>,
}


// This shader copies an entire texture by basically drawing a giant triangle that happens to contain it all
@vertex fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
var result: VertexOutput;
let x = i32(vertex_index) / 2;
let y = i32(vertex_index) & 1;
let tc = vec2<f32>(
f32(x) * 2.0,
f32(y) * 2.0
);
result.position = vec4<f32>(
tc.x * 2.0 - 1.0,
1.0 - tc.y * 2.0,
0.0, 1.0
);
result.tex_coord = tc;
return result;
}

@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(frame_texture, frame_sampler, in.tex_coord);
}
Loading
Loading