# `Dala.Gpu.Surface`
[🔗](https://github.com/manhvu/dala/blob/main/lib/dala/gpu/surface.ex#L1)

GenServer that holds the state for a GPU surface.

Each surface corresponds to a Rust-side GPU renderer with a CPU-side
framebuffer, a command queue, and a GPU texture. The GenServer owns the
NIF reference and ensures clean teardown via `terminate/2`.

Commands are fire-and-forget (cast) for performance. Pixel access is
synchronous (call) since it returns data.

# `t`

```elixir
@type t() :: %Dala.Gpu.Surface{
  height: non_neg_integer(),
  ref: reference(),
  width: non_neg_integer()
}
```

# `batch`

```elixir
@spec batch(pid(), [binary()]) :: :ok
```

Execute a batch of pre-encoded commands.

# `blit`

```elixir
@spec blit(pid(), non_neg_integer(), integer(), integer()) :: :ok
```

Blit a loaded sprite at the given position.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear`

```elixir
@spec clear(pid(), Dala.Gpu.Command.color()) :: :ok
```

Clear the surface with a solid color.

# `dispatch_compute`

```elixir
@spec dispatch_compute(
  pid(),
  String.t(),
  binary(),
  {non_neg_integer(), non_neg_integer(), non_neg_integer()}
) :: :ok | {:error, term()}
```

Dispatch a GPU compute shader.

# `draw_circle`

```elixir
@spec draw_circle(
  pid(),
  integer(),
  integer(),
  non_neg_integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Draw a circle outline.

# `draw_image`

```elixir
@spec draw_image(
  pid(),
  non_neg_integer(),
  integer(),
  integer(),
  non_neg_integer(),
  non_neg_integer()
) :: :ok
```

Draw a loaded image onto the framebuffer.

# `draw_line`

```elixir
@spec draw_line(
  pid(),
  integer(),
  integer(),
  integer(),
  integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Draw a line between two points.

# `draw_round_rect`

```elixir
@spec draw_round_rect(
  pid(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Draw a rounded rectangle outline.

# `draw_triangle`

```elixir
@spec draw_triangle(
  pid(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Draw a triangle outline.

# `fill_circle`

```elixir
@spec fill_circle(
  pid(),
  integer(),
  integer(),
  non_neg_integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Fill a circle.

# `fill_rect`

```elixir
@spec fill_rect(
  pid(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Fill a rectangle with a solid color.

# `fill_round_rect`

```elixir
@spec fill_round_rect(
  pid(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Fill a rounded rectangle.

# `fill_triangle`

```elixir
@spec fill_triangle(
  pid(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  integer(),
  Dala.Gpu.Command.color()
) :: :ok
```

Fill a triangle.

# `get_info`

```elixir
@spec get_info(pid()) :: %{width: non_neg_integer(), height: non_neg_integer()}
```

Get surface info as a map.

# `get_pixels`

```elixir
@spec get_pixels(pid()) :: binary()
```

Read the current pixel data as an RGBA8888 binary.

# `load_image`

```elixir
@spec load_image(
  pid(),
  non_neg_integer(),
  binary(),
  non_neg_integer(),
  non_neg_integer()
) :: :ok
```

Load an image into the GPU texture pool.

# `load_shader`

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

Load or hot-reload a shader.

# `load_sprite`

```elixir
@spec load_sprite(
  pid(),
  non_neg_integer(),
  binary(),
  non_neg_integer(),
  non_neg_integer()
) :: :ok
```

Load a sprite into the texture atlas for later blitting.

# `present`

```elixir
@spec present(pid()) :: :ok
```

Present the surface — flush the command queue and update the GPU texture.

# `remove_image`

```elixir
@spec remove_image(pid(), non_neg_integer()) :: :ok
```

Remove an image from the GPU texture pool.

# `remove_sprite`

```elixir
@spec remove_sprite(pid(), non_neg_integer()) :: :ok
```

Remove a sprite from the texture atlas.

# `reset_clip`

```elixir
@spec reset_clip(pid()) :: :ok
```

Reset the clipping region.

# `resize`

```elixir
@spec resize(pid(), non_neg_integer(), non_neg_integer()) :: :ok
```

Resize the surface.

# `set_clip`

```elixir
@spec set_clip(
  pid(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  non_neg_integer(),
  boolean()
) :: :ok
```

Set the clipping rectangle.

# `set_pixels`

```elixir
@spec set_pixels(pid(), binary()) :: :ok
```

Set the pixel data directly. Binary must be exactly width * height * 4 bytes.

# `set_uniform`

```elixir
@spec set_uniform(pid(), String.t(), binary()) :: :ok | {:error, term()}
```

Set a uniform value.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start a linked surface GenServer.

# `stop`

```elixir
@spec stop(pid()) :: :ok
```

Stop the surface GenServer and free GPU resources.

# `supports_compute`

```elixir
@spec supports_compute(pid()) :: boolean()
```

Check compute support.

# `with_pixels`

```elixir
@spec with_pixels(pid(), (binary() -&gt; binary())) :: :ok
```

Modify pixels via a callback. The callback receives the current RGBA8888 binary
  and must return the new RGBA8888 binary of the same size.

---

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