Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api-reference/experimental/gpu-primitives/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,7 @@ close enough to WebGPU that developers can reason about cost, ordering, and owne
- [`GPUSceneResourceGroups`](/docs/api-reference/experimental/gpu-primitives/gpu-scene-resource-groups)
- [`GPUTraceScene`](/docs/api-reference/experimental/gpu-primitives/gpu-trace-scene)
- [`GPUTraceInteraction`](/docs/api-reference/experimental/gpu-primitives/gpu-trace-interaction)
- [GPU trace picking](/docs/api-reference/experimental/gpu-primitives/gpu-trace-picking)
- [`GPUGroupAggregation`](/docs/api-reference/experimental/gpu-primitives/gpu-group-aggregation)
- [`GPUHashIndex`](/docs/api-reference/experimental/gpu-primitives/gpu-hash-index)
- [`GPUHashJoin`](/docs/api-reference/experimental/gpu-primitives/gpu-hash-join)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-docs-tabs';
import {GPUTraceSceneExample} from '@site/src/examples';

# GPUAncestorProjection

Expand All @@ -10,6 +11,12 @@ import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-do
parents. This lets dependency lines remain meaningful when intermediate spans disappear under
duration, status, runtime, or topology filters.

In the live trace explorer, collapsing a process or excluding a classification can hide an
operation that remains the endpoint of a dependency. Ancestor projection gives the renderer a
visible canonical representative while preserving the hidden operation's original source identity.

<GPUTraceSceneExample embedded />

## Concepts

Projection is different from traversal: it follows each node's one canonical parent chain until it
Expand Down
21 changes: 21 additions & 0 deletions docs/api-reference/experimental/gpu-primitives/gpu-fft2d.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-docs-tabs';
import {TempestOceanExample} from '@site/src/examples';

# GPUFFT2D

Expand All @@ -16,6 +17,26 @@ spectral oceans, frequency-domain filters, convolution, and procedural fields. I
does not own textures, convert real-valued inputs, select padding dimensions, or hide command
submission.

The live ocean below makes the transform's value tangible: GPU spectral coefficients evolve over
time, inverse FFT passes reconstruct spatial displacement fields, and the renderer turns those
fields into waves, normals, and whitecaps without reading intermediate results back to the CPU.

<TempestOceanExample embedded />

## Concepts

### Frequency-domain structure becomes spatial detail

A two-dimensional FFT changes how a complex field is represented without changing its logical
grid resolution. Frequency-space coefficients describe how much each wavelength and direction
contributes; the inverse transform reconstructs the corresponding spatial values. This makes
spectral water, image filtering, convolution, diffraction, and other field simulations practical
when a physical model is simpler to evolve in frequency space than at every spatial sample.

`GPUFFT2D` performs that representation change only. Applications still define coefficient
generation, physical units, normalization expectations, boundary policy, and how reconstructed
fields are consumed by later compute or rendering passes.

### FFT in a complete system

[`SpectralOceanSimulation`](../spectral-ocean-simulation) is the concrete composition example. It
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-docs-tabs';
import {GPUTraceSceneExample} from '@site/src/examples';

# GPUGraphTraversal

Expand All @@ -10,6 +11,13 @@ import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-do
graph adjacency. It supports direct dependencies, incoming and outgoing neighborhoods, and
multi-hop focused subgraphs without synchronizing the CPU.

The scene-backed trace explorer demonstrates why bounded traversal matters: select one operation,
enable linked-span focus, and expand the hop radius to reveal the upstream and downstream work
responsible for it. Selection stays on canonical GPU span rows while the same graph is encoded for
each new focus state.

<GPUTraceSceneExample embedded />

## Concepts

Compressed sparse row (CSR) adjacency stores each node's neighbor range in `offsets` and all
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-docs-tabs';
import {GPUTraceViewerExample} from '@site/src/examples';

# GPUHierarchyLayout

Expand All @@ -10,6 +11,13 @@ import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-do
exclusive GPU-scanned positions. It supports interactive process/thread collapse without
rebuilding source data or render commands.

The live trace viewer demonstrates the motivating interaction directly: collapsing a process
retains one representative row, collapsing a thread retains its first lane, and later rows move
into place through GPU-scanned offsets. The underlying source spans and their stable identities
never move.

<GPUTraceViewerExample embedded />

## Concepts

