[][src]Struct emu_core::device::Device

pub struct Device {
    pub device: Device,
    pub queue: Queue,
    pub info: Option<DeviceInfo>,
}

Represents a single device

Since its fields are public, you can easily construct and mutate a Device's WebGPU internals. To get a Device from an existing device pool, you will want to use take.

One thing to remember is that each Device owns its data. So even though the device pool lets you create DeviceBoxs on different devices, you cannot use them together in the same kernel.

Fields

device: Device

The WebGPU device wrapped by this data structure

queue: Queue

The queue this device exposes to submit work to

info: Option<DeviceInfo>

Information about the device

This is optional so that you don't need information to construct a Device yourself.

Methods

impl Device[src]

pub async fn all() -> Vec<Self>[src]

Gets all detected devices

This is asynchronous because it may take a long time for all the devices that are detected to actually be available. However, you shouldn't actually use this. Unless you manually construct a pool of devices, a default device pool is implicitly created. So you should instead do one of the following.

  • If you are developing a library, select a device from the pool with select/take
  • If you are developing an application, construct a pool with pool or use the default pool

If you are using the default pool, don't forget to call assert_device_pool_initialized before doing anthing with a device.

pub fn create_with_size<T>(&mut self, size: usize) -> DeviceBox<T> where
    T: ?Sized
[src]

Creates a constant DeviceBox<T> with size of given number of bytes

let mut device = &mut futures::executor::block_on(Device::all())[0];
let pi: DeviceBox<f32> = device.create_with_size(std::mem::size_of::<f32>());

pub fn create_with_size_mut<T>(&mut self, size: usize) -> DeviceBox<T> where
    T: ?Sized
[src]

Creates a mutable DeviceBox<T> with size of given number of bytes

let mut device = &mut futures::executor::block_on(Device::all())[0];
let mut data: DeviceBox<[f32]> = device.create_with_size(std::mem::size_of::<f32>() * 2048);

pub fn create_from<T: ?Sized, B: Borrow<T>>(
    &mut self,
    host_obj: B
) -> DeviceBox<T> where
    T: AsBytes, 
[src]

Creates a constant DeviceBox<T> from a borrow of T

let mut device = &mut futures::executor::block_on(Device::all())[0];
let pi: DeviceBox<f32> = device.create_from(&3.1415);

pub fn create_from_mut<T: ?Sized, B: Borrow<T>>(
    &mut self,
    host_obj: B
) -> DeviceBox<T> where
    T: AsBytes, 
[src]

Creates a mutable DeviceBox<T> from a borrow of T

let mut device = &mut futures::executor::block_on(Device::all())[0];
let data = vec![0.0; 2048];
let mut data_on_gpu: DeviceBox<[f32]> = device.create_from(data.as_slice());

pub fn set_from<T: ?Sized, B: Borrow<T>>(
    &mut self,
    device_obj: &mut DeviceBox<T>,
    host_obj: B
) where
    T: AsBytes, 
[src]

Uploads data from the given borrow to T to the given DeviceBox<T> that lives on this (meaning self) device

let mut device = &mut futures::executor::block_on(Device::all())[0];
let data = vec![0.0; 2048];
let mut data_on_gpu: DeviceBox<[f32]> = device.create_from_mut(data.as_slice());
device.set_from(&mut data_on_gpu, vec![0.5; 2048].as_slice());

pub async fn get<'_, '_, T>(
    &'_ mut self,
    device_obj: &'_ DeviceBox<[T]>
) -> Result<Box<[T]>, CompletionError> where
    T: FromBytes + Copy
[src]

Downloads data from the given DeviceBox<T> asynchronously and returns a boxed slice of T

This functions is asynchronous so you can either .await it in an asynchronous context (like an async fn or async block) or you can simply pass the returned future to an executor.

// get a device
let mut device = &mut futures::executor::block_on(Device::all())[0];

