Visitar URL original
feat(core): prepare WebGPU shader hooks for extensions by ibgreen · Pull Request #10996 · visgl/deck.gl · GitHub
Skip to content

feat(core): prepare WebGPU shader hooks for extensions - #10996

Merged
ibgreen merged 1 commit into
masterfrom
codex/extension-shader-plugin-prep
Nov 4, 2026
Merged

ibgreen merged 1 commit into
masterfrom
codex/extension-shader-plugin-prep

Conversation

@ibgreen

@ibgreen ibgreen commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Background

WebGPU extensions need layer injection points and geometry state. Master already registers shared GLSL and WGSL targets, and luma.gl alpha.10 resolves same-name targets by stage. This PR wires the layer calls into those targets.

Change List

  • Wire WGSL layers to the shared injection targets
  • Populate common-space geometry and fragment coordinates
  • Preserve globe billboards and native Trips injection targets
  • Preserve picking payloads while allowing filter discards
  • Apply color filters before premultiplication
  • Unit tests: update existing shader assertions
  • Documentation: describe shared stage-qualified target names

Verified: full build and lint pass; no local tests run. Fresh CI pending.


Note

Medium Risk
Modifies WGSL shader implementations across multiple core rendering layers, introducing moderate regression risk for WebGPU rendering and picking pipelines.

Overview
Wired standard WGSL shader injection hooks (DECKGL_FILTER_SIZE, DECKGL_FILTER_GL_POSITION, and DECKGL_FILTER_COLOR) across all core WebGPU layer shaders. Standardized geometry structures by aliasing Geometry to VertexGeometry in project.wgsl and populating fragmentGeometry.uv across fragment entry points.

Applied DECKGL_FILTER_COLOR hooks prior to alpha premultiplication on both visible rendering and picking paths, allowing extension filters to discard fragments while keeping picking payloads intact. Also added developer documentation for authoring WebGPU shader plugins and unit tests verifying ordered plugin merging.

Reviewed by Cursor Bugbot for commit 86e6032. Bugbot is set up for automated code reviews on this repo. Configure here.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-11-02T03:00:40.629643Z
We couldn’t complete this review. Comment @codex review to try again.
3c86c50 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@greptile-apps

greptile-apps Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes reach built-in WebGPU rendering across many layer types.

Fix the picking filter input before merging so color-based extensions draw and select the same objects.

Findings

  1. P1 Picking filters see wrong colors ▶

Summary

Adds shared GLSL/WGSL hook names and calls them across built-in WGSL shaders.

  • WebGPU extensions can change built-in layer sizes and vertex positions.
  • WebGPU extensions can filter visible color and discard fragments during picking.

Reviews (7) · Last reviewed commit: "Wire shared shader injection targets for..." · Reviewed by Greptile

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@coveralls

coveralls commented Nov 2, 2026 •

Copy link
Copy Markdown

Coverage Status

coverage: 84.668%. remained the same — codex/extension-shader-plugin-prep into master

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@ibgreen
ibgreen force-pushed the codex/extension-shader-plugin-prep branch from 2a816bd to 86e6032 Compare November 4, 2026 03:01

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 86e6032. Configure here.

@ibgreen
ibgreen merged commit f902676 into master Nov 4, 2026
7 checks passed
@ibgreen
ibgreen deleted the codex/extension-shader-plugin-prep branch November 4, 2026 03:12

@chrisgervang chrisgervang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 86e6032 after merge; follow-ups below. No P1s. The new WebGPU section explains luma.gl internals and pins a luma.gl alpha. One rewrite of the section is proposed inline.

Labels: P1 settle before this is merged, P2 can follow, Non-blocking optional.

Comment on lines +266 to +304
## WebGPU shader plugins

Extensions can return `{plugins: [plugin]}` from `getShaders`. deck.gl preserves
plugins contributed by the layer and other extensions, in order. Declare shader
inputs in `ShaderPlugin.vertexInputs` and cross-stage values in `ShaderPlugin.interStageVariables`;
luma.gl allocates locations and rewrites the WGSL entry-point interfaces. Keep
accessors, attribute buffers, invalidation, and resource lifecycle in the extension.

Injections use explicit stages and language-specific source. For example:

```typescript
const plugin: ShaderPlugin = {
name: 'fade',
injections: {
'glsl:fs:DECKGL_FILTER_COLOR': 'color.a *= 0.5;',
'wgsl:fs:DECKGL_FILTER_COLOR': '(*color).a *= 0.5;'
}
};
```

The built-in rendering primitives expose these WGSL injection targets:

```wgsl
DECKGL_FILTER_SIZE(&size, geometry);
DECKGL_FILTER_GL_POSITION(&output.position, geometry);
DECKGL_FILTER_COLOR(&color, fragmentGeometry);
```

