Skip to content

feat: expose queue timestamp period#23

Merged
kolkov merged 5 commits into
go-webgpu:mainfrom
besmpl:besmpl/queue-timestamp-period
Jul 24, 2026
Merged

feat: expose queue timestamp period#23
kolkov merged 5 commits into
go-webgpu:mainfrom
besmpl:besmpl/queue-timestamp-period

Conversation

@besmpl

@besmpl besmpl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Dependency resolved

go-webgpu/goffi#65 has merged and shipped in the canonical goffi v0.6.2 release. This PR now consumes v0.6.2 directly; it has no fork, pseudo-version, or temporary Windows fallback.

Summary

  • add Queue.GetTimestampPeriod for wgpuQueueGetTimestampPeriod in wgpu-native v29
  • use explicit float32-return call paths so Unix and Windows read the native floating-point return register correctly
  • update the timestamp-query example to use the reported nanoseconds-per-tick value, with a visible 1.0 ns/tick fallback if the native value is unavailable

Windows correctness

@kolkov correctly blocked the original revision because goffi v0.6.0 discarded the floating-point return slot on Windows AMD64. The bounded upstream fix landed in go-webgpu/goffi#65: Go's Windows AMD64 asmstdcall already copies XMM0 into syscall.SyscallN's second result, so goffi can recover float32/float64 without a new assembly trampoline. The released fix includes an actual Windows DLL end-to-end regression test.

This PR requires goffi v0.6.2, so the Windows path now uses that canonical, tested fix.

Review changes

  • bumped the canonical goffi dependency to v0.6.2, which contains the merged Windows XMM0 fix
  • made every timestamp-period regression test part of the repository's TestABI CI lane
  • added a dynamically built shared-library ABI test that executes the pointer-argument float32 return path on Linux, macOS, and Windows
  • centralized Unix and Windows float32 calls in one fully covered helper, with the remaining CIF-caching opportunity documented there
  • removed the inconsistent mustInit() call from Queue.GetTimestampPeriod; an unavailable proc now returns zero without hidden initialization or panic
  • changed the example from hard failure to warning + fallback
  • rebased onto current main, including Android surface source feat(wgpu): add Android native-window surface source #24

Testing

  • CGO_ENABLED=0 go test -count=1 -race ./wgpu -run '^TestABIQueueGetTimestampPeriod'
  • GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go test -count=1 -run '^TestABIQueueGetTimestampPeriod' -exec=/usr/bin/true ./wgpu
  • GOOS=windows GOARCH=arm64 CGO_ENABLED=0 go test -count=1 -run '^TestABIQueueGetTimestampPeriod' -exec=/usr/bin/true ./wgpu
  • CGO_ENABLED=0 go build ./examples/timestamp_query
  • hosted Ubuntu, macOS, and Windows CI execute the dynamic-library float32 ABI regression
  • Codecov reports all modified and coverable lines covered
  • CGO_ENABLED=0 go vet ./wgpu/...
  • go mod verify
  • git diff --check

@besmpl
besmpl marked this pull request as ready for review July 15, 2026 10:42
@besmpl
besmpl requested a review from kolkov as a code owner July 15, 2026 10:42

@kolkov kolkov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the PR — GetTimestampPeriod is a real gap in our API, and the ABI analysis (separate float-return path via float32Proc) is the right approach. The test coverage is thorough and the example update is a nice touch.

I have one blocking issue and a few smaller items.


Blocking: CallFloat32 returns garbage on Windows

I traced the full call chain on Windows:

windowsProc.CallFloat32()
  → ffi.CallFunction(&cif, fn, &result, argPtrs)
    → executeFunction() → arch.Registry.Caller.Execute()
      → amd64.Implementation.Execute()          [call_windows.go]
        → syscall.SyscallN(fn, args...)          → ret = RAX
        → handleReturn(cif, rvalue, uint64(ret), 0, 0, 0)
          → case FloatType: *(*float32)(rvalue) = *(*float32)(unsafe.Pointer(&retVal))

