Conversation
Three wire structs were missing fields that the webgpu.h shipped with wgpu-native v29.0.0.0 has, so every field after them was read from the wrong offset: - WGPUBindGroupLayoutEntry: bindingArraySize (uint32 + padding) between visibility and buffer. wgpu-native panicked with "invalid buffer binding type for buffer binding layout at binding N". - WGPUVertexAttribute: the leading nextInChain. wgpu-native read the format from the offset field and panicked with "invalid vertex format for vertex attribute: 0". - WGPURenderPassDepthStencilAttachment: the leading nextInChain. TestABIWireStructAlignment now asserts the v29 layouts instead of the old "migration gap" expectations. The binding's own test suite passes against the official v29.0.0.0 DLL with these changes.
…rt failed present - stringViewToString aliased wgpu-native memory with unsafe.String; the adapter name turned into garbage once wgpu-native reused the buffer. Copy the bytes instead. - Surface.GetCurrentTexture returned nil on Lost/Timeout/Occluded/Error even when wgpu had handed out a texture. The caller could not present or release it, the swapchain image stayed acquired and the next call aborted the process with "Surface image is already acquired". Return the SurfaceTexture (status, and the texture only when the handle is non-zero) together with the error. - Surface.Present ignored the WGPUStatus of wgpuSurfacePresent. When the present fails wgpu-native has already dropped the acquisition, and releasing the texture afterwards discards it a second time (fatal "already acquired" in wgpuTextureRelease). Return an error so callers can skip the release.
… Proc.Call
Every binding method passes Go structs to wgpu-native as
uintptr(unsafe.Pointer(&local)). Proc was an interface, so the conversion
happened in a call that lacked //go:uintptrescapes: the local stayed on the
goroutine stack and could move (stack growth, GC shrink) between the
conversion and the syscall. wgpu-native then read stale input or wrote its
output to the old stack. In practice wgpuSurfaceGetCurrentTexture
"returned" a zeroed WGPUSurfaceTexture (status 0, texture 0) while the
texture had really been acquired, and the process aborted on the next
present or configure ("Surface image is already acquired" /
"SurfaceOutput must be dropped before a new Surface is made"), about once
every few starts.
Proc is now a concrete struct wrapping the platform implementation and
Proc.Call carries //go:uintptrescapes, which the compiler only honors on
direct calls. Library.NewProc returns *Proc; the platform loaders wrap
their implementation with newProc. This is a breaking change only for
code implementing its own Library/Proc.
//go:uintptrescapes on Proc.Call only protects pointers converted to uintptr directly in the call's argument list. Many descriptors reach wgpu-native nested: their address is stored as uintptr inside another struct (render pass color/depth attachments, SetBindGroup dynamic offsets, color target Blend, surface sources, command-buffer arrays) or converted before the call. When those values live on the goroutine stack, a stack growth or shrink between the conversion and the native call leaves wgpu-native reading stale memory. pin[T](p *T) *T returns p unchanged but forces the object onto the heap (an escape through a package-level sink the compiler cannot rule out); the Go heap does not move objects. Every uintptr(unsafe.Pointer(&x)) in the package now goes through pin, plus the two already-taken pointers stored in other descriptors. Cost: those structs are heap-allocated. Tested: go vet on windows/linux/darwin; go test ./wgpu passes with the wgpu-native v29.0.0.0 DLL on Windows (D3D12/Vulkan adapter). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Pushed one more commit to this PR: fix(wgpu): pin nested descriptors on the heap (61ba8a6). It is the same class of bug as the
Their address is stored as
Tested:
|
|
Oh, this PR fixs #34 |
Should use |
Summary
Four fixes found while building a Go game client on go-webgpu (wgpu-native v29.0.0.0, Windows / DX12). One commit per topic.
webgpu.hshipped with wgpu-native v29.0.0.0.WGPUBindGroupLayoutEntrygainsbindingArraySize(uint32 + padding) betweenvisibilityandbuffer;WGPUVertexAttributeandWGPURenderPassDepthStencilAttachmentgain the leadingnextInChain. Without them every later field was read from the wrong offset and wgpu-native panicked withinvalid buffer binding type for buffer binding layout at binding 0andinvalid vertex format for vertex attribute: 0.TestABIWireStructAlignmentnow asserts the v29 layouts instead of the "migration gap" expectations.stringViewToStringaliased it withunsafe.String; the adapter name read garbage once wgpu-native reused the buffer.Surface.GetCurrentTexturereturns theSurfaceTextureon error statuses, andSurface.Presentreports a failedwgpuSurfacePresent. Closes MissingRelease()in the error path ofSurface.GetCurrentTexture()#31. Dropping the texture on Lost/Timeout/Occluded/Error left the swapchain image acquired and the next call aborted the process withSurface image is already acquired. Releasing a texture after a failed present made wgpu-native discard the acquisition a second time (fatal inwgpuTextureRelease), so callers need to know.Proc.Callcarries//go:uintptrescapes. Every binding method passes Go structs asuintptr(unsafe.Pointer(&local)). WithProcas an interface the conversion happened in a call that lacked the directive, so the local stayed on the goroutine stack and could move (stack growth, GC shrink) between the conversion and the syscall; wgpu-native then read stale input or wrote its output to the old stack. Reproduced aswgpuSurfaceGetCurrentTexture"returning" a zeroedWGPUSurfaceTexture(status 0) while the texture had really been acquired, followed by an abort inwgpuSurfaceConfigure(SurfaceOutput must be dropped before a new Surface is made), about once every few program starts.Procis now a concrete struct andLibrary.NewProcreturns*Proc; the directive is only honored on direct calls. Breaking only for code that implements its ownLibrary/Proc.Testing
WGPU_NATIVE_PATH=<wgpu-native v29.0.0.0 dll> go test ./... -count=1passes on Windows 11 with an NVIDIA RTX 3080 Ti (DX12), including the render tests.GOOS=linux,GOOS=darwinandGOOS=linux GOARCH=arm64builds of./wgpu.🤖 Generated with Claude Code