Skip to main content

GpuContext

Struct GpuContext 

Source
pub struct GpuContext { /* private fields */ }
Expand description

A live GPU handle: one logical device, its command queue, and a snapshot of which adapter we ended up on (so the maintainer can VERIFY, on-device, whether the GPU actually engaged or we fell back to CPU).

Cheap to pass around by reference (&GpuContext); do not rebuild it per op. Held for the lifetime of an crate::Executor.

Implementations§

Source§

impl GpuContext

Source

pub fn new() -> Result<Self, GpuUnavailable>

Probe for a GPU and open a device on it, or return why we can’t.

Blocking: wgpu’s request_adapter / request_device are async, and this crate’s API is synchronous, so we drive them to completion with pollster::block_on. Call this once and cache the result.

We ask for wgpu::Limits::downlevel_defaults rather than the desktop defaults so the device also opens on mobile/GL-class adapters — this crate is meant to run on GPU-less and modest-GPU devices, and the demonstrator kernels stay well inside downlevel limits.

§The Termux GPU reality (hard-won, read before touching this)

Whether a GPU adapter is even reachable from the Termux userland is device + driver dependent, not a wgpu limitation. Android GPU access from Termux goes through Vulkan (preferred) or GLES, which is why the instance below enables exactly VULKAN | GL:

  • Adreno (Qualcomm / Snapdragon): works via Termux’s Mesa Turnip/Freedreno Vulkan ICD — install mesa-vulkan-icd-freedreno plus the Vulkan loader (vulkan-loader). This is the best-supported on-device path and what the README’s test recipe targets.
  • Mali (ARM): the open Panfrost/PanVK stack is immature; it may present no usable Vulkan adapter, in which case we get NoAdapter and the cascade lands on CPU. That is expected, not a bug.
  • No ICD installed: no adapter is found at all → NoAdapter → CPU.

In every one of those “no adapter / no driver” cases this returns Err and the crate::Executor cascade falls to the pure-Rust CPU path — no crash, correct answer, just slower. Nothing here requires a working GPU.

Source

pub fn device(&self) -> &Device

The logical device (buffer/pipeline/shader creation goes through this).

Source

pub fn queue(&self) -> &Queue

The command queue (submit encoded command buffers here).

Source

pub fn adapter_info(&self) -> &AdapterInfo

The selected adapter’s identity: name, backend, device type, driver.

This is the raw structured form; describe_backend formats it into one human line. Use this to verify on-device that the GPU engaged and via which backend (Vulkan vs GL).

Source

pub fn describe_backend(&self) -> String

A one-line human description of what we’re running on, e.g. GPU: Turnip Adreno (TM) 730 [Vulkan] (driver: Mesa 24.x, Turnip).

This is the string logged at init and the one the README’s Termux recipe tells the maintainer to look for — if they see a GPU/Vulkan line here, the device GPU engaged; if they see the Executor’s CPU-fallback line instead, it didn’t.

Trait Implementations§

Source§

impl Debug for GpuContext

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

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

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,