A hierarchical list can be laid out as a flat sequence when every child row publishes an effective
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ its existing required-count, published-count, overflow, and `indirect-first-inst
This distinction lets one application use compacted rows for labels or picking while another
replays stable resource-grouped indirect draws from the same interaction state.

### Picking follows the same visible hierarchy

[`getGPUTracePickingShader`](./gpu-trace-picking) consumes `threadOffsets` and `visibleMask`
directly. A click therefore resolves against the effective post-collapse row and current filtering
policy instead of an outdated original lane. The returned value remains the canonical source row,
so it can feed `selectedSpans` directly when linked-span focus should follow the current selection.

## Usage

```ts
Expand Down
107 changes: 107 additions & 0 deletions docs/api-reference/experimental/gpu-primitives/gpu-trace-picking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {GPUPrimitivesDocsTabs} from '@site/src/components/docs/gpu-primitives-docs-tabs';
import {GPUTraceSceneExample} from '@site/src/examples';

# GPU Trace Picking

<GPUPrimitivesDocsTabs active="trace-picking" />

## Overview

`getGPUTracePickingShader` generates a small WebGPU compute shader that resolves a timeline
coordinate into the lowest matching visible canonical span row. It belongs to the optional
[`@luma.gl/experimental/lutrace`](/docs/api-reference/experimental/lutrace) submodule because its
inputs understand execution-span timing, process/thread lane topology, hierarchy collapse, and
trace-specific visibility policies.

The motivating use case is a dense execution timeline whose visible rows move whenever a process
or thread expands. A generic screen-space object ID cannot recover the original timeline span
without knowing which canonical spans survived filtering and how their original thread lanes were
projected into the current display layout. The shader resolves those domain-specific details while
keeping dispatch, command submission, result ownership, and asynchronous readback application-owned.

Click a span in the live trace explorer, collapse one of its neighboring processes, and click the
updated row again. Picking follows the GPU-computed effective lane rather than the span's original
uncompacted position, and hidden spans cannot steal the visible selection.

<GPUTraceSceneExample embedded />

## Concepts

### Timeline coordinates are different from source identity

Every canonical span has a stable source row, an application object ID, an original timeline lane,
and a time interval. Display lanes are not stable: process/thread collapse changes exclusive-scanned
thread offsets, while filtering removes rows from visibility. The generated shader compares the
requested time and effective lane against canonical span data and publishes the original source row.

This distinction is important for overlapping spans. The shader uses `atomicMin` so competing
matches resolve deterministically to the lowest canonical row, not whichever GPU invocation happens
to complete first. Applications may translate that row to the stable application object ID through
`GPUTraceSceneView.objectIds` when updating their inspector or selection state.

### Picking consumes the existing interaction outputs

[`GPUTraceInteraction`](./gpu-trace-interaction) already produces exclusive-scanned thread offsets
and a source-aligned final visibility mask. The picking shader consumes those buffers directly; it
does not recompute hierarchy layout, traverse dependencies, or create its own filtering policy.

The effective lane is:

```text
threadOffsets[threadId] + originalLane % lanesPerThread
```

A source row is eligible only when the pick request is active, its final visibility-mask entry is
nonzero, its interval includes the requested time, and its effective lane contains the requested
vertical coordinate.

### The result is caller-owned and sentinel-based

Initialize the result buffer to `0xffffffff` before dispatch. Matching rows atomically minimize that
value to their canonical source index. An inactive request or a coordinate outside all visible spans
leaves the sentinel unchanged. Reinitialize the result before every independent request.

The generated entry point uses 256 invocations per workgroup. Dispatch enough workgroups to cover
the canonical source-row count; the shader bounds-checks the final partial workgroup automatically.
The application owns command-graph ordering, queue submission, staging-buffer reuse, readback, and
any UI synchronization.

## Usage

```ts
import {getGPUTracePickingShader} from '@luma.gl/experimental/lutrace';

const lanesPerThread = 4;
const source = getGPUTracePickingShader(trace.stats.spanCount, lanesPerThread);
const shader = device.createShader({stage: 'compute', source});
const workgroupCount = Math.ceil(trace.stats.spanCount / 256);
```

The caller binds the generated shader into its own compute pipeline. Queue the pick pass after
hierarchy and visibility generation so it observes the same effective rows that rendering uses.

## Storage-binding contract

All five bindings belong to bind group zero:

| Binding | Access | Contents |
| --- | --- | --- |
| 0 | Read-only storage | Packed eight-word canonical span records from `GPUTraceScene` |
| 1 | Read-only storage | Exclusive-scanned effective thread offsets from `GPUTraceInteraction` |
| 2 | Read-only storage | Source-aligned final visibility mask from `GPUTraceInteraction` |
| 3 | Read-only storage | Pick request: `time: f32`, `lane: f32`, `active: u32`, `padding: u32` |
| 4 | Read/write storage | One `atomic<u32>` result initialized to `0xffffffff` |

