Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 2
updates:
# Every action in our workflows is pinned by commit SHA with a version
# comment; Dependabot moves the SHA and the comment together.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ["*"]

# CI tools (go-mod-outdated), pinned in tools/go.mod. The root module is left
# out on purpose: ecosystem dependencies move only to released versions, in
# the order the cascade tiers set, and the deps job already reports what is
# behind.
- package-ecosystem: gomod
directory: /tools
schedule:
interval: weekly
groups:
tools:
patterns: ["*"]
146 changes: 98 additions & 48 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ on:

permissions:
contents: read
id-token: write

env:
# goffi requires CGO_ENABLED=0 for pure Go FFI on Unix
Expand All @@ -39,10 +38,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Checkout exact merged WebGPU Android surface source
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
repository: go-webgpu/webgpu
ref: a801aed7399042e5564ef76fc9f075da5cb70081
Expand All @@ -54,7 +53,7 @@ jobs:
run: test "$(git rev-parse HEAD)" = a801aed7399042e5564ef76fc9f075da5cb70081

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ matrix.go-version }}
cache: true
Expand Down Expand Up @@ -85,10 +84,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ matrix.go-version }}
cache: true
Expand All @@ -113,12 +112,18 @@ jobs:
include:
- { goos: js, goarch: wasm, tags: '', name: 'browser' }
- { goos: linux, goarch: amd64, tags: 'rust', name: 'rust' }
# 32-bit int: a constant that fits int on 64-bit targets does not
# there (P1-INFRA-008: TrackerIndex bounds and math.MaxUint32). Build
# only — there is no GPU on 386 and no test runs. windows rather than
# linux: goffi's internal/syscall has no linux/386 files, so the
# linux/386 combination cannot build in the ecosystem.
- { goos: windows, goarch: "386", tags: '', name: '386' }
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true
Expand All @@ -134,6 +139,10 @@ jobs:
test:
name: Test - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
# Codecov uploads with OIDC; no other job needs an id token.
permissions:
contents: read
id-token: write
strategy:
# Each OS runs different backends (DX12, Metal, Vulkan/GLES), so one
# OS failing must not cancel the others' results.
Expand All @@ -144,10 +153,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: ${{ matrix.go-version }}
cache: true
Expand All @@ -161,14 +170,20 @@ jobs:
run: |
go vet $(go list ./... | grep -v '/hal/vulkan/vk$' | grep -v '/hal/gles')

# The build users ship: CGO_ENABLED=0, so goffi runs its fakecgo path.
- name: Run tests
shell: bash
run: go test -v -count=1 -coverprofile=coverage.txt -covermode=atomic ./...

# Race detection uses the toolchain's -race (ThreadSanitizer, needs cgo).
# With CGO_ENABLED=1 goffi links the real runtime/cgo instead of its
# fakecgo, so this step tests that path, not the one above. A non-std cgo
# package in the test binary would fail to link here on Linux (goffi#72).
- name: Run tests with the race detector
shell: bash
# The standard race detector needs cgo at test time only; the library
# itself stays cgo-free (goffi supports CGO_ENABLED=1 too). A data race
# fails the job.
env:
CGO_ENABLED: 1
run: go test -race -v -coverprofile=coverage.txt -covermode=atomic ./...
run: go test -race -count=1 ./...

- name: Verify coverage file
if: matrix.os == 'ubuntu-latest'
Expand All @@ -183,7 +198,7 @@ jobs:

- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5
with:
use_oidc: true
files: ./coverage.txt
Expand All @@ -197,10 +212,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true
Expand Down Expand Up @@ -274,18 +289,70 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true

# The golangci-lint version and its sha256 are pinned in the composite
# action, which restores the verified binary from the Actions cache, so
# lint does not depend on GitHub Releases being reachable on every run
# (on 2026-11-08 the release download URL returned 504 for over an hour).
# Bump golangci-lint in gogpu/.github, then move this pin; keep
# lint-targets on the same commit.
- name: Set up golangci-lint
uses: gogpu/.github/actions/setup-golangci-lint@cdb7bd4a5bd3852541a05f0fa1fa92b09d1ee732 # main 2026-11-08, golangci-lint v2.15.0

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v8
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: latest
install-mode: none
args: --timeout=5m

