# `ExBurn.CubeclBridge`
[🔗](https://github.com/ohhi-vn/ex_burn/blob/main/lib/ex_burn/cubecl_bridge.ex#L1)

Bridge to ExCubecl for GPU execution via Burn's CubeCL backend.

⚠️ **EXPERIMENTAL**: This module is a placeholder for future GPU
acceleration via the ExCubecl library. The API is unstable and may
change without notice. GPU operations are not yet fully integrated
with the ExBurn tensor pipeline.

CubeCL (Compute Unified Backend for Compute Language) is Burn's
GPU compute abstraction layer that supports:

- **CUDA** (NVIDIA GPUs)
- **Metal** (Apple GPUs — iOS, macOS)
- **Vulkan** (Android, Linux, Windows)
- **WebGPU** (Browser-based GPU)
- **ROCm** (AMD GPUs)

This module delegates to the ExCubecl library (v0.4.0) for all GPU
operations. ExCubecl buffers (opaque references) are used for GPU
memory throughout.

## Usage

    # Check if a GPU is available
    if ExBurn.CubeclBridge.available?() do
      # Initialize the GPU context
      {:ok, ctx} = ExBurn.CubeclBridge.init(:metal)

      # Check device capabilities
      caps = ExBurn.CubeclBridge.device_capabilities(ctx)

      # Allocate GPU buffer and run a kernel
      {:ok, buf} = ExBurn.CubeclBridge.allocate_gpu(ctx, [4, 4], :f32)
      {:ok, result} = ExBurn.CubeclBridge.execute(ctx, :add, [buf, buf])

      # Pipeline for multi-kernel execution
      {:ok, pid} = ExBurn.CubeclBridge.pipeline()
      :ok = ExBurn.CubeclBridge.pipeline_add(pid, :add, [buf, buf], buf)
      :ok = ExBurn.CubeclBridge.pipeline_add(pid, :relu, [buf], buf)
      {:ok, commands} = ExBurn.CubeclBridge.pipeline_run(pid)
      :ok = ExBurn.CubeclBridge.pipeline_free(pid)
    end

# `backend`

```elixir
@type backend() :: :cuda | :metal | :vulkan | :wgpu | :rocm
```

# `buffer`

```elixir
@type buffer() :: reference()
```

# `command_id`

```elixir
@type command_id() :: non_neg_integer()
```

# `context`

```elixir
@type context() :: reference()
```

# `kernel`

```elixir
@type kernel() :: atom()
```

# `pipeline_id`

```elixir
@type pipeline_id() :: non_neg_integer()
```

# `allocate_gpu`

```elixir
@spec allocate_gpu(context(), [non_neg_integer()], atom()) ::
  {:ok, buffer()} | {:error, String.t()}
```

Allocates a GPU buffer with the given shape and type.

Returns an ExCubecl buffer reference.

# `async_poll`

```elixir
@spec async_poll(command_id()) ::
  {:ok, :pending | :running | :completed | :failed} | {:error, term()}
```

Polls the status of an asynchronous command.

Returns `:pending`, `:running`, `:completed`, or `:failed`.

# `async_submit`

```elixir
@spec async_submit(String.t()) :: {:ok, command_id()} | {:error, term()}
```

Submits a command for asynchronous execution.

Returns a command ID that can be polled or waited on.

# `async_wait`

```elixir
@spec async_wait(command_id()) :: :ok | {:error, term()}
```

Blocks until the given command completes.

# `available?`

```elixir
@spec available?() :: boolean()
```

Checks whether a GPU device is available via ExCubecl.

# `available_backends`

```elixir
@spec available_backends() :: [backend()]
```

Returns a list of available GPU backends on this system.

Delegates to ExCubecl availability checks and platform detection.
On Linux/Windows with NVIDIA hardware, `:cuda` is included.
On macOS, `:metal` is included.

# `buffer_dtype`

```elixir
@spec buffer_dtype(buffer()) :: {:ok, String.t()} | {:error, term()}
```

Returns the data type of a GPU buffer.

# `buffer_read`

```elixir
@spec buffer_read(buffer()) :: {:ok, binary()} | {:error, term()}
```

Reads the raw binary data from a GPU buffer.

# `buffer_read!`

```elixir
@spec buffer_read!(buffer()) :: binary()
```

Reads the raw binary data from a GPU buffer, raising on error.

# `buffer_shape`

```elixir
@spec buffer_shape(buffer()) :: {:ok, [non_neg_integer()]} | {:error, term()}
```

Returns the shape of a GPU buffer.

# `buffer_size`

```elixir
@spec buffer_size(buffer()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Returns the size of a GPU buffer in bytes.

# `compile_kernel`

```elixir
@spec compile_kernel(context(), kernel(), keyword()) ::
  {:ok, reference()} | {:error, String.t()}
```

Compiles a compute kernel for the given backend.

Kernels are managed by ExCubecl; this function verifies the kernel
is available and returns a reference.

# `cuda_available?`

```elixir
@spec cuda_available?() :: boolean()
```

Checks whether an NVIDIA CUDA GPU is available on this system.

First checks via ExCubecl if available, then falls back to
platform-specific heuristics (nvidia-smi on Linux/Windows).

# `destroy`

```elixir
@spec destroy(context()) :: :ok
```

Destroys the GPU context and frees all associated resources.

# `device_capabilities`

```elixir
@spec device_capabilities(term()) :: map()
```

Returns the capabilities of the GPU device.

# `device_count`

```elixir
@spec device_count() :: {:ok, non_neg_integer()} | {:error, term()}
```

Returns the number of GPU devices available.

# `device_summary`

```elixir
@spec device_summary() :: String.t()
```

Returns a human-readable summary of the GPU device.

## Example

    IO.puts(ExBurn.CubeclBridge.device_summary())

# `device_to_host`

```elixir
@spec device_to_host(context(), buffer()) ::
  {:ok, Nx.Tensor.t()} | {:error, String.t()}
```

Copies data from a GPU buffer to host (CPU) as an Nx tensor.

## Parameters

  * `ctx` — The GPU context
  * `buffer` — An ExCubecl buffer reference

## Returns

  `{:ok, Nx.Tensor.t()}` on success, `{:error, reason}` on failure.

# `execute`

```elixir
@spec execute(context(), kernel(), [buffer()], keyword()) ::
  {:ok, buffer()} | {:error, String.t()}
```

Executes a compute kernel on the GPU.

## Parameters

  * `ctx` — The GPU context
  * `kernel` — The kernel to execute (atom)
  * `args` — List of ExCubecl buffer references
  * `opts` — Options (currently unused, reserved for future use)

## Returns

  `{:ok, result_buffer}` on success, `{:error, reason}` on failure.

# `free`

```elixir
@spec free(context(), buffer()) :: :ok
```

Frees a GPU buffer.

Note: ExCubecl buffers are garbage-collected when their reference
goes out of scope. This function is a no-op for API compatibility.

# `host_to_device`

```elixir
@spec host_to_device(context(), Nx.Tensor.t()) ::
  {:ok, buffer()} | {:error, String.t()}
```

Copies data from host (CPU) to a new GPU buffer.

## Parameters

  * `ctx` — The GPU context
  * `tensor` — An Nx tensor to copy to the GPU

## Returns

  `{:ok, buffer}` on success, `{:error, reason}` on failure.

# `init`

```elixir
@spec init(
  backend(),
  keyword()
) :: {:ok, context()} | {:error, String.t()}
```

Initializes a GPU compute context for the given backend.

## Parameters

  * `backend` — The GPU backend to use (`:cuda`, `:metal`, `:vulkan`, `:wgpu`, `:rocm`)
  * `opts` — Options (currently unused, reserved for future use)

## Returns

  `{:ok, context}` on success, `{:error, reason}` on failure.

# `kernels`

```elixir
@spec kernels() :: {:ok, [String.t()]} | {:error, term()}
```

Returns the list of kernel names supported by ExCubecl.

# `memory_info`

```elixir
@spec memory_info() :: {:ok, map()} | {:error, term()}
```

Returns a map with GPU memory information.

Returns `:error` if no GPU is available or memory info cannot be queried.

## Returns

    {:ok, %{total: integer(), used: integer(), free: integer()}}
    or
    {:error, reason}

# `memory_total`

```elixir
@spec memory_total(context()) :: non_neg_integer()
```

Returns the total available GPU memory (in bytes).

Attempts to query the GPU device for total memory.
Falls back to 0 if the information is not available.

# `memory_used`

```elixir
@spec memory_used(context()) :: non_neg_integer()
```

Returns the amount of GPU memory currently in use (in bytes).

Attempts to query the GPU device for actual memory usage.
Falls back to 0 if the information is not available.

# `pipeline`

```elixir
@spec pipeline() :: {:ok, pipeline_id()} | {:error, term()}
```

Creates a new pipeline for multi-kernel execution.

# `pipeline_add`

```elixir
@spec pipeline_add(pipeline_id(), atom(), [buffer()], buffer(), map()) ::
  :ok | {:error, term()}
```

Adds a kernel command to a pipeline.

## Parameters

  * `pipeline_id` — The pipeline to add to
  * `kernel` — Kernel name (atom)
  * `inputs` — List of input buffer references
  * `output` — Output buffer reference
  * `params` — Additional parameters (optional, default: `%{}`)

# `pipeline_add_struct`

```elixir
@spec pipeline_add_struct(pipeline_id(), ExCubecl.Command.t()) ::
  :ok | {:error, term()}
```

Adds a pre-built `%ExCubecl.Command{}` struct to a pipeline.

# `pipeline_free`

```elixir
@spec pipeline_free(pipeline_id()) :: :ok | {:error, term()}
```

Frees a pipeline and its associated resources.

# `pipeline_run`

```elixir
@spec pipeline_run(pipeline_id()) :: {:ok, [command_id()]} | {:error, term()}
```

Executes all commands in the pipeline and returns their command IDs.

# `supported_dtypes`

```elixir
@spec supported_dtypes() :: [atom()]
```

Returns the list of supported data types.

# `synchronize`

```elixir
@spec synchronize(context()) :: :ok
```

Synchronizes the GPU context, blocking until all queued operations complete.

Note: ExCubecl does not expose a global synchronization primitive.
Use `async_wait/1` on specific command IDs for fine-grained control.

# `version`

```elixir
@spec version() :: String.t()
```

Returns the ExCubecl library version string.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