`spanCount` must be a nonnegative safe integer, and `lanesPerThread` must be a positive safe
integer. Both values specialize the generated WGSL; changing either requires generating a new
shader. Changing the request, expansion state, or visibility policy does not.

## Ownership and scope

The helper returns WGSL source only. It does not allocate resources, compile pipelines, import
buffers into a command graph, schedule dispatches, submit work, read results back, or destroy
caller-owned buffers.

General-purpose picking infrastructure remains independent from the trace domain. Use this helper
when a selection must interpret trace time, hierarchy-projected lanes, and canonical span identity;
use a renderer-specific picking target when object selection has no execution-timeline semantics.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ the same graph. [`GPUTraceInteraction`](/docs/api-reference/experimental/gpu-pri
composes those views into a reusable hierarchy, dependency-focus, visibility, and indirect-draw
workflow.

When a timeline coordinate needs to recover the original source row, compose the interaction
outputs with [`getGPUTracePickingShader`](./gpu-trace-picking). Its visibility-aware shader uses
these same canonical records and scanned thread offsets without adding picking state to the scene.

## Current scope

This tranche establishes canonical ingestion, stable trace-to-scene identity, preserved source
Expand Down
44 changes: 38 additions & 6 deletions docs/api-reference/experimental/lutrace.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ExperimentalDocsTabs} from '@site/src/components/docs/experimental-docs-tabs';
import {GPUTraceSceneExample} from '@site/src/examples';
import {GPUTraceSceneExample, GPUTraceViewerExample} from '@site/src/examples';

# GPU Trace Exploration

Expand All @@ -18,6 +18,11 @@ scientific workflow with both hierarchical ownership and explicit cross-task dep
data remains GPU-resident while time windows, expansion state, selected spans, and visibility
change interactively.

The scene-backed explorer below combines canonical trace ingestion, process/thread collapse,
linked-span selection, stable indirect drawing, and trace-aware GPU picking. Expand or collapse a
process, change the classification filters, and click a span to see the same compiled GPU graph
respond to small control-buffer updates.

<GPUTraceSceneExample embedded />

## Concepts
Expand Down Expand Up @@ -60,6 +65,12 @@ Each trace span also projects into a normal
renderer-owned resource groups, and indirect draw commands can therefore render a trace without
adding trace-specific fields to the scene database.

For example, a distributed request can retain canonical row `417`, application object ID `9021`,
and compacted visible position `12` simultaneously. Dependencies and picking resolve row `417`;
application inspection resolves object `9021`; a compacted label pass consumes position `12`.
Treating these identities as interchangeable would attach selections or dependency endpoints to
the wrong operation whenever filtering changes.

### Interactive policies change control state, not graph topology

[`GPUTraceInteraction`](/docs/api-reference/experimental/gpu-primitives/gpu-trace-interaction)
Expand All @@ -77,12 +88,19 @@ small caller-owned GPU control buffers. The application re-encodes its existing
it does not rebuild a JavaScript span list, perform CPU draw selection, or hand submission
ownership to `lutrace`.

The hierarchy-first trace viewer below demonstrates the same underlying generic layout, dependency
traversal, filtering, and stable row identity from a different application composition. Collapse a
process or isolate linked spans to compare its direct primitive orchestration with the scene-backed
workflow above.

<GPUTraceViewerExample embedded />

### Trace picking is separate from generic picking infrastructure

`getGPUTracePickingShader(spanCount, lanesPerThread)` produces a compute shader for a timeline
coordinate. It considers only spans marked visible by the current interaction policy, reconstructs
effective display lanes from GPU-scanned thread offsets, and atomically publishes the lowest
matching canonical source-row identity.
[`getGPUTracePickingShader`](/docs/api-reference/experimental/gpu-primitives/gpu-trace-picking)
produces a compute shader for a timeline coordinate. It considers only spans marked visible by the
current interaction policy, reconstructs effective display lanes from GPU-scanned thread offsets,
and atomically publishes the lowest matching canonical source-row identity.