# Lint the other desktop targets. The job above type-checks only the linux
# files, so code under darwin or windows build tags (hal/metal, hal/dx12,
# hal/gles/wgl) is never linted otherwise. The code is pure Go
# (CGO_ENABLED=0), so GOOS/GOARCH on a linux runner load exactly that
# target's files; a target that fails to type-check exits non-zero, never
# "0 issues". One GOARCH per GOOS is enough: the module has no arch-specific
# files and no darwin/windows + GOARCH build tags (checked 2026-11-08), so
# only darwin/arm64 and windows/amd64 are added. GOOS-named tags in the
# .golangci.yml build-tags would not switch the target and are not used.
lint-targets:
name: Lint - ${{ matrix.goos }}/${{ matrix.goarch }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- { goos: windows, goarch: amd64 }
- { goos: darwin, goarch: arm64 }

steps:
- name: Checkout code
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true

- name: Set up golangci-lint
uses: gogpu/.github/actions/setup-golangci-lint@cdb7bd4a5bd3852541a05f0fa1fa92b09d1ee732 # main 2026-11-08, golangci-lint v2.15.0

# GOOS/GOARCH go on the lint step only: the binary above stays linux/amd64.
- name: Run golangci-lint
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
with:
install-mode: none
args: --timeout=5m

# Code formatting check
Expand All @@ -295,10 +362,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true
Expand All @@ -323,38 +390,20 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: '1.25'
cache: true

# Pin the module version so each run does not re-resolve @latest.
# Retry: proxy.golang.org occasionally returns INTERNAL_ERROR / stream
# resets (seen as red Dependencies checks on otherwise-green PRs).
# continue-on-error: the direct-deps step is advisory only; ecosystem
# checks below do not need this binary.
- name: Install go-mod-outdated
id: install-outdated
continue-on-error: true
run: |
for attempt in 1 2 3; do
if go install github.com/psampaz/go-mod-outdated@v0.9.0; then
exit 0
fi
echo "install attempt ${attempt} failed; retrying..."
sleep $((attempt * 5))
done
echo "::warning::Failed to install go-mod-outdated after retries; skipping direct-deps check"
exit 1

# go-mod-outdated is pinned in tools/go.mod (checksums in tools/go.sum,
# updated by Dependabot), never installed @latest.
- name: Check direct dependencies for updates
if: steps.install-outdated.outcome == 'success'
run: |
echo "## Direct Dependencies with Updates"
OUTDATED=$(go list -u -m -json all 2>/dev/null | go-mod-outdated -update -direct || true)
OUTDATED=$(go list -u -m -json all 2>/dev/null | go tool -modfile=tools/go.mod go-mod-outdated -update -direct || true)
if [ -n "$OUTDATED" ]; then
echo "$OUTDATED"
echo "::warning::Some direct dependencies have updates available"
Expand Down Expand Up @@ -391,14 +440,15 @@ jobs:
[ $WARNINGS -gt 0 ] && echo "::warning::$WARNINGS ecosystem dep(s) outdated"
exit 0

# The one check the main-protection ruleset requires. Jobs and the matrix can
# The one check the main-protection ruleset requires, by this exact job name:
# renaming the job silently drops the requirement. Jobs and the matrix can
# change without touching the ruleset; a new required job goes into `needs`.
# `if: always()` and the explicit result check matter: a job skipped because a
# job it needs failed counts as passed for a required check.
gate:
name: Test
if: always()
needs: [android-arm64-preview, build, cross-compile, test, integration-gles, lint, formatting, deps]
needs: [android-arm64-preview, build, cross-compile, test, integration-gles, lint, lint-targets, formatting, deps]
runs-on: ubuntu-latest
steps:
- name: Every required job succeeded
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Example: `examples/raytracing-headless/` builds a BLAS through the software HAL

## Current Version

v0.34.10 | Go 1.25+ | Dependencies: naga v0.21.5, gpucontext v0.31.3, gputypes v0.8.2, goffi v0.6.8, webgpu v0.5.5
v0.34.11 | Go 1.25+ | Dependencies: naga v0.21.7, gpucontext v0.31.3, gputypes v0.8.2, goffi v0.6.8, webgpu v0.5.5

## Build & Test

Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.34.11] - 2026-11-08

A lifetime and validation patch: resources released after recording stay alive through the work that uses them,
pass input is validated as the spec requires, and the module builds on 32-bit.

### Fixed