The problem: goffi on Windows passes fret=0 to handleReturn (call_windows.go:90). This is because syscall.SyscallN only captures RAX — there is no Windows assembly trampoline to capture XMM0 (compare: Unix has MOVQ X0, 128(DI) in syscall_unix_amd64.s:111 to save XMM0 after the C call).

Then handleReturn for FloatType interprets the lower 32 bits of RAX as float32:

case types.FloatType:
    *(*float32)(rvalue) = *(*float32)(unsafe.Pointer(&retVal)) // retVal = RAX bits

Per Windows x64 ABI, float returns go exclusively in XMM0 — RAX is a scratch register with undefined contents. This applies to MSVC, Clang, and Rust/LLVM (x86_64-pc-windows-msvc). So CallFloat32 will interpret whatever garbage is in RAX as a float32.

This is a documented known limitation in goffi (TASK-019 / GAP-7) — purego has the same issue.

Suggested path forward: since you're already deep in goffi internals (goffi#62 Android), would you be up for adding a Windows assembly trampoline to capture XMM0? The Unix path already does this in syscall_unix_amd64.s:111:

MOVQ X0, 128(DI) // f1: float return in XMM0

Windows would need a similar trampoline that wraps (or replaces) syscall.SyscallN for float-return calls and saves XMM0 to the syscallArgs struct. Bundling both (goffi fix + this PR rebased on top) would ship a complete, correct solution across all platforms.

If you'd rather keep this PR scoped to webgpu only, a build-tag split with a safe Windows fallback (return 0 or 1.0 with a log warning) would also work as a temporary measure — I can file a separate goffi issue for the trampoline.


Smaller items

mustInit() in GetTimestampPeriod — Other public Queue methods (Submit, WriteBuffer) assume Init() was already called. mustInit() panics on missing library, which is inconsistent. The next procQueueGetTimestampPeriod == nil check already handles this — suggest removing the mustInit() block.

CIF not cached in CallFloat32 — Both Unix and Windows CallFloat32 create a fresh CIF on every call. The existing Call() caches via u.prepared + u.cifMu. Not a perf issue for GetTimestampPeriod, but a // TODO: cache CIF comment would acknowledge the pattern gap.

Example hard-fails on period <= 0return fmt.Errorf("timestamp period unavailable") exits the example entirely. A warning + fallback to 1.0 would be more forgiving, especially given the Windows issue.


Summary

The Unix/macOS implementation is correct and well-tested. The Windows path needs either a goffi-level fix (XMM0 trampoline) or a temporary workaround before merge. Happy to discuss either approach — and nice work on the broader effort with Hearth, goffi#62, and gogpu/wgpu#268.

@besmpl
besmpl force-pushed the besmpl/queue-timestamp-period branch from d8de296 to 078e63f Compare July 22, 2026 16:27
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@besmpl

besmpl commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@kolkov The Windows blocker and all smaller review items are now addressed:

  • this now uses released goffi v0.6.2 (go-webgpu/goffi#65) for correct XMM0 float returns on Windows
  • removed the inconsistent mustInit(), centralized the float32 call path with the remaining CIF-caching opportunity documented, and changed the example to warn + fall back
  • added an end-to-end shared-library ABI test that runs on Linux, macOS, and Windows

All checks are green, Codecov reports every modified coverable line covered, and the PR is clean/mergeable. Could you please take another look when you have a chance? Thanks again for catching the Windows ABI issue.

@kolkov kolkov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Windows blocker resolved via goffi v0.6.2 (XMM0 float returns). All review items addressed: mustInit removed, example uses warn+fallback, CIF cache TODO documented, shared callFloat32 path is clean and well-tested. E2E dynamic library test is a great addition. LGTM.

@kolkov
kolkov merged commit 1779245 into go-webgpu:main Jul 24, 2026
7 checks passed
@kolkov kolkov mentioned this pull request Jul 24, 2026
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.

2 participants