```ts
const pickingSource = getGPUTracePickingShader(trace.stats.spanCount, lanesPerThread);
Expand All @@ -92,6 +110,20 @@ Applications still own the pick request, result buffer, command graph, readback,
General-purpose picking targets remain available separately; this helper adds only the
trace-specific time/lane interpretation.

### Choose the right level of composition

| Requirement | Recommended API | Reason |
| --- | --- | --- |
| Schedule arbitrary compute and render passes | `GPUCommandGraph` | No trace assumptions or domain-specific schemas |
| Upload canonical spans, ownership, hierarchy, and dependencies | `GPUTraceScene` | Preserves source identity and projects into a generic `GPUScene` |
| Apply reusable timeline controls without rebuilding graph topology | `GPUTraceInteraction` | Composes hierarchy, focus, visibility, ancestors, and indirect drawing |
| Resolve a timeline coordinate to its visible canonical span | `getGPUTracePickingShader` | Understands trace timing, scanned lanes, and interaction visibility |
| Control queue submission, asynchronous readback, or UI state | Application-owned code | Keeps scheduling, resource lifetime, and presentation policies explicit |

The first embedded explorer uses all four GPU layers together. The hierarchy-first explorer shows
that applications can also compose the generic primitives directly when they need a different
rendering model or interaction policy.

## Public API

| Export | Responsibility |
Expand All @@ -100,7 +132,7 @@ trace-specific time/lane interpretation.
| `GPUTraceInteraction` | Reusable GPU hierarchy, time filtering, classification, dependency focus, ancestor retention, visibility, and indirect draws |
| `GPU_TRACE_SPAN_RECORD_WORD_LENGTH` | Number of 32-bit words in one canonical trace span |
| `GPU_TRACE_LINK_RECORD_WORD_LENGTH` | Number of 32-bit words in one dependency record |
| `getGPUTracePickingShader` | Capacity-bounded, visible-span-aware timeline picking shader |
| [`getGPUTracePickingShader`](/docs/api-reference/experimental/gpu-primitives/gpu-trace-picking) | Capacity-bounded, visible-span-aware timeline picking shader |

Trace-specific classes, constants, helpers, and types are exported only from
`@luma.gl/experimental/lutrace`; they are intentionally absent from the root
Expand Down
2 changes: 2 additions & 0 deletions docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
"api-reference/experimental/gpu-primitives/gpu-scene-resource-groups",
"api-reference/experimental/gpu-primitives/gpu-trace-scene",
"api-reference/experimental/gpu-primitives/gpu-trace-interaction",
"api-reference/experimental/gpu-primitives/gpu-trace-picking",
"api-reference/experimental/gpu-primitives/gpu-group-aggregation",
"api-reference/experimental/gpu-primitives/gpu-hash-index",
"api-reference/experimental/gpu-primitives/gpu-hash-join",
Expand Down Expand Up @@ -363,6 +364,7 @@
"api-reference/experimental/gpu-primitives/gpu-scene-resource-groups",
"api-reference/experimental/gpu-primitives/gpu-trace-scene",
"api-reference/experimental/gpu-primitives/gpu-trace-interaction",
"api-reference/experimental/gpu-primitives/gpu-trace-picking",
"api-reference/experimental/gpu-primitives/gpu-group-aggregation",
"api-reference/experimental/gpu-primitives/gpu-hash-index",
"api-reference/experimental/gpu-primitives/gpu-hash-join",
Expand Down
17 changes: 17 additions & 0 deletions modules/experimental/src/lutrace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,22 @@ lowest matching source-row identity.
This helper is trace-specific; general-purpose picking targets, readback ownership, graph
encoding, and command submission remain outside the `lutrace` module.

The generated shader uses five group-zero storage bindings: packed canonical spans, scanned
thread offsets, the final visibility mask, a `{time, lane, active, padding}` request, and an atomic
result initialized to `0xffffffff`. Matching visible spans atomically publish their lowest
canonical source-row index, which can feed dependency selection without translating through a
compacted display position.

### Use cases and composition boundaries

- Service latency investigations: focus a slow request's upstream and downstream dependencies.
- Browser or GPU captures: collapse noisy processes while preserving stable operation identity.
- Build-system schedules: filter short tasks and inspect cross-worker critical-path relationships.
- Scientific workflows: retain explicit batch boundaries and cross-stage dependency topology.

Applications own command graphs, queue submission, rendering policy, interaction controls, and
readback. `GPUTraceScene` owns only its uploaded trace and projected scene allocations;
`GPUTraceInteraction` borrows caller-owned graph views and registers reusable passes.

See the [lutrace API reference](https://luma.gl/docs/api-reference/experimental/lutrace) for
complete usage examples and the live trace explorer.
Loading
Loading