- **A query set released after recording stays alive until that work completes** (P1-CORE-021, closes the v0.34.10 known issue). `QuerySet.Release` destroyed the HAL query pool at the previous submission index, so a set released after timestamp writes or a `ResolveQuerySet` were recorded went away under the submitted command buffer: `VUID-vkDestroyQueryPool-queryPool-00793` on Vulkan, zero timestamps on DX12. Query sets are reference counted as samplers are; the command encoder holds the set's reference until the submission completes, and `Submit` refuses only a set whose HAL resource is gone (`ErrSubmitQuerySetDestroyed`).
- **A render or compute pipeline keeps its pipeline layout alive** (P2-CORE-022, closes the second v0.34.10 known issue). A `PipelineLayout` released after the pipeline was created was destroyed while later `SetBindGroup` calls still named it — an invalid `VkPipelineLayout` at `vkCmdBindDescriptorSets`. Pipelines now hold their layout's reference and drop it when their own resource is destroyed.
- **A released bind group layout cannot back a new bind group or pipeline layout** (P2-CORE-023). `CreateBindGroup` and `CreatePipelineLayout` now return `ErrReleased`, as `CreateBindGroup` already did for a released sampler. Before, the released layout's HAL handle reached `vkAllocateDescriptorSets` and crashed inside the driver.
- **`SetViewport` is validated as the spec requires** (P2-CORE-019). Non-finite or negative sizes, an origin outside the viewport range, or a depth range outside `[0, 1]` is a `RenderPassValidationError` on the encoder instead of invalid values reaching the driver. Where the spec and Rust wgpu differ, the spec decides.
- **A vertex format gputypes does not define is a pipeline-creation error** (P2-CORE-019, `CreateRenderPipelineErrorInvalidVertexFormat`). Each backend used to substitute a format of its own (float32x4 on Vulkan and GLES, an invalid Metal format, an unknown DXGI format).
- **The module builds on GOARCH=386** (P1-INFRA-008). Four comparisons against `TrackerIndex` and `math.MaxUint32` were written as `int` constants and overflowed a 32-bit `int`, so every 386 build of wgpu failed to compile. Comparison is done in `uint64` now; behaviour on 64-bit targets is unchanged. Build only — there is no GPU on 386, and ecosystem CI needs goffi's own 386 support before the other repositories can run the leg. Two test files that did not type-check for 32-bit are fixed with it.
- **GLES: MSAA, buffer mapping and storage textures work on an OpenGL ES context** (P1-GLES-025, items 1 and 3). Multisampled render targets were created with `glTexImage2DMultisample`, which ES does not have, so every MSAA texture failed with `GL_INVALID_OPERATION`; they are renderbuffers now (`glRenderbufferStorageMultisample`), as in Rust wgpu-hal. `MapBuffer` used `glMapBuffer`, absent from ES, so every buffer readback of GPU-written data returned zeros while rendering was correct; it maps with `glMapBufferRange`. And `glBindImageTexture` rejects a texture with mutable storage on ES, so compute storage textures wrote nothing; textures are allocated with immutable storage (`glTexStorage2D`/`glTexStorage3D`) where the context offers it.
- **GLES: BC textures are detected from core GL versions and ARB names** (P2-GLES-024). Detection required only the `EXT_texture_compression_*` names, so a driver that lists `GL_ARB_texture_compression_rgtc` (Intel on Windows) advertised no BC formats at all. RGTC from desktop GL 3.0, BPTC from 4.2 and the `ARB` names are accepted now; the compressed-format readback compares all 24 formats against the software backend on that adapter.

### Changed

- **naga v0.21.7.** The DX12 fragment `@builtin(position).w` is now WGSL's `1/w` (naga P1-HLSL-037): the perspective readback asserts it on both DX12 legs instead of excluding them. DXIL `mem2reg` promotes bool locals as `i32` (naga P2-DXIL-107/092): a short-circuit `||` chain's local used to be a `phi i1` or an `alloca i1`, and WARP, the D3D12 software adapter, ran neither arm's stores on the first shape while D3D12's GPU-based validation dropped them on the second. The new readback case `flow/short-circuit-or-rt` pins the values on every backend; the discriminating WARP + GPU-based-validation run is kept in the gate harness. Also in the release: the streaming WGSL lexer (behaviour-neutral), a DXIL built-in used as a runtime array index, a DXIL refusal of workgroup storage above the model's limit instead of a bad module, HLSL storage stores nested past 20, and an opt-in SPIR-V demote-to-helper (`spirv.Options.DemoteToHelperInvocation`, off by default). No IR change.
- **`Device.PushErrorScope` returns an error for a filter outside the three WebGPU filters** (P3-API-025). It used to map an unknown value to `Validation` silently, pushing a scope that could never capture what the caller asked for. The native build validates in core, `-tags rust` rejects the value before it reaches wgpu-native, which panics on an unknown filter and whose panic would abort the process across the FFI boundary. Calls written as statements are unaffected.

### Infrastructure

- CI lints windows/amd64 and darwin/arm64 in addition to the host, pins every action by SHA, installs the pinned golangci-lint from the ecosystem action, adds a dependabot configuration, and builds windows/386 (P2-INFRA-007, P1-INFRA-008). The ruleset still requires the `Test` gate; switching it to `Required checks` is a separate, coordinated step.

### Known issues

- Scissor rects are not validated yet; they go to the HAL unvalidated, as viewports did before this release (P2-CORE-024, next patch).

## [0.34.10] - 2026-11-08

A patch for frame-batching consumers and a security update of naga.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Components: `core`, `hal`, `vulkan`, `metal`, `dx12`, `gles`, `software`, `noop`
- Reference the Rust wgpu equivalent for non-trivial HAL/core changes
- Add tests for new functionality
- Update documentation if needed (CHANGELOG, docs/, README)
- Ensure all CI checks pass (build, cross-compile, tests with the race detector, GLES integration, lint, formatting, deps, Android preview)
- Ensure all CI checks pass (build across three OSes and windows/386, cross-compile for browser and the Rust binding, tests with the race detector, GLES integration, lint on windows/amd64 and darwin/arm64 as well as linux, formatting, deps, Android preview)
- Reference related issues

## Testing
Expand Down
Loading
Loading