Call the position target after populating `geometry.worldPosition` and, when relevant,
`geometry.worldPositionAlt`. Call the fragment color target on visible and picking
return paths, after derivative-dependent calculations and before premultiplying color. Custom layer shaders should
return a named vertex-output struct and accept a named fragment-input struct so
luma.gl can transport plugin varyings. Do not add extension-specific attributes or
varyings to those structs yourself.

GLSL and WGSL share injection target names, with language-specific signatures in one descriptor.
Plugins select the shader language and stage through qualified injection keys.
Luma.gl alpha.10 resolves vertex and fragment targets with the same name by
stage. The WGSL layer call sites shown above apply color filters in the fragment stage.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This section mixes two readers (extension authors and custom WGSL layer authors) with luma.gl internals: "luma.gl allocates locations and rewrites the WGSL entry-point interfaces" and "Luma.gl alpha.10 resolves vertex and fragment targets with the same name by stage". The example also doesn't show where the plugin goes.

Could it read like this? The heading keeps the #webgpu-shader-plugins anchor that brushing-extension.md and clip-extension.md link to.

Suggested change
## WebGPU shader plugins
Extensions can return `{plugins: [plugin]}` from `getShaders`. deck.gl preserves
plugins contributed by the layer and other extensions, in order. Declare shader
inputs in `ShaderPlugin.vertexInputs` and cross-stage values in `ShaderPlugin.interStageVariables`;
luma.gl allocates locations and rewrites the WGSL entry-point interfaces. Keep
accessors, attribute buffers, invalidation, and resource lifecycle in the extension.
Injections use explicit stages and language-specific source. For example:
```typescript
const plugin: ShaderPlugin = {
name: 'fade',
injections: {
'glsl:fs:DECKGL_FILTER_COLOR': 'color.a *= 0.5;',
'wgsl:fs:DECKGL_FILTER_COLOR': '(*color).a *= 0.5;'
}
};
```
The built-in rendering primitives expose these WGSL injection targets:
```wgsl
DECKGL_FILTER_SIZE(&size, geometry);
DECKGL_FILTER_GL_POSITION(&output.position, geometry);
DECKGL_FILTER_COLOR(&color, fragmentGeometry);
```
Call the position target after populating `geometry.worldPosition` and, when relevant,
`geometry.worldPositionAlt`. Call the fragment color target on visible and picking
return paths, after derivative-dependent calculations and before premultiplying color. Custom layer shaders should
return a named vertex-output struct and accept a named fragment-input struct so
luma.gl can transport plugin varyings. Do not add extension-specific attributes or
varyings to those structs yourself.
GLSL and WGSL share injection target names, with language-specific signatures in one descriptor.
Plugins select the shader language and stage through qualified injection keys.
Luma.gl alpha.10 resolves vertex and fragment targets with the same name by
stage. The WGSL layer call sites shown above apply color filters in the fragment stage.
## WebGPU shader plugins
To support WebGPU, return a `ShaderPlugin` with both GLSL and WGSL injections from `getShaders`. deck.gl keeps the plugins from the layer and from other extensions, in order.
```typescript
import type {ShaderPlugin} from '@luma.gl/shaders';
const plugin: ShaderPlugin = {
name: 'fade',
injections: {
'glsl:fs:DECKGL_FILTER_COLOR': 'color.a *= 0.5;',
'wgsl:fs:DECKGL_FILTER_COLOR': '(*color).a *= 0.5;'
}
};
class FadeExtension extends LayerExtension {
getShaders() {
return {plugins: [plugin]};
}
}
```
The key prefix selects the shader language (`glsl` or `wgsl`) and the stage (`vs` or `fs`). The [standard injection targets](./writing-shaders.md#standard-shader-injection-targets) have the same names in both languages.
For per-object values, declare the shader inputs in the plugin's `vertexInputs` and pass values to the fragment stage with `interStageVariables`. The extension still adds the matching attributes to the layer's attribute manager.
### Supporting extensions in custom WGSL layers
A custom WGSL layer supports extensions by calling the injection targets:
```wgsl
DECKGL_FILTER_SIZE(&size, geometry);
DECKGL_FILTER_GL_POSITION(&output.position, geometry);
DECKGL_FILTER_COLOR(&color, fragmentGeometry);
```
- Call `DECKGL_FILTER_GL_POSITION` after setting `geometry.worldPosition`, and `geometry.worldPositionAlt` when the layer uses it.
- Call `DECKGL_FILTER_COLOR` in the fragment shader on both the visible and picking paths, after any derivative calculations and before premultiplying alpha.
- Return a named struct from the vertex entry point and take a named struct in the fragment entry point. Don't add extension attributes or varyings to these structs yourself.
Details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants