#![cfg(feature = "gpu")]
use frust::authoring::Rect;
use frust::authoring::scene::{Command, Scene, SceneBuilder};
use frust::gpu::{Context, DeviceHandle, Texture, with_context};
#[allow(dead_code)]
fn draw_registered_texture<T, V>(texture: &Texture<T, V>, scene: &mut Scene, dest: Rect) {
let mut builder = SceneBuilder::new(scene);
builder.scene_texture(texture.as_scene_texture().get(), dest);
}
fn record_scene_texture_draw() {
let id = 42_u64;
let dest = Rect::new(0.0, 0.0, 64.0, 64.0);
let mut scene = Scene::new();
let mut builder = SceneBuilder::new(&mut scene);
builder.scene_texture(id, dest);
match &scene.commands()[0] {
Command::SceneTexture {
id: recorded,
dest: recorded_dest,
..
} => {
assert_eq!(*recorded, id);
assert_eq!(*recorded_dest, dest);
}
other => panic!("expected exactly one SceneTexture command, got {other:?}"),
}
}
#[test]
fn scene_texture_seam_compiles_and_records_through_facade_types_only() {
record_scene_texture_draw();
}
#[test]
fn with_context_answers_none_before_any_shell_installs_a_device() {
let answer = with_context(|handle| handle.caps.adapter_name.clone());
assert!(
answer.is_none(),
"with_context must answer None until a shell installs a device"
);
}
fn block_on<F: std::future::Future>(fut: F) -> F::Output {
let mut fut = std::pin::pin!(fut);
let waker = std::task::Waker::noop();
let mut cx = std::task::Context::from_waker(waker);
loop {
match fut.as_mut().poll(&mut cx) {
std::task::Poll::Ready(output) => return output,
std::task::Poll::Pending => std::thread::yield_now(),
}
}
}
#[test]
#[ignore = "needs a real GPU adapter; run with `cargo test -p frust-ui --features gpu --test \
gpu_seam -- --ignored` (WGPU_BACKEND/WGPU_ADAPTER_NAME pin the adapter; \
FRUST_GOLDEN_EXPECT_ADAPTER verifies it resolved)"]
fn scene_texture_seam_reaches_a_real_headless_device_through_the_facade_context() {
block_on(async {
let mut context = Context::new();
context
.ensure_device_headless()
.await
.expect("frust::gpu::Context headless device creation");
let caps = context
.caps()
.expect("caps are populated once a device exists");
if let Ok(expected) = std::env::var("FRUST_GOLDEN_EXPECT_ADAPTER") {
let expected = expected.trim();
if !expected.is_empty() {
assert!(
caps.adapter_name
.to_lowercase()
.contains(&expected.to_lowercase()),
"expected an adapter matching `{expected}`, resolved `{}` instead",
caps.adapter_name
);
}
}
println!(
"frust::gpu::Context resolved adapter: {}",
caps.adapter_name
);
});
record_scene_texture_draw();
}
#[test]
#[ignore = "needs a real GPU adapter; run with `cargo test -p frust-ui --features gpu --test \
gpu_seam -- --ignored` (WGPU_BACKEND/WGPU_ADAPTER_NAME pin the adapter; \
FRUST_GOLDEN_EXPECT_ADAPTER verifies it resolved)"]
fn with_context_reaches_a_handle_installed_the_way_a_shell_would() {
let installed_adapter = block_on(async {
let mut context = Context::new();
context
.ensure_device_headless()
.await
.expect("frust::gpu::Context headless device creation");
let handle: DeviceHandle = context.device_handle().clone();
let adapter_name = handle.caps.adapter_name.clone();
if let Ok(expected) = std::env::var("FRUST_GOLDEN_EXPECT_ADAPTER") {
let expected = expected.trim();
if !expected.is_empty() {
assert!(
adapter_name
.to_lowercase()
.contains(&expected.to_lowercase()),
"expected an adapter matching `{expected}`, resolved `{adapter_name}` instead"
);
}
}
frust_shell_common::gpu::install_gpu_handle(handle);
adapter_name
});
let read_back_adapter = with_context(|handle| handle.caps.adapter_name.clone())
.expect("a device was installed just above");
assert_eq!(read_back_adapter, installed_adapter);
println!("frust::gpu::with_context resolved adapter: {read_back_adapter}");
}