// create some data on a GPU and mutate it in place
let data = vec![0.0; 2048];
let mut data_on_gpu: DeviceBox<[f32]> = device.create_from_mut(data.as_slice());
device.set_from(&mut data_on_gpu, vec![0.5; 2048].as_slice());

// use `get` to download from the GPU
assert_eq!(futures::executor::block_on(device.get(&data_on_gpu))?,
    vec![0.5; 2048].into_boxed_slice());

pub unsafe fn call<'a>(
    &mut self,
    device_fn_mut: &DeviceFnMut,
    work_space_dim: (u32, u32, u32),
    args: DeviceFnMutArgs<'a>
) -> Result<(), LaunchError>
[src]

Runs the given DeviceFnMut on a multi-dimensional space of threads to launch and arguments to pass to the launched kernel

This is unsafe because it runs arbitrary code on a device.

let mut device = &mut futures::executor::block_on(Device::all())[0];
let data = vec![0.0; 2048];
let mut data_on_gpu: DeviceBox<[f32]> = device.create_from(data.as_slice());

// these are bytes so we first convert to 4-byte words
let shader: Vec<u32> = convert_to_spirv(std::io::Cursor::new(vec![
    // Magic number.           Version number: 1.0.
    0x03, 0x02, 0x23, 0x07,    0x00, 0x00, 0x01, 0x00,
    // Generator number: 0.    Bound: 0.
    0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00,
    // Reserved word: 0.
    0x00, 0x00, 0x00, 0x00,
    // OpMemoryModel.          Logical.
    0x0e, 0x00, 0x03, 0x00,    0x00, 0x00, 0x00, 0x00,
    // GLSL450.
    0x01, 0x00, 0x00, 0x00]))?;

// then, we compile to a `DeviceFnMut`
// the compilation here will fail at runtime because the above shader
// doesn't have an entry point called main
let shader_compiled = device.compile(ParamsBuilder::new().build(), "main", shader)?;

// run
unsafe { device.call(&shader_compiled, (1, 1, 1), ArgsBuilder::new().build())? };

pub fn compile<T: Into<String>, P: Borrow<[u32]>>(
    &self,
    program_params: DeviceFnMutParams,
    program_entry: T,
    program: P
) -> Result<DeviceFnMut, CompileError>
[src]

Compiles a DeviceFnMut using the given parameters, entry point name, and SPIR-V program

The entry point is where in the SPIR-V program the compiled kernel should be entered upon execution. The entry point's name is anything implementing Into<String> including &str and String while the program itself is anything Borrow<[u32]> including Vec<u32> and &[u32].

// get a device to use
let mut device = &mut futures::executor::block_on(Device::all())[0];

// these are bytes so we first convert to 4-byte words
let shader: Vec<u32> = convert_to_spirv(std::io::Cursor::new(vec![
    // Magic number.           Version number: 1.0.
    0x03, 0x02, 0x23, 0x07,    0x00, 0x00, 0x01, 0x00,
    // Generator number: 0.    Bound: 0.
    0x00, 0x00, 0x00, 0x00,    0x00, 0x00, 0x00, 0x00,
    // Reserved word: 0.
    0x00, 0x00, 0x00, 0x00,
    // OpMemoryModel.          Logical.
    0x0e, 0x00, 0x03, 0x00,    0x00, 0x00, 0x00, 0x00,
    // GLSL450.
    0x01, 0x00, 0x00, 0x00]))?;

// then, we compile to a `DeviceFnMut`
// the compilation here will fail at runtime because the above shader
// doesn't have an entry point called main
let shader_compiled = device.compile(ParamsBuilder::new().build(), "main", shader)?;

Auto Trait Implementations

impl !RefUnwindSafe for Device

impl Send for Device

impl Sync for Device

impl Unpin for Device

impl UnwindSafe for Device

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T, U> AsDeviceBoxed<T> for U where
    T: AsBytes + ?Sized,
    U: Borrow<T>, 
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.